From acacbd5c2d4405e68e5b890eb3bc0d92bb99f66e Mon Sep 17 00:00:00 2001 From: Nach Date: Wed, 5 Mar 2008 00:35:39 +0000 Subject: [PATCH] Whitespace trim, and eol-style native propery set again. git-svn-id: https://svn.code.sf.net/p/vbam/code/trunk@448 a31d4220-a93d-0410-bf67-fe4944624d44 --- VBA2008.sln | 150 +- VBA2008.vcproj | 3738 +++++----- debian/changelog | 28 +- debian/compat | 2 +- debian/control | 26 +- debian/copyright | 46 +- debian/dirs | 4 +- debian/docs | 2 +- debian/vbam.1 | 328 +- debian/vbam.manpages | 2 +- doc/authors.txt | 28 +- doc/todo.txt | 104 +- lang/how-to.txt | 54 +- lang/release.cmd | 2 +- lang/update.cmd | 2 +- project/qmake/vba-m.pro | 338 +- project/vc2008/vba-m.sln | 40 +- project/vc2008/vba-m.vcproj | 874 +-- src/Util.cpp | 1502 ++-- src/agb/GBA-arm.cpp | 5930 +++++++-------- src/agb/GBA-thumb.cpp | 4660 ++++++------ src/agb/GBA.cpp | 7966 ++++++++++---------- src/agb/GBA.h | 320 +- src/agb/GBAGfx.cpp | 94 +- src/agb/GBAGfx.h | 3202 ++++---- src/agb/GBALink.cpp | 2166 +++--- src/agb/GBALink.h | 248 +- src/agb/GBAcpu.h | 604 +- src/agb/GBAinline.h | 1478 ++-- src/agb/agbprint.cpp | 196 +- src/agb/agbprint.h | 54 +- src/agb/gbafilter.cpp | 454 +- src/agb/gbafilter.h | 10 +- src/dmg/GB.cpp | 10898 ++++++++++++++-------------- src/dmg/gb.h | 128 +- src/dmg/gbCheats.cpp | 1044 +-- src/dmg/gbCheats.h | 124 +- src/dmg/gbCodes.h | 2920 ++++---- src/dmg/gbCodesCB.h | 2582 +++---- src/dmg/gbDis.cpp | 498 +- src/dmg/gbGfx.cpp | 1202 +-- src/dmg/gbGlobals.cpp | 114 +- src/dmg/gbGlobals.h | 178 +- src/dmg/gbMemory.cpp | 3434 ++++----- src/dmg/gbMemory.h | 412 +- src/dmg/gbPrinter.cpp | 458 +- src/dmg/gbPrinter.h | 40 +- src/dmg/gbSGB.cpp | 1834 ++--- src/dmg/gbSGB.h | 78 +- src/dmg/gbSound.cpp | 824 +-- src/dmg/gbSound.h | 148 +- src/dmg/gb_apu/Blip_Buffer.cpp | 930 +-- src/dmg/gb_apu/Blip_Buffer.h | 1112 +-- src/dmg/gb_apu/Effects_Buffer.cpp | 1276 ++-- src/dmg/gb_apu/Effects_Buffer.h | 286 +- src/dmg/gb_apu/Gb_Apu.cpp | 788 +- src/dmg/gb_apu/Gb_Apu.h | 364 +- src/dmg/gb_apu/Gb_Apu_State.cpp | 236 +- src/dmg/gb_apu/Gb_Oscs.cpp | 1330 ++-- src/dmg/gb_apu/Gb_Oscs.h | 380 +- src/dmg/gb_apu/Multi_Buffer.cpp | 562 +- src/dmg/gb_apu/Multi_Buffer.h | 410 +- src/dmg/gb_apu/blargg_common.h | 412 +- src/dmg/gb_apu/blargg_config.h | 66 +- src/dmg/gb_apu/blargg_source.h | 184 +- src/qt/emu.cpp | 352 +- src/qt/emu.h | 142 +- src/win32/AccelEditor.cpp | 580 +- src/win32/CmdAccelOb.cpp | 1054 +-- src/win32/Direct3D.cpp | 1804 ++--- src/win32/MainWnd.cpp | 2614 +++---- src/win32/OpenGL.cpp | 1528 ++-- src/win32/VBA.cpp | 5316 +++++++------- src/win32/VBA.h | 556 +- src/win32/VBA.rc | 4524 ++++++------ 75 files changed, 44187 insertions(+), 44187 deletions(-) diff --git a/VBA2008.sln b/VBA2008.sln index 0a3466e7..4a385055 100644 --- a/VBA2008.sln +++ b/VBA2008.sln @@ -1,75 +1,75 @@ -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VisualBoyAdvance", "VBA2008.vcproj", "{6D4C5EC8-933F-4C05-A1BF-498E658576DF}" - ProjectSection(ProjectDependencies) = postProject - {DB5C12E9-BCD3-4517-8708-475C0D1D88CE} = {DB5C12E9-BCD3-4517-8708-475C0D1D88CE} - {96E945F7-0377-48DA-A5F8-1C192DE9F25F} = {96E945F7-0377-48DA-A5F8-1C192DE9F25F} - {B938FBD9-C7F9-4BF7-8C27-68865D1FA092} = {B938FBD9-C7F9-4BF7-8C27-68865D1FA092} - {7AEC599C-7C82-4F00-AA60-411E0A359CB0} = {7AEC599C-7C82-4F00-AA60-411E0A359CB0} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\dependencies\zlib\zlib2008.vcproj", "{B938FBD9-C7F9-4BF7-8C27-68865D1FA092}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "..\dependencies\libpng\libpng2008.vcproj", "{96E945F7-0377-48DA-A5F8-1C192DE9F25F}" - ProjectSection(ProjectDependencies) = postProject - {B938FBD9-C7F9-4BF7-8C27-68865D1FA092} = {B938FBD9-C7F9-4BF7-8C27-68865D1FA092} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "File_Extractor", "..\dependencies\File_Extractor-0.4.2\File_Extractor2008.vcproj", "{7AEC599C-7C82-4F00-AA60-411E0A359CB0}" - ProjectSection(ProjectDependencies) = postProject - {B938FBD9-C7F9-4BF7-8C27-68865D1FA092} = {B938FBD9-C7F9-4BF7-8C27-68865D1FA092} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cximage", "..\dependencies\cximage\cximage2008.vcproj", "{DB5C12E9-BCD3-4517-8708-475C0D1D88CE}" -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 - {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Debug|Win32.ActiveCfg = Debug|Win32 - {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Debug|Win32.Build.0 = Debug|Win32 - {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Debug|x64.ActiveCfg = Debug|x64 - {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Debug|x64.Build.0 = Debug|x64 - {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Release|Win32.ActiveCfg = Release|Win32 - {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Release|Win32.Build.0 = Release|Win32 - {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Release|x64.ActiveCfg = Release|x64 - {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Release|x64.Build.0 = Release|x64 - {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Debug|Win32.ActiveCfg = Debug|Win32 - {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Debug|Win32.Build.0 = Debug|Win32 - {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Debug|x64.ActiveCfg = Debug|x64 - {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Debug|x64.Build.0 = Debug|x64 - {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Release|Win32.ActiveCfg = Release|Win32 - {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Release|Win32.Build.0 = Release|Win32 - {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Release|x64.ActiveCfg = Release|x64 - {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Release|x64.Build.0 = Release|x64 - {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Debug|Win32.ActiveCfg = Debug|Win32 - {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Debug|Win32.Build.0 = Debug|Win32 - {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Debug|x64.ActiveCfg = Debug|x64 - {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Debug|x64.Build.0 = Debug|x64 - {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Release|Win32.ActiveCfg = Release|Win32 - {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Release|Win32.Build.0 = Release|Win32 - {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Release|x64.ActiveCfg = Release|x64 - {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Release|x64.Build.0 = Release|x64 - {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Debug|Win32.ActiveCfg = Debug|Win32 - {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Debug|Win32.Build.0 = Debug|Win32 - {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Debug|x64.ActiveCfg = Debug|x64 - {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Debug|x64.Build.0 = Debug|x64 - {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Release|Win32.ActiveCfg = Release|Win32 - {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Release|Win32.Build.0 = Release|Win32 - {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Release|x64.ActiveCfg = Release|x64 - {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Release|x64.Build.0 = Release|x64 - {DB5C12E9-BCD3-4517-8708-475C0D1D88CE}.Debug|Win32.ActiveCfg = Debug|Win32 - {DB5C12E9-BCD3-4517-8708-475C0D1D88CE}.Debug|Win32.Build.0 = Debug|Win32 - {DB5C12E9-BCD3-4517-8708-475C0D1D88CE}.Debug|x64.ActiveCfg = Debug|Win32 - {DB5C12E9-BCD3-4517-8708-475C0D1D88CE}.Release|Win32.ActiveCfg = Release|Win32 - {DB5C12E9-BCD3-4517-8708-475C0D1D88CE}.Release|Win32.Build.0 = Release|Win32 - {DB5C12E9-BCD3-4517-8708-475C0D1D88CE}.Release|x64.ActiveCfg = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VisualBoyAdvance", "VBA2008.vcproj", "{6D4C5EC8-933F-4C05-A1BF-498E658576DF}" + ProjectSection(ProjectDependencies) = postProject + {DB5C12E9-BCD3-4517-8708-475C0D1D88CE} = {DB5C12E9-BCD3-4517-8708-475C0D1D88CE} + {96E945F7-0377-48DA-A5F8-1C192DE9F25F} = {96E945F7-0377-48DA-A5F8-1C192DE9F25F} + {B938FBD9-C7F9-4BF7-8C27-68865D1FA092} = {B938FBD9-C7F9-4BF7-8C27-68865D1FA092} + {7AEC599C-7C82-4F00-AA60-411E0A359CB0} = {7AEC599C-7C82-4F00-AA60-411E0A359CB0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\dependencies\zlib\zlib2008.vcproj", "{B938FBD9-C7F9-4BF7-8C27-68865D1FA092}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "..\dependencies\libpng\libpng2008.vcproj", "{96E945F7-0377-48DA-A5F8-1C192DE9F25F}" + ProjectSection(ProjectDependencies) = postProject + {B938FBD9-C7F9-4BF7-8C27-68865D1FA092} = {B938FBD9-C7F9-4BF7-8C27-68865D1FA092} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "File_Extractor", "..\dependencies\File_Extractor-0.4.2\File_Extractor2008.vcproj", "{7AEC599C-7C82-4F00-AA60-411E0A359CB0}" + ProjectSection(ProjectDependencies) = postProject + {B938FBD9-C7F9-4BF7-8C27-68865D1FA092} = {B938FBD9-C7F9-4BF7-8C27-68865D1FA092} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cximage", "..\dependencies\cximage\cximage2008.vcproj", "{DB5C12E9-BCD3-4517-8708-475C0D1D88CE}" +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 + {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Debug|Win32.ActiveCfg = Debug|Win32 + {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Debug|Win32.Build.0 = Debug|Win32 + {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Debug|x64.ActiveCfg = Debug|x64 + {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Debug|x64.Build.0 = Debug|x64 + {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Release|Win32.ActiveCfg = Release|Win32 + {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Release|Win32.Build.0 = Release|Win32 + {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Release|x64.ActiveCfg = Release|x64 + {6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Release|x64.Build.0 = Release|x64 + {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Debug|Win32.ActiveCfg = Debug|Win32 + {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Debug|Win32.Build.0 = Debug|Win32 + {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Debug|x64.ActiveCfg = Debug|x64 + {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Debug|x64.Build.0 = Debug|x64 + {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Release|Win32.ActiveCfg = Release|Win32 + {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Release|Win32.Build.0 = Release|Win32 + {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Release|x64.ActiveCfg = Release|x64 + {B938FBD9-C7F9-4BF7-8C27-68865D1FA092}.Release|x64.Build.0 = Release|x64 + {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Debug|Win32.ActiveCfg = Debug|Win32 + {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Debug|Win32.Build.0 = Debug|Win32 + {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Debug|x64.ActiveCfg = Debug|x64 + {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Debug|x64.Build.0 = Debug|x64 + {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Release|Win32.ActiveCfg = Release|Win32 + {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Release|Win32.Build.0 = Release|Win32 + {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Release|x64.ActiveCfg = Release|x64 + {96E945F7-0377-48DA-A5F8-1C192DE9F25F}.Release|x64.Build.0 = Release|x64 + {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Debug|Win32.ActiveCfg = Debug|Win32 + {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Debug|Win32.Build.0 = Debug|Win32 + {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Debug|x64.ActiveCfg = Debug|x64 + {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Debug|x64.Build.0 = Debug|x64 + {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Release|Win32.ActiveCfg = Release|Win32 + {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Release|Win32.Build.0 = Release|Win32 + {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Release|x64.ActiveCfg = Release|x64 + {7AEC599C-7C82-4F00-AA60-411E0A359CB0}.Release|x64.Build.0 = Release|x64 + {DB5C12E9-BCD3-4517-8708-475C0D1D88CE}.Debug|Win32.ActiveCfg = Debug|Win32 + {DB5C12E9-BCD3-4517-8708-475C0D1D88CE}.Debug|Win32.Build.0 = Debug|Win32 + {DB5C12E9-BCD3-4517-8708-475C0D1D88CE}.Debug|x64.ActiveCfg = Debug|Win32 + {DB5C12E9-BCD3-4517-8708-475C0D1D88CE}.Release|Win32.ActiveCfg = Release|Win32 + {DB5C12E9-BCD3-4517-8708-475C0D1D88CE}.Release|Win32.Build.0 = Release|Win32 + {DB5C12E9-BCD3-4517-8708-475C0D1D88CE}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/VBA2008.vcproj b/VBA2008.vcproj index 536a8b97..c8275291 100644 --- a/VBA2008.vcproj +++ b/VBA2008.vcproj @@ -1,1869 +1,1869 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/debian/changelog b/debian/changelog index 4cc47e07..a426479f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,14 +1,14 @@ -vbam (0.svn333-1) unstable; urgency=low - - * Added a man page - * Added a default configuration file - * Updated VBA-M to r333 - - -- Bastien Bouclet Tue, 22 Jan 2008 22:06:31 +0100 - -vbam (0.svn307-1) unstable; urgency=low - - * Initial release - - -- Bastien Bouclet Tue, 15 Jan 2008 13:31:45 +0100 - +vbam (0.svn333-1) unstable; urgency=low + + * Added a man page + * Added a default configuration file + * Updated VBA-M to r333 + + -- Bastien Bouclet Tue, 22 Jan 2008 22:06:31 +0100 + +vbam (0.svn307-1) unstable; urgency=low + + * Initial release + + -- Bastien Bouclet Tue, 15 Jan 2008 13:31:45 +0100 + diff --git a/debian/compat b/debian/compat index 3d2c52f7..7ed6ff82 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -5 +5 diff --git a/debian/control b/debian/control index 615d1c4e..1bd45f7e 100644 --- a/debian/control +++ b/debian/control @@ -1,13 +1,13 @@ -Source: vbam -Section: games -Priority: extra -Maintainer: Bastien Bouclet -Build-Depends: debhelper (>= 5), zlib1g-dev, libpng12-dev, libsdl1.2-dev, libgl1-mesa-dev -Standards-Version: 3.7.2 - -Package: vbam -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Description: Nintendo GameBoy Advance emulator - VBA-M is a Nintendo GameBoy Advance emulator. It runs homebrew and commercial games. - This version is based on the SDL library. +Source: vbam +Section: games +Priority: extra +Maintainer: Bastien Bouclet +Build-Depends: debhelper (>= 5), zlib1g-dev, libpng12-dev, libsdl1.2-dev, libgl1-mesa-dev +Standards-Version: 3.7.2 + +Package: vbam +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Nintendo GameBoy Advance emulator + VBA-M is a Nintendo GameBoy Advance emulator. It runs homebrew and commercial games. + This version is based on the SDL library. diff --git a/debian/copyright b/debian/copyright index 5c786a9a..b5e8e0fa 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,23 +1,23 @@ -This package was debianized by Bastien Bouclet on -Tue, 15 Jan 2008 13:31:45 +0100. - -It was downloaded from https://vbam.bountysource.com/ - -Copyright: - - Copyright (C) 1999-2003 Forgotten - Copyright (C) 2004-2006 VBA development team - Copyright (C) 2007-2008 VBA-M development team - -License: - - VBA-M is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - -On Debian systems, the complete text of the GNU General Public License -can be found in the '/usr/share/common-licenses/GPL' file. - -The Debian packaging is (C) 2008, Bastien Bouclet and -is licensed under the GPL, see `/usr/share/common-licenses/GPL'. +This package was debianized by Bastien Bouclet on +Tue, 15 Jan 2008 13:31:45 +0100. + +It was downloaded from https://vbam.bountysource.com/ + +Copyright: + + Copyright (C) 1999-2003 Forgotten + Copyright (C) 2004-2006 VBA development team + Copyright (C) 2007-2008 VBA-M development team + +License: + + VBA-M is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + +On Debian systems, the complete text of the GNU General Public License +can be found in the '/usr/share/common-licenses/GPL' file. + +The Debian packaging is (C) 2008, Bastien Bouclet and +is licensed under the GPL, see `/usr/share/common-licenses/GPL'. diff --git a/debian/dirs b/debian/dirs index 454f2670..ca882bbb 100644 --- a/debian/dirs +++ b/debian/dirs @@ -1,2 +1,2 @@ -usr/bin -usr/sbin +usr/bin +usr/sbin diff --git a/debian/docs b/debian/docs index 1f4582a8..30d29dea 100644 --- a/debian/docs +++ b/debian/docs @@ -1 +1 @@ -doc/* +doc/* diff --git a/debian/vbam.1 b/debian/vbam.1 index 7b49017b..37e7cd94 100644 --- a/debian/vbam.1 +++ b/debian/vbam.1 @@ -1,164 +1,164 @@ -.TH "VBAM" "1" "January 2008" "VBA-M development team" "User Commands" -.SH "NAME" -vbam \- manual page for VisualBoy Advance\-M -.SH "DESCRIPTION" -vbam [option ...] file -.SH "OPTIONS" -.TP -\fB\-O\fR, \fB\-\-opengl\fR=\fIMODE\fR -Set OpenGL texture filter -.TP -\fB\-\-no\-opengl\fR -0 \- Disable OpenGL -.TP -\fB\-\-opengl\-nearest\fR -1 \- No filtering -.TP -\fB\-\-opengl\-bilinear\fR -2 \- Bilinear filtering -.TP -\fB\-F\fR, \fB\-\-fullscreen\fR -Full screen -.TP -\fB\-G\fR, \fB\-\-gdb\fR=\fIPROTOCOL\fR -GNU Remote Stub mode: -\fBtcp\fR \- use TCP at port 55555, -\fBtcp:PORT\fR \- use TCP at port PORT, -\fBpipe\fR \- use pipe transport -.TP -\fB\-I\fR, \fB\-\-ifb\-filter\fR=\fIFILTER\fR -Select interframe blending filter: -\fB0\fR \- No interframe blending, -\fB1\fR \- Interframe motion blur, -\fB2\fR \- Smart interframe blending -.TP -\fB\-N\fR, \fB\-\-no\-debug\fR -Don't parse debug information -.TP -\fB\-S\fR, \fB\-\-flash\-size\fR=\fISIZE\fR -Set the Flash size -.TP -\fB\-\-flash\-64k\fR -0 \- 64K Flash -.TP -\fB\-\-flash\-128k\fR -1 \- 128K Flash -.TP -\fB\-T\fR, \fB\-\-throttle\fR=\fITHROTTLE\fR -Set the desired throttle (5...1000) -.TP -\fB\-b\fR, \fB\-\-bios\fR=\fIBIOS\fR -Use given bios file -.TP -\fB\-c\fR, \fB\-\-config\fR=\fIFILE\fR -Read the given configuration file -.TP -\fB\-d\fR, \fB\-\-debug\fR -Enter debugger -.TP -\fB\-f\fR, \fB\-\-filter\fR=\fIFILTER\fR -Select filter: -\fB0\fR \- Stretch 1x, -\fB1\fR \- Stretch 2x, -\fB2\fR \- 2xSaI, -\fB3\fR \- Super 2xSaI, -\fB4\fR \- Super Eagle, -\fB5\fR \- Pixelate, -\fB6\fR \- Motion Blur, -\fB7\fR \- AdvanceMAME Scale2x, -\fB8\fR \- Bilinear, -\fB9\fR \- Bilinear Plus, -\fB10\fR \- Scanlines, -\fB11\fR \- TV Mode, -\fB12\fR \- lq2x, -\fB13\fR \- hq2x, -\fB14\fR \- Stretch 3x, -\fB15\fR \- hq3x, -\fB16\fR \- Stretch 4x, -\fB17\fR \- hq4x -.TP -\fB\-h\fR, \fB\-\-help\fR -Print an help screen -.TP -\fB\-i\fR, \fB\-\-ips\fR=\fIPATCH\fR -Apply given IPS patch -.TP -\fB\-p\fR, \fB\-\-profile\fR=\fI[HERTZ]\fR -Enable profiling -.TP -\fB\-s\fR, \fB\-\-frameskip\fR=\fIFRAMESKIP\fR -Set frame skip (0...9) -.TP -\fB\-t\fR, \fB\-\-save\-type\fR=\fITYPE\fR -Set the available save type -.TP -\fB\-\-save\-auto\fR -0 \- Automatic (EEPROM, SRAM, FLASH) -.TP -\fB\-\-save\-eeprom\fR -1 \- EEPROM -.TP -\fB\-\-save\-sram\fR -2 \- SRAM -.TP -\fB\-\-save\-flash\fR -3 \- FLASH -.TP -\fB\-\-save\-sensor\fR -4 \- EEPROM+Sensor -.TP -\fB\-\-save\-none\fR -5 \- NONE -.TP -\fB\-v\fR, \fB\-\-verbose\fR=\fIVERBOSE\fR -Set verbose logging (trace.log): -\fB1\fR \- SWI, -\fB2\fR \- Unaligned memory access, -\fB4\fR \- Illegal memory write, -\fB8\fR \- Illegal memory read, -\fB16\fR \- DMA 0, -\fB32\fR \- DMA 1, -\fB64\fR \- DMA 2, -\fB128\fR \- DMA 3, -\fB256\fR \- Undefined instruction, -\fB512\fR \- AGBPrint messages -.SS "Long options only:" -.TP -\fB\-\-agb\-print\fR -Enable AGBPrint support -.TP -\fB\-\-auto\-frameskip\fR -Enable auto frameskipping -.TP -\fB\-\-no\-agb\-print\fR -Disable AGBPrint support -.TP -\fB\-\-no\-auto\-frameskip\fR -Disable auto frameskipping -.TP -\fB\-\-no\-ips\fR -Do not apply IPS patch -.TP -\fB\-\-no\-pause\-when\-inactive\fR -Don't pause when inactive -.TP -\fB\-\-no\-rtc\fR -Disable RTC support -.TP -\fB\-\-no\-show\-speed\fR -Don't show emulation speed -.TP -\fB\-\-no\-throttle\fR -Disable throttle -.TP -\fB\-\-pause\-when\-inactive\fR -Pause when inactive -.TP -\fB\-\-rtc\fR -Enable RTC support -.TP -\fB\-\-show\-speed\-normal\fR -Show emulation speed -.TP -\fB\-\-show\-speed\-detailed\fR -Show detailed speed data +.TH "VBAM" "1" "January 2008" "VBA-M development team" "User Commands" +.SH "NAME" +vbam \- manual page for VisualBoy Advance\-M +.SH "DESCRIPTION" +vbam [option ...] file +.SH "OPTIONS" +.TP +\fB\-O\fR, \fB\-\-opengl\fR=\fIMODE\fR +Set OpenGL texture filter +.TP +\fB\-\-no\-opengl\fR +0 \- Disable OpenGL +.TP +\fB\-\-opengl\-nearest\fR +1 \- No filtering +.TP +\fB\-\-opengl\-bilinear\fR +2 \- Bilinear filtering +.TP +\fB\-F\fR, \fB\-\-fullscreen\fR +Full screen +.TP +\fB\-G\fR, \fB\-\-gdb\fR=\fIPROTOCOL\fR +GNU Remote Stub mode: +\fBtcp\fR \- use TCP at port 55555, +\fBtcp:PORT\fR \- use TCP at port PORT, +\fBpipe\fR \- use pipe transport +.TP +\fB\-I\fR, \fB\-\-ifb\-filter\fR=\fIFILTER\fR +Select interframe blending filter: +\fB0\fR \- No interframe blending, +\fB1\fR \- Interframe motion blur, +\fB2\fR \- Smart interframe blending +.TP +\fB\-N\fR, \fB\-\-no\-debug\fR +Don't parse debug information +.TP +\fB\-S\fR, \fB\-\-flash\-size\fR=\fISIZE\fR +Set the Flash size +.TP +\fB\-\-flash\-64k\fR +0 \- 64K Flash +.TP +\fB\-\-flash\-128k\fR +1 \- 128K Flash +.TP +\fB\-T\fR, \fB\-\-throttle\fR=\fITHROTTLE\fR +Set the desired throttle (5...1000) +.TP +\fB\-b\fR, \fB\-\-bios\fR=\fIBIOS\fR +Use given bios file +.TP +\fB\-c\fR, \fB\-\-config\fR=\fIFILE\fR +Read the given configuration file +.TP +\fB\-d\fR, \fB\-\-debug\fR +Enter debugger +.TP +\fB\-f\fR, \fB\-\-filter\fR=\fIFILTER\fR +Select filter: +\fB0\fR \- Stretch 1x, +\fB1\fR \- Stretch 2x, +\fB2\fR \- 2xSaI, +\fB3\fR \- Super 2xSaI, +\fB4\fR \- Super Eagle, +\fB5\fR \- Pixelate, +\fB6\fR \- Motion Blur, +\fB7\fR \- AdvanceMAME Scale2x, +\fB8\fR \- Bilinear, +\fB9\fR \- Bilinear Plus, +\fB10\fR \- Scanlines, +\fB11\fR \- TV Mode, +\fB12\fR \- lq2x, +\fB13\fR \- hq2x, +\fB14\fR \- Stretch 3x, +\fB15\fR \- hq3x, +\fB16\fR \- Stretch 4x, +\fB17\fR \- hq4x +.TP +\fB\-h\fR, \fB\-\-help\fR +Print an help screen +.TP +\fB\-i\fR, \fB\-\-ips\fR=\fIPATCH\fR +Apply given IPS patch +.TP +\fB\-p\fR, \fB\-\-profile\fR=\fI[HERTZ]\fR +Enable profiling +.TP +\fB\-s\fR, \fB\-\-frameskip\fR=\fIFRAMESKIP\fR +Set frame skip (0...9) +.TP +\fB\-t\fR, \fB\-\-save\-type\fR=\fITYPE\fR +Set the available save type +.TP +\fB\-\-save\-auto\fR +0 \- Automatic (EEPROM, SRAM, FLASH) +.TP +\fB\-\-save\-eeprom\fR +1 \- EEPROM +.TP +\fB\-\-save\-sram\fR +2 \- SRAM +.TP +\fB\-\-save\-flash\fR +3 \- FLASH +.TP +\fB\-\-save\-sensor\fR +4 \- EEPROM+Sensor +.TP +\fB\-\-save\-none\fR +5 \- NONE +.TP +\fB\-v\fR, \fB\-\-verbose\fR=\fIVERBOSE\fR +Set verbose logging (trace.log): +\fB1\fR \- SWI, +\fB2\fR \- Unaligned memory access, +\fB4\fR \- Illegal memory write, +\fB8\fR \- Illegal memory read, +\fB16\fR \- DMA 0, +\fB32\fR \- DMA 1, +\fB64\fR \- DMA 2, +\fB128\fR \- DMA 3, +\fB256\fR \- Undefined instruction, +\fB512\fR \- AGBPrint messages +.SS "Long options only:" +.TP +\fB\-\-agb\-print\fR +Enable AGBPrint support +.TP +\fB\-\-auto\-frameskip\fR +Enable auto frameskipping +.TP +\fB\-\-no\-agb\-print\fR +Disable AGBPrint support +.TP +\fB\-\-no\-auto\-frameskip\fR +Disable auto frameskipping +.TP +\fB\-\-no\-ips\fR +Do not apply IPS patch +.TP +\fB\-\-no\-pause\-when\-inactive\fR +Don't pause when inactive +.TP +\fB\-\-no\-rtc\fR +Disable RTC support +.TP +\fB\-\-no\-show\-speed\fR +Don't show emulation speed +.TP +\fB\-\-no\-throttle\fR +Disable throttle +.TP +\fB\-\-pause\-when\-inactive\fR +Pause when inactive +.TP +\fB\-\-rtc\fR +Enable RTC support +.TP +\fB\-\-show\-speed\-normal\fR +Show emulation speed +.TP +\fB\-\-show\-speed\-detailed\fR +Show detailed speed data diff --git a/debian/vbam.manpages b/debian/vbam.manpages index 968c2ea6..37809c3d 100644 --- a/debian/vbam.manpages +++ b/debian/vbam.manpages @@ -1 +1 @@ -debian/vbam.1 +debian/vbam.1 diff --git a/doc/authors.txt b/doc/authors.txt index f3aa2d5c..d18dd5c6 100644 --- a/doc/authors.txt +++ b/doc/authors.txt @@ -1,14 +1,14 @@ -Original Developers: -Forgotten - -New Developers: -Mudlord -DJRobX -Nach -Jonas Quinn -Spacy - - -The Qt build uses Icons from the KDE project: -http://kde.org/ -svn://anonsvn.kde.org/home/kde/trunk/KDE/kdebase/runtime/pics/oxygen +Original Developers: +Forgotten + +New Developers: +Mudlord +DJRobX +Nach +Jonas Quinn +Spacy + + +The Qt build uses Icons from the KDE project: +http://kde.org/ +svn://anonsvn.kde.org/home/kde/trunk/KDE/kdebase/runtime/pics/oxygen diff --git a/doc/todo.txt b/doc/todo.txt index d09ac777..cfd33c44 100644 --- a/doc/todo.txt +++ b/doc/todo.txt @@ -1,53 +1,53 @@ -Important: -- Many games show emulation warnings in the log window (unaligned read, bad read/write address) - - Test: Metroid Fusion, Advance Wars 2 - -- Gfx.cpp/h optimization - - Test: Final Fantasy 4 airship intro - -- Improve automatic 64k/128k flash save detection - -- HQ3x/4x ASM implementation produces wrong interpolation on the image's border - - This has already been fixed in the C version; look at hq_base.h / line 343 - 372. The ASM version most likely only has something like skipLine instead of skipLinePlus and skipLineMinus, which is however necessary in order to work correctly. - -- Fix OpenGL issues - -- Remove 16 bit hack for filters - - Not compatible to software motion blur (display corruption) - -- Add selection for compressed archives with more than one ROM in them - - - -Less important: -- Add GBA cheat editing support (GB already has) - - Look at Cheats.cpp (Core) and GBACheats.cpp (GUI) - -- Support D3DFMT_A2R10G10B10 (10 bit per color component) color format - -- Add documentation for VBA-M (configuration guide) - -- Improve AVI recording (produces asynchronous files) - -- Enable audio stream compression for AVI files - -- Add stereo upmixing support to OpenAL - -- Verify BIOS files by checksum instead by file extension - -- Merge HQ2x/LQ2x C code into code for HQ3x/4x - -- Apply pixel filter to sprites and BG seperately for better image quality - -- Create Visual Studio project using SDL makefile - - - -Performance: -- Apply HQ3x/4x optimizations from C version to ASM version - -- Apply pixel filter only to changed parts of the image - -- Make use of multi-core CPUs - +Important: +- Many games show emulation warnings in the log window (unaligned read, bad read/write address) + - Test: Metroid Fusion, Advance Wars 2 + +- Gfx.cpp/h optimization + - Test: Final Fantasy 4 airship intro + +- Improve automatic 64k/128k flash save detection + +- HQ3x/4x ASM implementation produces wrong interpolation on the image's border + - This has already been fixed in the C version; look at hq_base.h / line 343 - 372. The ASM version most likely only has something like skipLine instead of skipLinePlus and skipLineMinus, which is however necessary in order to work correctly. + +- Fix OpenGL issues + +- Remove 16 bit hack for filters + - Not compatible to software motion blur (display corruption) + +- Add selection for compressed archives with more than one ROM in them + + + +Less important: +- Add GBA cheat editing support (GB already has) + - Look at Cheats.cpp (Core) and GBACheats.cpp (GUI) + +- Support D3DFMT_A2R10G10B10 (10 bit per color component) color format + +- Add documentation for VBA-M (configuration guide) + +- Improve AVI recording (produces asynchronous files) + +- Enable audio stream compression for AVI files + +- Add stereo upmixing support to OpenAL + +- Verify BIOS files by checksum instead by file extension + +- Merge HQ2x/LQ2x C code into code for HQ3x/4x + +- Apply pixel filter to sprites and BG seperately for better image quality + +- Create Visual Studio project using SDL makefile + + + +Performance: +- Apply HQ3x/4x optimizations from C version to ASM version + +- Apply pixel filter only to changed parts of the image + +- Make use of multi-core CPUs + - Make use of 64 bit CPUs \ No newline at end of file diff --git a/lang/how-to.txt b/lang/how-to.txt index e0683f67..690e4fa1 100644 --- a/lang/how-to.txt +++ b/lang/how-to.txt @@ -1,27 +1,27 @@ -How to create a new translation: - -For Windows: - -- Add "TRANSLATIONS += path/to/language.ts" to vba-m.pro - -- Execute the "update.cmd" script to create .ts files - -- Edit & translate the .ts file with the "Qt Linguist" tool - -- Execute the "release.cmd" script to compile it to a .qm file - -- The .qm file can now be loaded & used by the application - - - -For Linux: - -- Add "TRANSLATIONS += path/to/language.ts" to vba-m.pro - -- Type lrelease vba-m.pro - -- Edit & translate the .ts file with the "Qt Linguist" tool - -- In Qt Linguist, go to File -> release as. This will compile it into a .qm file - -- The .qm file can now be loaded & used by the application +How to create a new translation: + +For Windows: + +- Add "TRANSLATIONS += path/to/language.ts" to vba-m.pro + +- Execute the "update.cmd" script to create .ts files + +- Edit & translate the .ts file with the "Qt Linguist" tool + +- Execute the "release.cmd" script to compile it to a .qm file + +- The .qm file can now be loaded & used by the application + + + +For Linux: + +- Add "TRANSLATIONS += path/to/language.ts" to vba-m.pro + +- Type lrelease vba-m.pro + +- Edit & translate the .ts file with the "Qt Linguist" tool + +- In Qt Linguist, go to File -> release as. This will compile it into a .qm file + +- The .qm file can now be loaded & used by the application diff --git a/lang/release.cmd b/lang/release.cmd index 102d695b..6b9d11d2 100644 --- a/lang/release.cmd +++ b/lang/release.cmd @@ -1,2 +1,2 @@ -cd ..\project\qmake +cd ..\project\qmake lrelease vba-m.pro \ No newline at end of file diff --git a/lang/update.cmd b/lang/update.cmd index 0c01594c..810d9ea9 100644 --- a/lang/update.cmd +++ b/lang/update.cmd @@ -1,2 +1,2 @@ -cd ..\project\qmake +cd ..\project\qmake lupdate vba-m.pro \ No newline at end of file diff --git a/project/qmake/vba-m.pro b/project/qmake/vba-m.pro index c0a5368e..2e17784a 100644 --- a/project/qmake/vba-m.pro +++ b/project/qmake/vba-m.pro @@ -1,169 +1,169 @@ -TEMPLATE = app -CONFIG += qt release -QT += opengl -TARGET = VisualBoyAdvance -DEFINES += BKPT_SUPPORT - - -# Directory Locations -M_DIR_QT = ../../src/qt/ -M_DIR_LANG = ../../lang/ -M_DIR_SHARED = ../../src/ -M_DIR_GBAPU = ../../src/dmg/gb_apu/ -M_DIR_AGB = ../../src/agb/ -M_DIR_DMG = ../../src/dmg/ - - -# Tweaks -win32-msvc2005 { - DEFINES += _CRT_SECURE_NO_WARNINGS - DEFINES += NO_PNG -} - - -# Resource Files -RESOURCES += $${M_DIR_QT}vba-m.qrc - -win32 { - RC_FILE = $${M_DIR_QT}vba-m.rc -} - - -# Language Files -TRANSLATIONS += $${M_DIR_LANG}german.ts -TRANSLATIONS += $${M_DIR_LANG}spanish.ts - - -# Qt GUI Files -PRECOMPILED_HEADER = $${M_DIR_QT}precompile.h - -HEADERS += $${M_DIR_QT}version.h - -HEADERS += $${M_DIR_QT}main.h -SOURCES += $${M_DIR_QT}main.cpp - -HEADERS += $${M_DIR_QT}MainWnd.h -SOURCES += $${M_DIR_QT}MainWnd.cpp - -FORMS += $${M_DIR_QT}sidewidget_cheats.ui -HEADERS += $${M_DIR_QT}sidewidget_cheats.h -SOURCES += $${M_DIR_QT}sidewidget_cheats.cpp - -HEADERS += $${M_DIR_QT}MainOptions.h -SOURCES += $${M_DIR_QT}MainOptions.cpp - -HEADERS += $${M_DIR_QT}configdialog.h -SOURCES += $${M_DIR_QT}configdialog.cpp - -HEADERS += $${M_DIR_QT}emu.h -SOURCES += $${M_DIR_QT}emu.cpp - -HEADERS += $${M_DIR_QT}EmuManager.h -SOURCES += $${M_DIR_QT}EmuManager.cpp - -HEADERS += $${M_DIR_QT}GraphicsOutput.h -SOURCES += $${M_DIR_QT}GraphicsOutput.cpp - - -# Shared Core Files -HEADERS += $${M_DIR_SHARED}System.h - -HEADERS += $${M_DIR_SHARED}Globals.h -SOURCES += $${M_DIR_SHARED}Globals.cpp - -#HEADERS += $${M_DIR_SHARED}armdis.h -#SOURCES += $${M_DIR_SHARED}armdis.cpp - -HEADERS += $${M_DIR_SHARED}bios.h -SOURCES += $${M_DIR_SHARED}bios.cpp - -HEADERS += $${M_DIR_SHARED}Cheats.h -SOURCES += $${M_DIR_SHARED}Cheats.cpp - -#HEADERS += $${M_DIR_SHARED}CheatSearch.h -#SOURCES += $${M_DIR_SHARED}CheatSearch.cpp - -HEADERS += $${M_DIR_SHARED}EEprom.h -SOURCES += $${M_DIR_SHARED}EEprom.cpp - -HEADERS += $${M_DIR_SHARED}Flash.h -SOURCES += $${M_DIR_SHARED}Flash.cpp - -HEADERS += $${M_DIR_SHARED}Sram.h -SOURCES += $${M_DIR_SHARED}Sram.cpp - -HEADERS += $${M_DIR_SHARED}elf.h -SOURCES += $${M_DIR_SHARED}elf.cpp - -HEADERS += $${M_DIR_SHARED}RTC.h -SOURCES += $${M_DIR_SHARED}RTC.cpp - -HEADERS += $${M_DIR_SHARED}Sound.h -SOURCES += $${M_DIR_SHARED}Sound.cpp - -HEADERS += $${M_DIR_SHARED}memgzio.h -SOURCES += $${M_DIR_SHARED}memgzio.c - -HEADERS += $${M_DIR_SHARED}fex.h -SOURCES += $${M_DIR_SHARED}fex_mini.cpp - -HEADERS += $${M_DIR_SHARED}Util.h -SOURCES += $${M_DIR_SHARED}Util.cpp - -SOURCES += $${M_DIR_SHARED}Mode0.cpp -SOURCES += $${M_DIR_SHARED}Mode1.cpp -SOURCES += $${M_DIR_SHARED}Mode2.cpp -SOURCES += $${M_DIR_SHARED}Mode3.cpp -SOURCES += $${M_DIR_SHARED}Mode4.cpp -SOURCES += $${M_DIR_SHARED}Mode5.cpp - -#HEADERS += $${M_DIR_SHARED}NLS.h - -#HEADERS += $${M_DIR_SHARED}Port.h - -#SOURCES += $${M_DIR_SHARED}remote.cpp - - -# GB APU -HEADERS += $${M_DIR_GBAPU}blargg_common.h -HEADERS += $${M_DIR_GBAPU}blargg_config.h -HEADERS += $${M_DIR_GBAPU}blargg_source.h - -HEADERS += $${M_DIR_GBAPU}Blip_Buffer.h -SOURCES += $${M_DIR_GBAPU}Blip_Buffer.cpp - -HEADERS += $${M_DIR_GBAPU}Effects_Buffer.h -SOURCES += $${M_DIR_GBAPU}Effects_Buffer.cpp - -HEADERS += $${M_DIR_GBAPU}Gb_Apu.h -SOURCES += $${M_DIR_GBAPU}Gb_Apu.cpp -SOURCES += $${M_DIR_GBAPU}Gb_Apu_State.cpp - -HEADERS += $${M_DIR_GBAPU}Gb_Oscs.h -SOURCES += $${M_DIR_GBAPU}Gb_Oscs.cpp - -HEADERS += $${M_DIR_GBAPU}Multi_Buffer.h -SOURCES += $${M_DIR_GBAPU}Multi_Buffer.cpp - - -# GBA Core Files -HEADERS += $${M_DIR_AGB}agbprint.h -SOURCES += $${M_DIR_AGB}agbprint.cpp - -HEADERS += $${M_DIR_AGB}GBA.h -SOURCES += $${M_DIR_AGB}GBA.cpp - -#HEADERS += $${M_DIR_AGB}gbafilter.h -#SOURCES += $${M_DIR_AGB}gbafilter.cpp - -HEADERS += $${M_DIR_AGB}GBAGfx.h -SOURCES += $${M_DIR_AGB}GBAGfx.cpp - -#HEADERS += $${M_DIR_AGB}GBALink.h -#SOURCES += $${M_DIR_AGB}GBALink.cpp - -SOURCES += $${M_DIR_AGB}GBA-arm.cpp -SOURCES += $${M_DIR_AGB}GBA-thumb.cpp - -HEADERS += $${M_DIR_AGB}GBAcpu.h -HEADERS += $${M_DIR_AGB}GBAinline.h +TEMPLATE = app +CONFIG += qt release +QT += opengl +TARGET = VisualBoyAdvance +DEFINES += BKPT_SUPPORT + + +# Directory Locations +M_DIR_QT = ../../src/qt/ +M_DIR_LANG = ../../lang/ +M_DIR_SHARED = ../../src/ +M_DIR_GBAPU = ../../src/dmg/gb_apu/ +M_DIR_AGB = ../../src/agb/ +M_DIR_DMG = ../../src/dmg/ + + +# Tweaks +win32-msvc2005 { + DEFINES += _CRT_SECURE_NO_WARNINGS + DEFINES += NO_PNG +} + + +# Resource Files +RESOURCES += $${M_DIR_QT}vba-m.qrc + +win32 { + RC_FILE = $${M_DIR_QT}vba-m.rc +} + + +# Language Files +TRANSLATIONS += $${M_DIR_LANG}german.ts +TRANSLATIONS += $${M_DIR_LANG}spanish.ts + + +# Qt GUI Files +PRECOMPILED_HEADER = $${M_DIR_QT}precompile.h + +HEADERS += $${M_DIR_QT}version.h + +HEADERS += $${M_DIR_QT}main.h +SOURCES += $${M_DIR_QT}main.cpp + +HEADERS += $${M_DIR_QT}MainWnd.h +SOURCES += $${M_DIR_QT}MainWnd.cpp + +FORMS += $${M_DIR_QT}sidewidget_cheats.ui +HEADERS += $${M_DIR_QT}sidewidget_cheats.h +SOURCES += $${M_DIR_QT}sidewidget_cheats.cpp + +HEADERS += $${M_DIR_QT}MainOptions.h +SOURCES += $${M_DIR_QT}MainOptions.cpp + +HEADERS += $${M_DIR_QT}configdialog.h +SOURCES += $${M_DIR_QT}configdialog.cpp + +HEADERS += $${M_DIR_QT}emu.h +SOURCES += $${M_DIR_QT}emu.cpp + +HEADERS += $${M_DIR_QT}EmuManager.h +SOURCES += $${M_DIR_QT}EmuManager.cpp + +HEADERS += $${M_DIR_QT}GraphicsOutput.h +SOURCES += $${M_DIR_QT}GraphicsOutput.cpp + + +# Shared Core Files +HEADERS += $${M_DIR_SHARED}System.h + +HEADERS += $${M_DIR_SHARED}Globals.h +SOURCES += $${M_DIR_SHARED}Globals.cpp + +#HEADERS += $${M_DIR_SHARED}armdis.h +#SOURCES += $${M_DIR_SHARED}armdis.cpp + +HEADERS += $${M_DIR_SHARED}bios.h +SOURCES += $${M_DIR_SHARED}bios.cpp + +HEADERS += $${M_DIR_SHARED}Cheats.h +SOURCES += $${M_DIR_SHARED}Cheats.cpp + +#HEADERS += $${M_DIR_SHARED}CheatSearch.h +#SOURCES += $${M_DIR_SHARED}CheatSearch.cpp + +HEADERS += $${M_DIR_SHARED}EEprom.h +SOURCES += $${M_DIR_SHARED}EEprom.cpp + +HEADERS += $${M_DIR_SHARED}Flash.h +SOURCES += $${M_DIR_SHARED}Flash.cpp + +HEADERS += $${M_DIR_SHARED}Sram.h +SOURCES += $${M_DIR_SHARED}Sram.cpp + +HEADERS += $${M_DIR_SHARED}elf.h +SOURCES += $${M_DIR_SHARED}elf.cpp + +HEADERS += $${M_DIR_SHARED}RTC.h +SOURCES += $${M_DIR_SHARED}RTC.cpp + +HEADERS += $${M_DIR_SHARED}Sound.h +SOURCES += $${M_DIR_SHARED}Sound.cpp + +HEADERS += $${M_DIR_SHARED}memgzio.h +SOURCES += $${M_DIR_SHARED}memgzio.c + +HEADERS += $${M_DIR_SHARED}fex.h +SOURCES += $${M_DIR_SHARED}fex_mini.cpp + +HEADERS += $${M_DIR_SHARED}Util.h +SOURCES += $${M_DIR_SHARED}Util.cpp + +SOURCES += $${M_DIR_SHARED}Mode0.cpp +SOURCES += $${M_DIR_SHARED}Mode1.cpp +SOURCES += $${M_DIR_SHARED}Mode2.cpp +SOURCES += $${M_DIR_SHARED}Mode3.cpp +SOURCES += $${M_DIR_SHARED}Mode4.cpp +SOURCES += $${M_DIR_SHARED}Mode5.cpp + +#HEADERS += $${M_DIR_SHARED}NLS.h + +#HEADERS += $${M_DIR_SHARED}Port.h + +#SOURCES += $${M_DIR_SHARED}remote.cpp + + +# GB APU +HEADERS += $${M_DIR_GBAPU}blargg_common.h +HEADERS += $${M_DIR_GBAPU}blargg_config.h +HEADERS += $${M_DIR_GBAPU}blargg_source.h + +HEADERS += $${M_DIR_GBAPU}Blip_Buffer.h +SOURCES += $${M_DIR_GBAPU}Blip_Buffer.cpp + +HEADERS += $${M_DIR_GBAPU}Effects_Buffer.h +SOURCES += $${M_DIR_GBAPU}Effects_Buffer.cpp + +HEADERS += $${M_DIR_GBAPU}Gb_Apu.h +SOURCES += $${M_DIR_GBAPU}Gb_Apu.cpp +SOURCES += $${M_DIR_GBAPU}Gb_Apu_State.cpp + +HEADERS += $${M_DIR_GBAPU}Gb_Oscs.h +SOURCES += $${M_DIR_GBAPU}Gb_Oscs.cpp + +HEADERS += $${M_DIR_GBAPU}Multi_Buffer.h +SOURCES += $${M_DIR_GBAPU}Multi_Buffer.cpp + + +# GBA Core Files +HEADERS += $${M_DIR_AGB}agbprint.h +SOURCES += $${M_DIR_AGB}agbprint.cpp + +HEADERS += $${M_DIR_AGB}GBA.h +SOURCES += $${M_DIR_AGB}GBA.cpp + +#HEADERS += $${M_DIR_AGB}gbafilter.h +#SOURCES += $${M_DIR_AGB}gbafilter.cpp + +HEADERS += $${M_DIR_AGB}GBAGfx.h +SOURCES += $${M_DIR_AGB}GBAGfx.cpp + +#HEADERS += $${M_DIR_AGB}GBALink.h +#SOURCES += $${M_DIR_AGB}GBALink.cpp + +SOURCES += $${M_DIR_AGB}GBA-arm.cpp +SOURCES += $${M_DIR_AGB}GBA-thumb.cpp + +HEADERS += $${M_DIR_AGB}GBAcpu.h +HEADERS += $${M_DIR_AGB}GBAinline.h diff --git a/project/vc2008/vba-m.sln b/project/vc2008/vba-m.sln index ec80a3c8..22f34466 100644 --- a/project/vc2008/vba-m.sln +++ b/project/vc2008/vba-m.sln @@ -1,20 +1,20 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vba-m", "vba-m.vcproj", "{714B3EF3-5D43-421F-A97E-447540E7C137}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - debug|Win32 = debug|Win32 - release|Win32 = release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {714B3EF3-5D43-421F-A97E-447540E7C137}.debug|Win32.ActiveCfg = debug|Win32 - {714B3EF3-5D43-421F-A97E-447540E7C137}.debug|Win32.Build.0 = debug|Win32 - {714B3EF3-5D43-421F-A97E-447540E7C137}.release|Win32.ActiveCfg = release|Win32 - {714B3EF3-5D43-421F-A97E-447540E7C137}.release|Win32.Build.0 = release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vba-m", "vba-m.vcproj", "{714B3EF3-5D43-421F-A97E-447540E7C137}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + debug|Win32 = debug|Win32 + release|Win32 = release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {714B3EF3-5D43-421F-A97E-447540E7C137}.debug|Win32.ActiveCfg = debug|Win32 + {714B3EF3-5D43-421F-A97E-447540E7C137}.debug|Win32.Build.0 = debug|Win32 + {714B3EF3-5D43-421F-A97E-447540E7C137}.release|Win32.ActiveCfg = release|Win32 + {714B3EF3-5D43-421F-A97E-447540E7C137}.release|Win32.Build.0 = release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/project/vc2008/vba-m.vcproj b/project/vc2008/vba-m.vcproj index d8542ca2..1f405713 100644 --- a/project/vc2008/vba-m.vcproj +++ b/project/vc2008/vba-m.vcproj @@ -1,437 +1,437 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Util.cpp b/src/Util.cpp index cbb5c0fa..171e1d9b 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -1,751 +1,751 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004-2006 Forgotten and the VBA development team -// Copyright (C) 2007-2008 VBA-M development team and Shay Green -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include -#include -#include -#include - -#ifndef NO_PNG -extern "C" { -#include -} -#endif - -#include "System.h" -#include "NLS.h" -#include "Util.h" -#include "Flash.h" -#include "agb/GBA.h" -#include "Globals.h" -#include "RTC.h" -#include "Port.h" - -#include "fex.h" - -extern "C" { -#include "memgzio.h" -} - -#ifndef _MSC_VER -#define _stricmp strcasecmp -#endif // ! _MSC_VER - -extern int systemColorDepth; -extern int systemRedShift; -extern int systemGreenShift; -extern int systemBlueShift; - -extern u16 systemColorMap16[0x10000]; -extern u32 systemColorMap32[0x10000]; - -static int (ZEXPORT *utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL; -static int (ZEXPORT *utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL; -static int (ZEXPORT *utilGzCloseFunc)(gzFile) = NULL; - -bool utilWritePNGFile(const char *fileName, int w, int h, u8 *pix) -{ -#ifndef NO_PNG - u8 writeBuffer[512 * 3]; - - FILE *fp = fopen(fileName,"wb"); - - if(!fp) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); - return false; - } - - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, - NULL, - NULL, - NULL); - if(!png_ptr) { - fclose(fp); - return false; - } - - png_infop info_ptr = png_create_info_struct(png_ptr); - - if(!info_ptr) { - png_destroy_write_struct(&png_ptr,NULL); - fclose(fp); - return false; - } - - if(setjmp(png_ptr->jmpbuf)) { - png_destroy_write_struct(&png_ptr,NULL); - fclose(fp); - return false; - } - - png_init_io(png_ptr,fp); - - png_set_IHDR(png_ptr, - info_ptr, - w, - h, - 8, - PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - - png_write_info(png_ptr,info_ptr); - - u8 *b = writeBuffer; - - int sizeX = w; - int sizeY = h; - - switch(systemColorDepth) { - case 16: - { - u16 *p = (u16 *)(pix+(w+2)*2); // skip first black line - for(int y = 0; y < sizeY; y++) { - for(int x = 0; x < sizeX; x++) { - u16 v = *p++; - - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B - } - p++; // skip black pixel for filters - p++; // skip black pixel for filters - png_write_row(png_ptr,writeBuffer); - - b = writeBuffer; - } - } - break; - case 24: - { - u8 *pixU8 = (u8 *)pix; - for(int y = 0; y < sizeY; y++) { - for(int x = 0; x < sizeX; x++) { - if(systemRedShift < systemBlueShift) { - *b++ = *pixU8++; // R - *b++ = *pixU8++; // G - *b++ = *pixU8++; // B - } else { - int blue = *pixU8++; - int green = *pixU8++; - int red = *pixU8++; - - *b++ = red; - *b++ = green; - *b++ = blue; - } - } - png_write_row(png_ptr,writeBuffer); - - b = writeBuffer; - } - } - break; - case 32: - { - u32 *pixU32 = (u32 *)(pix+4*(w+1)); - for(int y = 0; y < sizeY; y++) { - for(int x = 0; x < sizeX; x++) { - u32 v = *pixU32++; - - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B - } - pixU32++; - - png_write_row(png_ptr,writeBuffer); - - b = writeBuffer; - } - } - break; - } - - png_write_end(png_ptr, info_ptr); - - png_destroy_write_struct(&png_ptr, &info_ptr); - - fclose(fp); - - return true; -#else - return false; -#endif -} - -void utilPutDword(u8 *p, u32 value) -{ - *p++ = value & 255; - *p++ = (value >> 8) & 255; - *p++ = (value >> 16) & 255; - *p = (value >> 24) & 255; -} - -void utilPutWord(u8 *p, u16 value) -{ - *p++ = value & 255; - *p = (value >> 8) & 255; -} - -bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix) -{ - u8 writeBuffer[512 * 3]; - - FILE *fp = fopen(fileName,"wb"); - - if(!fp) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); - return false; - } - - struct { - u8 ident[2]; - u8 filesize[4]; - u8 reserved[4]; - u8 dataoffset[4]; - u8 headersize[4]; - u8 width[4]; - u8 height[4]; - u8 planes[2]; - u8 bitsperpixel[2]; - u8 compression[4]; - u8 datasize[4]; - u8 hres[4]; - u8 vres[4]; - u8 colors[4]; - u8 importantcolors[4]; - // u8 pad[2]; - } bmpheader; - memset(&bmpheader, 0, sizeof(bmpheader)); - - bmpheader.ident[0] = 'B'; - bmpheader.ident[1] = 'M'; - - u32 fsz = sizeof(bmpheader) + w*h*3; - utilPutDword(bmpheader.filesize, fsz); - utilPutDword(bmpheader.dataoffset, 0x36); - utilPutDword(bmpheader.headersize, 0x28); - utilPutDword(bmpheader.width, w); - utilPutDword(bmpheader.height, h); - utilPutDword(bmpheader.planes, 1); - utilPutDword(bmpheader.bitsperpixel, 24); - utilPutDword(bmpheader.datasize, 3*w*h); - - fwrite(&bmpheader, 1, sizeof(bmpheader), fp); - - u8 *b = writeBuffer; - - int sizeX = w; - int sizeY = h; - - switch(systemColorDepth) { - case 16: - { - u16 *p = (u16 *)(pix+(w+2)*(h)*2); // skip first black line - for(int y = 0; y < sizeY; y++) { - for(int x = 0; x < sizeX; x++) { - u16 v = *p++; - - *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - } - p++; // skip black pixel for filters - p++; // skip black pixel for filters - p -= 2*(w+2); - fwrite(writeBuffer, 1, 3*w, fp); - - b = writeBuffer; - } - } - break; - case 24: - { - u8 *pixU8 = (u8 *)pix+3*w*(h-1); - for(int y = 0; y < sizeY; y++) { - for(int x = 0; x < sizeX; x++) { - if(systemRedShift > systemBlueShift) { - *b++ = *pixU8++; // B - *b++ = *pixU8++; // G - *b++ = *pixU8++; // R - } else { - int red = *pixU8++; - int green = *pixU8++; - int blue = *pixU8++; - - *b++ = blue; - *b++ = green; - *b++ = red; - } - } - pixU8 -= 2*3*w; - fwrite(writeBuffer, 1, 3*w, fp); - - b = writeBuffer; - } - } - break; - case 32: - { - u32 *pixU32 = (u32 *)(pix+4*(w+1)*(h)); - for(int y = 0; y < sizeY; y++) { - for(int x = 0; x < sizeX; x++) { - u32 v = *pixU32++; - - *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - } - pixU32++; - pixU32 -= 2*(w+1); - - fwrite(writeBuffer, 1, 3*w, fp); - - b = writeBuffer; - } - } - break; - } - - fclose(fp); - - return true; -} - -static int utilReadInt2(FILE *f) -{ - int res = 0; - int c = fgetc(f); - if(c == EOF) - return -1; - res = c; - c = fgetc(f); - if(c == EOF) - return -1; - return c + (res<<8); -} - -static int utilReadInt3(FILE *f) -{ - int res = 0; - int c = fgetc(f); - if(c == EOF) - return -1; - res = c; - c = fgetc(f); - if(c == EOF) - return -1; - res = c + (res<<8); - c = fgetc(f); - if(c == EOF) - return -1; - return c + (res<<8); -} - -void utilApplyIPS(const char *ips, u8 **r, int *s) -{ - // from the IPS spec at http://zerosoft.zophar.net/ips.htm - FILE *f = fopen(ips, "rb"); - if(!f) - return; - u8 *rom = *r; - int size = *s; - if(fgetc(f) == 'P' && - fgetc(f) == 'A' && - fgetc(f) == 'T' && - fgetc(f) == 'C' && - fgetc(f) == 'H') { - int b; - int offset; - int len; - for(;;) { - // read offset - offset = utilReadInt3(f); - // if offset == EOF, end of patch - if(offset == 0x454f46) - break; - // read length - len = utilReadInt2(f); - if(!len) { - // len == 0, RLE block - len = utilReadInt2(f); - // byte to fill - int c = fgetc(f); - if(c == -1) - break; - b = (u8)c; - } else - b= -1; - // check if we need to reallocate our ROM - if((offset + len) >= size) { - size *= 2; - rom = (u8 *)realloc(rom, size); - *r = rom; - *s = size; - } - if(b == -1) { - // normal block, just read the data - if(fread(&rom[offset], 1, len, f) != (size_t)len) - break; - } else { - // fill the region with the given byte - while(len--) { - rom[offset++] = b; - } - } - } - } - // close the file - fclose(f); -} - -extern bool cpuIsMultiBoot; - -bool utilIsGBAImage(const char * file) -{ - cpuIsMultiBoot = false; - if(strlen(file) > 4) { - const char * p = strrchr(file,'.'); - - if(p != NULL) { - if(_stricmp(p, ".gba") == 0) - return true; - if(_stricmp(p, ".agb") == 0) - return true; - if(_stricmp(p, ".bin") == 0) - return true; - if(_stricmp(p, ".elf") == 0) - return true; - if(_stricmp(p, ".mb") == 0) { - cpuIsMultiBoot = true; - return true; - } - } - } - - return false; -} - -bool utilIsGBImage(const char * file) -{ - if(strlen(file) > 4) { - const char * p = strrchr(file,'.'); - - if(p != NULL) { - if(_stricmp(p, ".gb") == 0) - return true; - if(_stricmp(p, ".gbc") == 0) - return true; - if(_stricmp(p, ".cgb") == 0) - return true; - if(_stricmp(p, ".sgb") == 0) - return true; - } - } - - return false; -} - -bool utilIsGzipFile(const char *file) -{ - if(strlen(file) > 3) { - const char * p = strrchr(file,'.'); - - if(p != NULL) { - if(_stricmp(p, ".gz") == 0) - return true; - if(_stricmp(p, ".z") == 0) - return true; - } - } - - return false; -} - -// strip .gz or .z off end -void utilStripDoubleExtension(const char *file, char *buffer) -{ - if(buffer != file) // allows conversion in place - strcpy(buffer, file); - - if(utilIsGzipFile(file)) { - char *p = strrchr(buffer, '.'); - - if(p) - *p = 0; - } -} - -// Opens and scans archive using accept(). Returns File_Extractor if found. -// If error or not found, displays message and returns NULL. -static File_Extractor* scan_arc(const char *file, bool (*accept)(const char *), - char (&buffer) [2048] ) -{ - fex_err_t err; - File_Extractor* fe = fex_open( file, &err ); - if(!fe) - { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s: %s"), file, err); - return NULL; - } - - // Scan filenames - bool found=false; - while(!fex_done(fe)) { - strncpy(buffer,fex_name(fe),sizeof buffer); - buffer [sizeof buffer-1] = '\0'; - - utilStripDoubleExtension(buffer, buffer); - - if(accept(buffer)) { - found = true; - break; - } - - fex_err_t err = fex_next(fe); - if(err) { - systemMessage(MSG_BAD_ZIP_FILE, N_("Cannot read archive %s: %s"), file, err); - fex_close(fe); - return NULL; - } - } - - if(!found) { - systemMessage(MSG_NO_IMAGE_ON_ZIP, - N_("No image found in file %s"), file); - fex_close(fe); - return NULL; - } - return fe; -} - -static bool utilIsImage(const char *file) -{ - return utilIsGBAImage(file) || utilIsGBImage(file); -} - -IMAGE_TYPE utilFindType(const char *file) -{ - char buffer [2048]; - if ( !utilIsImage( file ) ) // TODO: utilIsArchive() instead? - { - File_Extractor* fe = scan_arc(file,utilIsImage,buffer); - if(!fe) - return IMAGE_UNKNOWN; - fex_close(fe); - file = buffer; - } - - return utilIsGBAImage(file) ? IMAGE_GBA : IMAGE_GB; -} - -static int utilGetSize(int size) -{ - int res = 1; - while(res < size) - res <<= 1; - return res; -} - -u8 *utilLoad(const char *file, - bool (*accept)(const char *), - u8 *data, - int &size) -{ - // find image file - char buffer [2048]; - File_Extractor *fe = scan_arc(file,accept,buffer); - if(!fe) - return NULL; - - // Allocate space for image - int fileSize = fex_size(fe); - if(size == 0) - size = fileSize; - - u8 *image = data; - - if(image == NULL) { - // allocate buffer memory if none was passed to the function - image = (u8 *)malloc(utilGetSize(size)); - if(image == NULL) { - fex_close(fe); - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "data"); - return NULL; - } - size = fileSize; - } - - // Read image - int read = fileSize <= size ? fileSize : size; // do not read beyond file - fex_err_t err = fex_read_once(fe, image, read); - fex_close(fe); - if(err) { - systemMessage(MSG_ERROR_READING_IMAGE, - N_("Error reading image from %s: %s"), buffer, err); - if(data == NULL) - free(image); - return NULL; - } - - size = fileSize; - - return image; -} - -void utilWriteInt(gzFile gzFile, int i) -{ - utilGzWrite(gzFile, &i, sizeof(int)); -} - -int utilReadInt(gzFile gzFile) -{ - int i = 0; - utilGzRead(gzFile, &i, sizeof(int)); - return i; -} - -void utilReadData(gzFile gzFile, variable_desc* data) -{ - while(data->address) { - utilGzRead(gzFile, data->address, data->size); - data++; - } -} - -void utilWriteData(gzFile gzFile, variable_desc *data) -{ - while(data->address) { - utilGzWrite(gzFile, data->address, data->size); - data++; - } -} - -gzFile utilGzOpen(const char *file, const char *mode) -{ - utilGzWriteFunc = (int (ZEXPORT *)(void *,void * const, unsigned int))gzwrite; - utilGzReadFunc = gzread; - utilGzCloseFunc = gzclose; - - return gzopen(file, mode); -} - -gzFile utilMemGzOpen(char *memory, int available, const char *mode) -{ - utilGzWriteFunc = memgzwrite; - utilGzReadFunc = memgzread; - utilGzCloseFunc = memgzclose; - - return memgzopen(memory, available, mode); -} - -int utilGzWrite(gzFile file, const voidp buffer, unsigned int len) -{ - return utilGzWriteFunc(file, buffer, len); -} - -int utilGzRead(gzFile file, voidp buffer, unsigned int len) -{ - return utilGzReadFunc(file, buffer, len); -} - -int utilGzClose(gzFile file) -{ - return utilGzCloseFunc(file); -} - -long utilGzMemTell(gzFile file) -{ - return memtell(file); -} - -void utilGBAFindSave(const u8 *data, const int size) -{ - u32 *p = (u32 *)data; - u32 *end = (u32 *)(data + size); - int saveType = 0; - int flashSize = 0x10000; - bool rtcFound = false; - - while(p < end) { - u32 d = READ32LE(p); - - if(d == 0x52504545) { - if(memcmp(p, "EEPROM_", 7) == 0) { - if(saveType == 0) - saveType = 3; - } - } else if (d == 0x4D415253) { - if(memcmp(p, "SRAM_", 5) == 0) { - if(saveType == 0) - saveType = 1; - } - } else if (d == 0x53414C46) { - if(memcmp(p, "FLASH1M_", 8) == 0) { - if(saveType == 0) { - saveType = 2; - flashSize = 0x20000; - } - } else if(memcmp(p, "FLASH", 5) == 0) { - if(saveType == 0) { - saveType = 2; - flashSize = 0x10000; - } - } - } else if (d == 0x52494953) { - if(memcmp(p, "SIIRTC_V", 8) == 0) - rtcFound = true; - } - p++; - } - // if no matches found, then set it to NONE - if(saveType == 0) { - saveType = 5; - } - rtcEnable(rtcFound); - cpuSaveType = saveType; - flashSetSize(flashSize); -} - -void utilUpdateSystemColorMaps() -{ - switch(systemColorDepth) { - case 16: - { - for(int i = 0; i < 0x10000; i++) { - systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | - (((i & 0x3e0) >> 5) << systemGreenShift) | - (((i & 0x7c00) >> 10) << systemBlueShift); - } - } - break; - case 24: - case 32: - { - for(int i = 0; i < 0x10000; i++) { - systemColorMap32[i] = ((i & 0x1f) << systemRedShift) | - (((i & 0x3e0) >> 5) << systemGreenShift) | - (((i & 0x7c00) >> 10) << systemBlueShift); - } - } - break; - } -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004-2006 Forgotten and the VBA development team +// Copyright (C) 2007-2008 VBA-M development team and Shay Green +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include +#include +#include + +#ifndef NO_PNG +extern "C" { +#include +} +#endif + +#include "System.h" +#include "NLS.h" +#include "Util.h" +#include "Flash.h" +#include "agb/GBA.h" +#include "Globals.h" +#include "RTC.h" +#include "Port.h" + +#include "fex.h" + +extern "C" { +#include "memgzio.h" +} + +#ifndef _MSC_VER +#define _stricmp strcasecmp +#endif // ! _MSC_VER + +extern int systemColorDepth; +extern int systemRedShift; +extern int systemGreenShift; +extern int systemBlueShift; + +extern u16 systemColorMap16[0x10000]; +extern u32 systemColorMap32[0x10000]; + +static int (ZEXPORT *utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL; +static int (ZEXPORT *utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL; +static int (ZEXPORT *utilGzCloseFunc)(gzFile) = NULL; + +bool utilWritePNGFile(const char *fileName, int w, int h, u8 *pix) +{ +#ifndef NO_PNG + u8 writeBuffer[512 * 3]; + + FILE *fp = fopen(fileName,"wb"); + + if(!fp) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); + return false; + } + + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, + NULL, + NULL); + if(!png_ptr) { + fclose(fp); + return false; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + + if(!info_ptr) { + png_destroy_write_struct(&png_ptr,NULL); + fclose(fp); + return false; + } + + if(setjmp(png_ptr->jmpbuf)) { + png_destroy_write_struct(&png_ptr,NULL); + fclose(fp); + return false; + } + + png_init_io(png_ptr,fp); + + png_set_IHDR(png_ptr, + info_ptr, + w, + h, + 8, + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + png_write_info(png_ptr,info_ptr); + + u8 *b = writeBuffer; + + int sizeX = w; + int sizeY = h; + + switch(systemColorDepth) { + case 16: + { + u16 *p = (u16 *)(pix+(w+2)*2); // skip first black line + for(int y = 0; y < sizeY; y++) { + for(int x = 0; x < sizeX; x++) { + u16 v = *p++; + + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B + } + p++; // skip black pixel for filters + p++; // skip black pixel for filters + png_write_row(png_ptr,writeBuffer); + + b = writeBuffer; + } + } + break; + case 24: + { + u8 *pixU8 = (u8 *)pix; + for(int y = 0; y < sizeY; y++) { + for(int x = 0; x < sizeX; x++) { + if(systemRedShift < systemBlueShift) { + *b++ = *pixU8++; // R + *b++ = *pixU8++; // G + *b++ = *pixU8++; // B + } else { + int blue = *pixU8++; + int green = *pixU8++; + int red = *pixU8++; + + *b++ = red; + *b++ = green; + *b++ = blue; + } + } + png_write_row(png_ptr,writeBuffer); + + b = writeBuffer; + } + } + break; + case 32: + { + u32 *pixU32 = (u32 *)(pix+4*(w+1)); + for(int y = 0; y < sizeY; y++) { + for(int x = 0; x < sizeX; x++) { + u32 v = *pixU32++; + + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B + } + pixU32++; + + png_write_row(png_ptr,writeBuffer); + + b = writeBuffer; + } + } + break; + } + + png_write_end(png_ptr, info_ptr); + + png_destroy_write_struct(&png_ptr, &info_ptr); + + fclose(fp); + + return true; +#else + return false; +#endif +} + +void utilPutDword(u8 *p, u32 value) +{ + *p++ = value & 255; + *p++ = (value >> 8) & 255; + *p++ = (value >> 16) & 255; + *p = (value >> 24) & 255; +} + +void utilPutWord(u8 *p, u16 value) +{ + *p++ = value & 255; + *p = (value >> 8) & 255; +} + +bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix) +{ + u8 writeBuffer[512 * 3]; + + FILE *fp = fopen(fileName,"wb"); + + if(!fp) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); + return false; + } + + struct { + u8 ident[2]; + u8 filesize[4]; + u8 reserved[4]; + u8 dataoffset[4]; + u8 headersize[4]; + u8 width[4]; + u8 height[4]; + u8 planes[2]; + u8 bitsperpixel[2]; + u8 compression[4]; + u8 datasize[4]; + u8 hres[4]; + u8 vres[4]; + u8 colors[4]; + u8 importantcolors[4]; + // u8 pad[2]; + } bmpheader; + memset(&bmpheader, 0, sizeof(bmpheader)); + + bmpheader.ident[0] = 'B'; + bmpheader.ident[1] = 'M'; + + u32 fsz = sizeof(bmpheader) + w*h*3; + utilPutDword(bmpheader.filesize, fsz); + utilPutDword(bmpheader.dataoffset, 0x36); + utilPutDword(bmpheader.headersize, 0x28); + utilPutDword(bmpheader.width, w); + utilPutDword(bmpheader.height, h); + utilPutDword(bmpheader.planes, 1); + utilPutDword(bmpheader.bitsperpixel, 24); + utilPutDword(bmpheader.datasize, 3*w*h); + + fwrite(&bmpheader, 1, sizeof(bmpheader), fp); + + u8 *b = writeBuffer; + + int sizeX = w; + int sizeY = h; + + switch(systemColorDepth) { + case 16: + { + u16 *p = (u16 *)(pix+(w+2)*(h)*2); // skip first black line + for(int y = 0; y < sizeY; y++) { + for(int x = 0; x < sizeX; x++) { + u16 v = *p++; + + *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + } + p++; // skip black pixel for filters + p++; // skip black pixel for filters + p -= 2*(w+2); + fwrite(writeBuffer, 1, 3*w, fp); + + b = writeBuffer; + } + } + break; + case 24: + { + u8 *pixU8 = (u8 *)pix+3*w*(h-1); + for(int y = 0; y < sizeY; y++) { + for(int x = 0; x < sizeX; x++) { + if(systemRedShift > systemBlueShift) { + *b++ = *pixU8++; // B + *b++ = *pixU8++; // G + *b++ = *pixU8++; // R + } else { + int red = *pixU8++; + int green = *pixU8++; + int blue = *pixU8++; + + *b++ = blue; + *b++ = green; + *b++ = red; + } + } + pixU8 -= 2*3*w; + fwrite(writeBuffer, 1, 3*w, fp); + + b = writeBuffer; + } + } + break; + case 32: + { + u32 *pixU32 = (u32 *)(pix+4*(w+1)*(h)); + for(int y = 0; y < sizeY; y++) { + for(int x = 0; x < sizeX; x++) { + u32 v = *pixU32++; + + *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + } + pixU32++; + pixU32 -= 2*(w+1); + + fwrite(writeBuffer, 1, 3*w, fp); + + b = writeBuffer; + } + } + break; + } + + fclose(fp); + + return true; +} + +static int utilReadInt2(FILE *f) +{ + int res = 0; + int c = fgetc(f); + if(c == EOF) + return -1; + res = c; + c = fgetc(f); + if(c == EOF) + return -1; + return c + (res<<8); +} + +static int utilReadInt3(FILE *f) +{ + int res = 0; + int c = fgetc(f); + if(c == EOF) + return -1; + res = c; + c = fgetc(f); + if(c == EOF) + return -1; + res = c + (res<<8); + c = fgetc(f); + if(c == EOF) + return -1; + return c + (res<<8); +} + +void utilApplyIPS(const char *ips, u8 **r, int *s) +{ + // from the IPS spec at http://zerosoft.zophar.net/ips.htm + FILE *f = fopen(ips, "rb"); + if(!f) + return; + u8 *rom = *r; + int size = *s; + if(fgetc(f) == 'P' && + fgetc(f) == 'A' && + fgetc(f) == 'T' && + fgetc(f) == 'C' && + fgetc(f) == 'H') { + int b; + int offset; + int len; + for(;;) { + // read offset + offset = utilReadInt3(f); + // if offset == EOF, end of patch + if(offset == 0x454f46) + break; + // read length + len = utilReadInt2(f); + if(!len) { + // len == 0, RLE block + len = utilReadInt2(f); + // byte to fill + int c = fgetc(f); + if(c == -1) + break; + b = (u8)c; + } else + b= -1; + // check if we need to reallocate our ROM + if((offset + len) >= size) { + size *= 2; + rom = (u8 *)realloc(rom, size); + *r = rom; + *s = size; + } + if(b == -1) { + // normal block, just read the data + if(fread(&rom[offset], 1, len, f) != (size_t)len) + break; + } else { + // fill the region with the given byte + while(len--) { + rom[offset++] = b; + } + } + } + } + // close the file + fclose(f); +} + +extern bool cpuIsMultiBoot; + +bool utilIsGBAImage(const char * file) +{ + cpuIsMultiBoot = false; + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".gba") == 0) + return true; + if(_stricmp(p, ".agb") == 0) + return true; + if(_stricmp(p, ".bin") == 0) + return true; + if(_stricmp(p, ".elf") == 0) + return true; + if(_stricmp(p, ".mb") == 0) { + cpuIsMultiBoot = true; + return true; + } + } + } + + return false; +} + +bool utilIsGBImage(const char * file) +{ + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".gb") == 0) + return true; + if(_stricmp(p, ".gbc") == 0) + return true; + if(_stricmp(p, ".cgb") == 0) + return true; + if(_stricmp(p, ".sgb") == 0) + return true; + } + } + + return false; +} + +bool utilIsGzipFile(const char *file) +{ + if(strlen(file) > 3) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".gz") == 0) + return true; + if(_stricmp(p, ".z") == 0) + return true; + } + } + + return false; +} + +// strip .gz or .z off end +void utilStripDoubleExtension(const char *file, char *buffer) +{ + if(buffer != file) // allows conversion in place + strcpy(buffer, file); + + if(utilIsGzipFile(file)) { + char *p = strrchr(buffer, '.'); + + if(p) + *p = 0; + } +} + +// Opens and scans archive using accept(). Returns File_Extractor if found. +// If error or not found, displays message and returns NULL. +static File_Extractor* scan_arc(const char *file, bool (*accept)(const char *), + char (&buffer) [2048] ) +{ + fex_err_t err; + File_Extractor* fe = fex_open( file, &err ); + if(!fe) + { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s: %s"), file, err); + return NULL; + } + + // Scan filenames + bool found=false; + while(!fex_done(fe)) { + strncpy(buffer,fex_name(fe),sizeof buffer); + buffer [sizeof buffer-1] = '\0'; + + utilStripDoubleExtension(buffer, buffer); + + if(accept(buffer)) { + found = true; + break; + } + + fex_err_t err = fex_next(fe); + if(err) { + systemMessage(MSG_BAD_ZIP_FILE, N_("Cannot read archive %s: %s"), file, err); + fex_close(fe); + return NULL; + } + } + + if(!found) { + systemMessage(MSG_NO_IMAGE_ON_ZIP, + N_("No image found in file %s"), file); + fex_close(fe); + return NULL; + } + return fe; +} + +static bool utilIsImage(const char *file) +{ + return utilIsGBAImage(file) || utilIsGBImage(file); +} + +IMAGE_TYPE utilFindType(const char *file) +{ + char buffer [2048]; + if ( !utilIsImage( file ) ) // TODO: utilIsArchive() instead? + { + File_Extractor* fe = scan_arc(file,utilIsImage,buffer); + if(!fe) + return IMAGE_UNKNOWN; + fex_close(fe); + file = buffer; + } + + return utilIsGBAImage(file) ? IMAGE_GBA : IMAGE_GB; +} + +static int utilGetSize(int size) +{ + int res = 1; + while(res < size) + res <<= 1; + return res; +} + +u8 *utilLoad(const char *file, + bool (*accept)(const char *), + u8 *data, + int &size) +{ + // find image file + char buffer [2048]; + File_Extractor *fe = scan_arc(file,accept,buffer); + if(!fe) + return NULL; + + // Allocate space for image + int fileSize = fex_size(fe); + if(size == 0) + size = fileSize; + + u8 *image = data; + + if(image == NULL) { + // allocate buffer memory if none was passed to the function + image = (u8 *)malloc(utilGetSize(size)); + if(image == NULL) { + fex_close(fe); + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "data"); + return NULL; + } + size = fileSize; + } + + // Read image + int read = fileSize <= size ? fileSize : size; // do not read beyond file + fex_err_t err = fex_read_once(fe, image, read); + fex_close(fe); + if(err) { + systemMessage(MSG_ERROR_READING_IMAGE, + N_("Error reading image from %s: %s"), buffer, err); + if(data == NULL) + free(image); + return NULL; + } + + size = fileSize; + + return image; +} + +void utilWriteInt(gzFile gzFile, int i) +{ + utilGzWrite(gzFile, &i, sizeof(int)); +} + +int utilReadInt(gzFile gzFile) +{ + int i = 0; + utilGzRead(gzFile, &i, sizeof(int)); + return i; +} + +void utilReadData(gzFile gzFile, variable_desc* data) +{ + while(data->address) { + utilGzRead(gzFile, data->address, data->size); + data++; + } +} + +void utilWriteData(gzFile gzFile, variable_desc *data) +{ + while(data->address) { + utilGzWrite(gzFile, data->address, data->size); + data++; + } +} + +gzFile utilGzOpen(const char *file, const char *mode) +{ + utilGzWriteFunc = (int (ZEXPORT *)(void *,void * const, unsigned int))gzwrite; + utilGzReadFunc = gzread; + utilGzCloseFunc = gzclose; + + return gzopen(file, mode); +} + +gzFile utilMemGzOpen(char *memory, int available, const char *mode) +{ + utilGzWriteFunc = memgzwrite; + utilGzReadFunc = memgzread; + utilGzCloseFunc = memgzclose; + + return memgzopen(memory, available, mode); +} + +int utilGzWrite(gzFile file, const voidp buffer, unsigned int len) +{ + return utilGzWriteFunc(file, buffer, len); +} + +int utilGzRead(gzFile file, voidp buffer, unsigned int len) +{ + return utilGzReadFunc(file, buffer, len); +} + +int utilGzClose(gzFile file) +{ + return utilGzCloseFunc(file); +} + +long utilGzMemTell(gzFile file) +{ + return memtell(file); +} + +void utilGBAFindSave(const u8 *data, const int size) +{ + u32 *p = (u32 *)data; + u32 *end = (u32 *)(data + size); + int saveType = 0; + int flashSize = 0x10000; + bool rtcFound = false; + + while(p < end) { + u32 d = READ32LE(p); + + if(d == 0x52504545) { + if(memcmp(p, "EEPROM_", 7) == 0) { + if(saveType == 0) + saveType = 3; + } + } else if (d == 0x4D415253) { + if(memcmp(p, "SRAM_", 5) == 0) { + if(saveType == 0) + saveType = 1; + } + } else if (d == 0x53414C46) { + if(memcmp(p, "FLASH1M_", 8) == 0) { + if(saveType == 0) { + saveType = 2; + flashSize = 0x20000; + } + } else if(memcmp(p, "FLASH", 5) == 0) { + if(saveType == 0) { + saveType = 2; + flashSize = 0x10000; + } + } + } else if (d == 0x52494953) { + if(memcmp(p, "SIIRTC_V", 8) == 0) + rtcFound = true; + } + p++; + } + // if no matches found, then set it to NONE + if(saveType == 0) { + saveType = 5; + } + rtcEnable(rtcFound); + cpuSaveType = saveType; + flashSetSize(flashSize); +} + +void utilUpdateSystemColorMaps() +{ + switch(systemColorDepth) { + case 16: + { + for(int i = 0; i < 0x10000; i++) { + systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | + (((i & 0x3e0) >> 5) << systemGreenShift) | + (((i & 0x7c00) >> 10) << systemBlueShift); + } + } + break; + case 24: + case 32: + { + for(int i = 0; i < 0x10000; i++) { + systemColorMap32[i] = ((i & 0x1f) << systemRedShift) | + (((i & 0x3e0) >> 5) << systemGreenShift) | + (((i & 0x7c00) >> 10) << systemBlueShift); + } + } + break; + } +} diff --git a/src/agb/GBA-arm.cpp b/src/agb/GBA-arm.cpp index 7c8f10d0..78743168 100644 --- a/src/agb/GBA-arm.cpp +++ b/src/agb/GBA-arm.cpp @@ -1,2965 +1,2965 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005-2006 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include -#include -#include -#include -#include - -#include "GBA.h" -#include "GBAcpu.h" -#include "GBAinline.h" -#include "../Globals.h" -#include "../EEprom.h" -#include "../Flash.h" -#include "../Sound.h" -#include "../Sram.h" -#include "../bios.h" -#include "../Cheats.h" -#include "../NLS.h" -#include "../elf.h" -#include "../Util.h" -#include "../Port.h" -#include "../System.h" -#include "agbprint.h" -#ifdef PROFILING -#include "prof/prof.h" -#endif - -#ifdef _MSC_VER - // Disable "empty statement" warnings - #pragma warning(disable: 4390) - // Visual C's inline assembler treats "offset" as a reserved word, so we - // tell it otherwise. If you want to use it, write "OFFSET" in capitals. - #define offset offset_ -#endif - -/////////////////////////////////////////////////////////////////////////// - -static int clockTicks; - -static INSN_REGPARM void armUnknownInsn(u32 opcode) -{ -#ifdef GBA_LOGGING - if (systemVerbose & VERBOSE_UNDEFINED) { - log("Undefined ARM instruction %08x at %08x\n", opcode, - armNextPC-4); - } -#endif - CPUUndefinedException(); -} - -#ifdef BKPT_SUPPORT -static INSN_REGPARM void armBreakpoint(u32 opcode) -{ - reg[15].I -= 4; - armNextPC -= 4; - dbgSignal(5, (opcode & 0x0f) | ((opcode>>4) & 0xfff0)); - clockTicks = -1; -} -#endif - - -// Subroutine to count instructions (for debugging/optimizing) -//#define INSN_COUNTER // comment out if you don't want it -#ifdef INSN_COUNTER -static void count(u32 opcode, int cond_res) -{ - static int insncount = 0; // number of insns seen - static int executed = 0; // number of insns executed - static int mergewith[4096]; // map instructions to routines - static int count[4096]; // count of each 12-bit code - int index = ((opcode>>16)&0xFF0) | ((opcode>>4)&0x0F); - static FILE *outfile = NULL; - - if (!insncount) { - for (int i = 0; i < 4096; i++) { - for (int j = 0; j < i; j++) { - if (armInsnTable[i] == armInsnTable[j]) - break; - } - mergewith[i] = j; - } - outfile = fopen("VBA-armcount.txt", "w"); - } - if (cond_res) { - count[mergewith[index]]++; - executed++; - } - insncount++; - if (outfile && insncount%1000000 == 0) { - fprintf(outfile, "Total instructions: %d\n", insncount); - fprintf(outfile, "Instructions executed: %d\n", executed); - for (int i = 0; i < 4096; i++) { - if (count[i]) - fprintf(outfile, "arm%03X: %d\n", i, count[i]); - } - } -} -#endif - -// Common macros ////////////////////////////////////////////////////////// - -#ifdef BKPT_SUPPORT -#define CONSOLE_OUTPUT(a,b) do { \ - if ((opcode == 0xe0000000) && (reg[0].I == 0xC0DED00D)) { \ - dbgOutput((a), (b)); \ -} while (0) -#else -#define CONSOLE_OUTPUT(a,b) /* nothing */ -#endif - -#define NEG(i) ((i) >> 31) -#define POS(i) ((~(i)) >> 31) - -// The following macros are used for optimization; any not defined for a -// particular compiler/CPU combination default to the C core versions. -// -// ALU_INIT_C: Used at the beginning of ALU instructions (AND/EOR/...). -// (ALU_INIT_NC) Can consist of variable declarations, like the C core, -// or the start of a continued assembly block, like the -// x86-optimized version. The _C version is used when the -// carry flag from the shift operation is needed (logical -// operations that set condition codes, like ANDS); the -// _NC version is used when the carry result is ignored. -// VALUE_XXX: Retrieve the second operand's value for an ALU instruction. -// The _C and _NC versions are used the same way as ALU_INIT. -// OP_XXX: ALU operations. XXX is the instruction name. -// ALU_FINISH: Appended to all ALU instructions. Usually empty, but if -// ALU_INIT started a block ALU_FINISH can be used to end it -// (as with the asm(...) statement in the x86 core). -// SETCOND_NONE: Used in multiply instructions in place of SETCOND_MUL -// when the condition codes are not set. Usually empty. -// SETCOND_MUL: Used in multiply instructions to set the condition codes. -// ROR_IMM_MSR: Used to rotate the immediate operand for MSR. -// ROR_OFFSET: Used to rotate the `offset' parameter for LDR and STR -// instructions. -// RRX_OFFSET: Used to rotate (RRX) the `offset' parameter for LDR and -// STR instructions. - -#ifndef C_CORE - -#if 0 // definitions have changed -//#ifdef __POWERPC__ - #define OP_SUBS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define OP_RSBS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subfco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define OP_ADDS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("addco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define OP_ADCS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("mtspr xer, %4\n" \ - "addeo. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value), \ - "r" (C_FLAG << 29) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define OP_SBCS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("mtspr xer, %4\n" \ - "subfeo. %0, %3, %2\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value), \ - "r" (C_FLAG << 29) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define OP_RSCS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("mtspr xer, %4\n" \ - "subfeo. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value), \ - "r" (C_FLAG << 29) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define OP_CMP \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value) \ - ); \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define OP_CMN \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("addco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value) \ - ); \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - -#else // !__POWERPC__ - -// Macros to emit instructions in the format used by the particular compiler. -// We use GNU assembler syntax: "op src, dest" rather than "op dest, src" - -#ifdef __GNUC__ - #define ALU_HEADER asm("mov %%ecx, %%edi; " - #define ALU_TRAILER : "=D" (opcode) : "c" (opcode) : "eax", "ebx", "edx", "esi") - #define EMIT0(op) #op"; " - #define EMIT1(op,arg) #op" "arg"; " - #define EMIT2(op,src,dest) #op" "src", "dest"; " - #define CONST(val) "$"#val - #define VAR(var) "_"#var - #define VARL(var) "_"#var - #define REGREF1(index) "_reg("index")" - #define REGREF2(index,scale) "_reg(,"index","#scale")" - #define LABEL(n) #n": " - #define LABELREF(n,dir) #n#dir - #define al "%%al" - #define ah "%%ah" - #define eax "%%eax" - #define bl "%%bl" - #define bh "%%bh" - #define ebx "%%ebx" - #define cl "%%cl" - #define ch "%%ch" - #define ecx "%%ecx" - #define dl "%%dl" - #define dh "%%dh" - #define edx "%%edx" - #define esp "%%esp" - #define ebp "%%ebp" - #define esi "%%esi" - #define edi "%%edi" - #define movzx movzb -#else - #define ALU_HEADER __asm { __asm mov ecx, opcode - #define ALU_TRAILER } - #define EMIT0(op) __asm op - #define EMIT1(op,arg) __asm op arg - #define EMIT2(op,src,dest) __asm op dest, src - #define CONST(val) val - #define VAR(var) var - #define VARL(var) dword ptr var - #define REGREF1(index) reg[index] - #define REGREF2(index,scale) reg[index*scale] - #define LABEL(n) __asm l##n: - #define LABELREF(n,dir) l##n -#endif - -//X//#ifndef _MSC_VER -// ALU op register usage: -// EAX -> 2nd operand value, result (RSB/RSC) -// EBX -> C_OUT (carry flag from shift/rotate) -// ECX -> opcode (input), shift/rotate count -// EDX -> Rn (base) value, result (all except RSB/RSC) -// ESI -> Rd (destination) index * 4 - -// Helper macros for loading value / shift count -#define VALUE_LOAD_IMM \ - EMIT2(and, CONST(0x0F), eax) \ - EMIT2(mov, REGREF2(eax,4), eax) \ - EMIT2(shr, CONST(7), ecx) \ - EMIT2(and, CONST(0x1F), ecx) -#define VALUE_LOAD_REG \ - EMIT2(and, CONST(0x0F), eax) \ - EMIT2(mov, REGREF2(eax,4), eax) \ - EMIT2(movzx, ch, ecx) \ - EMIT2(and, CONST(0x0F), ecx) \ - EMIT2(mov, REGREF2(ecx,4), ecx) - -// Helper macros for setting flags -#define SETCOND_LOGICAL \ - EMIT1(sets, VAR(N_FLAG)) \ - EMIT1(setz, VAR(Z_FLAG)) \ - EMIT2(mov, bl, VAR(C_FLAG)) -#define SETCOND_ADD \ - EMIT1(sets, VAR(N_FLAG)) \ - EMIT1(setz, VAR(Z_FLAG)) \ - EMIT1(seto, VAR(V_FLAG)) \ - EMIT1(setc, VAR(C_FLAG)) -#define SETCOND_SUB \ - EMIT1(sets, VAR(N_FLAG)) \ - EMIT1(setz, VAR(Z_FLAG)) \ - EMIT1(seto, VAR(V_FLAG)) \ - EMIT1(setnc, VAR(C_FLAG)) - -// ALU initialization -#define ALU_INIT(LOAD_C_FLAG) \ - ALU_HEADER \ - LOAD_C_FLAG \ - EMIT2(mov, ecx, edx) \ - EMIT2(shr, CONST(14), edx) \ - EMIT2(mov, ecx, eax) \ - EMIT2(mov, ecx, esi) \ - EMIT2(shr, CONST(10), esi) \ - EMIT2(and, CONST(0x3C), edx) \ - EMIT2(mov, REGREF1(edx), edx) \ - EMIT2(and, CONST(0x3C), esi) - -#define LOAD_C_FLAG_YES EMIT2(mov, VAR(C_FLAG), bl) -#define LOAD_C_FLAG_NO /*nothing*/ -#define ALU_INIT_C ALU_INIT(LOAD_C_FLAG_YES) -#define ALU_INIT_NC ALU_INIT(LOAD_C_FLAG_NO) - -// Macros to load the value operand for an ALU op; these all set N/Z -// according to the value - -// OP Rd,Rb,Rm LSL # -#define VALUE_LSL_IMM_C \ - VALUE_LOAD_IMM \ - EMIT1(jnz, LABELREF(1,f)) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(shl, cl, eax) \ - EMIT1(setc, bl) \ - LABEL(0) -#define VALUE_LSL_IMM_NC \ - VALUE_LOAD_IMM \ - EMIT2(shl, cl, eax) - -// OP Rd,Rb,Rm LSL Rs -#define VALUE_LSL_REG_C \ - VALUE_LOAD_REG \ - EMIT2(test, cl, cl) \ - EMIT1(jz, LABELREF(0,f)) \ - EMIT2(cmp, CONST(0x20), cl) \ - EMIT1(je, LABELREF(1,f)) \ - EMIT1(ja, LABELREF(2,f)) \ - EMIT2(shl, cl, eax) \ - EMIT1(setc, bl) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(test, CONST(1), al) \ - EMIT1(setnz, bl) \ - EMIT2(xor, eax, eax) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(2) \ - EMIT2(xor, ebx, ebx) \ - EMIT2(xor, eax, eax) \ - LABEL(0) -#define VALUE_LSL_REG_NC \ - VALUE_LOAD_REG \ - EMIT2(cmp, CONST(0x20), cl) \ - EMIT1(jae, LABELREF(1,f)) \ - EMIT2(shl, cl, eax) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(xor, eax, eax) \ - LABEL(0) - -// OP Rd,Rb,Rm LSR # -#define VALUE_LSR_IMM_C \ - VALUE_LOAD_IMM \ - EMIT1(jz, LABELREF(1,f)) \ - EMIT2(shr, cl, eax) \ - EMIT1(setc, bl) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(test, eax, eax) \ - EMIT1(sets, bl) \ - EMIT2(xor, eax, eax) \ - LABEL(0) -#define VALUE_LSR_IMM_NC \ - VALUE_LOAD_IMM \ - EMIT1(jz, LABELREF(1,f)) \ - EMIT2(shr, cl, eax) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(xor, eax, eax) \ - LABEL(0) - -// OP Rd,Rb,Rm LSR Rs -#define VALUE_LSR_REG_C \ - VALUE_LOAD_REG \ - EMIT2(test, cl, cl) \ - EMIT1(jz, LABELREF(0,f)) \ - EMIT2(cmp, CONST(0x20), cl) \ - EMIT1(je, LABELREF(1,f)) \ - EMIT1(ja, LABELREF(2,f)) \ - EMIT2(shr, cl, eax) \ - EMIT1(setc, bl) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(test, eax, eax) \ - EMIT1(sets, bl) \ - EMIT2(xor, eax, eax) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(2) \ - EMIT2(xor, ebx, ebx) \ - EMIT2(xor, eax, eax) \ - LABEL(0) -#define VALUE_LSR_REG_NC \ - VALUE_LOAD_REG \ - EMIT2(cmp, CONST(0x20), cl) \ - EMIT1(jae, LABELREF(1,f)) \ - EMIT2(shr, cl, eax) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(xor, eax, eax) \ - LABEL(0) - -// OP Rd,Rb,Rm ASR # -#define VALUE_ASR_IMM_C \ - VALUE_LOAD_IMM \ - EMIT1(jz, LABELREF(1,f)) \ - EMIT2(sar, cl, eax) \ - EMIT1(setc, bl) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(sar, CONST(31), eax) \ - EMIT1(sets, bl) \ - LABEL(0) -#define VALUE_ASR_IMM_NC \ - VALUE_LOAD_IMM \ - EMIT1(jz, LABELREF(1,f)) \ - EMIT2(sar, cl, eax) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(sar, CONST(31), eax) \ - LABEL(0) - -// OP Rd,Rb,Rm ASR Rs -#define VALUE_ASR_REG_C \ - VALUE_LOAD_REG \ - EMIT2(test, cl, cl) \ - EMIT1(jz, LABELREF(0,f)) \ - EMIT2(cmp, CONST(0x20), cl) \ - EMIT1(jae, LABELREF(1,f)) \ - EMIT2(sar, cl, eax) \ - EMIT1(setc, bl) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(sar, CONST(31), eax) \ - EMIT1(sets, bl) \ - LABEL(0) -#define VALUE_ASR_REG_NC \ - VALUE_LOAD_REG \ - EMIT2(cmp, CONST(0x20), cl) \ - EMIT1(jae, LABELREF(1,f)) \ - EMIT2(sar, cl, eax) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(sar, CONST(31), eax) \ - LABEL(0) - -// OP Rd,Rb,Rm ROR # -#define VALUE_ROR_IMM_C \ - VALUE_LOAD_IMM \ - EMIT1(jz, LABELREF(1,f)) \ - EMIT2(ror, cl, eax) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(bt, CONST(0), ebx) \ - EMIT2(rcr, CONST(1), eax) \ - LABEL(0) \ - EMIT1(setc, bl) -#define VALUE_ROR_IMM_NC \ - VALUE_LOAD_IMM \ - EMIT1(jz, LABELREF(1,f)) \ - EMIT2(ror, cl, eax) \ - EMIT1(jmp, LABELREF(0,f)) \ - LABEL(1) \ - EMIT2(bt, CONST(0), VARL(C_FLAG)) \ - EMIT2(rcr, CONST(1), eax) \ - LABEL(0) - -// OP Rd,Rb,Rm ROR Rs -#define VALUE_ROR_REG_C \ - VALUE_LOAD_REG \ - EMIT2(bt, CONST(0), ebx) \ - EMIT2(ror, cl, eax) \ - EMIT1(setc, bl) -#define VALUE_ROR_REG_NC \ - VALUE_LOAD_REG \ - EMIT2(ror, cl, eax) - -// OP Rd,Rb,# ROR # -#define VALUE_IMM_C \ - EMIT2(movzx, ch, ecx) \ - EMIT2(add, ecx, ecx) \ - EMIT2(movzx, al, eax) \ - EMIT2(bt, CONST(0), ebx) \ - EMIT2(ror, cl, eax) \ - EMIT1(setc, bl) -#define VALUE_IMM_NC \ - EMIT2(movzx, ch, ecx) \ - EMIT2(add, ecx, ecx) \ - EMIT2(movzx, al, eax) \ - EMIT2(ror, cl, eax) - -// Macros to perform ALU ops - -// Set condition codes iff the destination register is not R15 (PC) -#define CHECK_PC(OP, SETCOND) \ - EMIT2(cmp, CONST(0x3C), esi) \ - EMIT1(je, LABELREF(8,f)) \ - OP SETCOND \ - EMIT1(jmp, LABELREF(9,f)) \ - LABEL(8) \ - OP \ - LABEL(9) - -#define OP_AND \ - EMIT2(and, eax, edx) \ - EMIT2(mov, edx, REGREF1(esi)) -#define OP_ANDS CHECK_PC(OP_AND, SETCOND_LOGICAL) -#define OP_EOR \ - EMIT2(xor, eax, edx) \ - EMIT2(mov, edx, REGREF1(esi)) -#define OP_EORS CHECK_PC(OP_EOR, SETCOND_LOGICAL) -#define OP_SUB \ - EMIT2(sub, eax, edx) \ - EMIT2(mov, edx, REGREF1(esi)) -#define OP_SUBS CHECK_PC(OP_SUB, SETCOND_SUB) -#define OP_RSB \ - EMIT2(sub, edx, eax) \ - EMIT2(mov, eax, REGREF1(esi)) -#define OP_RSBS CHECK_PC(OP_RSB, SETCOND_SUB) -#define OP_ADD \ - EMIT2(add, eax, edx) \ - EMIT2(mov, edx, REGREF1(esi)) -#define OP_ADDS CHECK_PC(OP_ADD, SETCOND_ADD) -#define OP_ADC \ - EMIT2(bt, CONST(0), VARL(C_FLAG)) \ - EMIT2(adc, eax, edx) \ - EMIT2(mov, edx, REGREF1(esi)) -#define OP_ADCS CHECK_PC(OP_ADC, SETCOND_ADD) -#define OP_SBC \ - EMIT2(bt, CONST(0), VARL(C_FLAG)) \ - EMIT0(cmc) \ - EMIT2(sbb, eax, edx) \ - EMIT2(mov, edx, REGREF1(esi)) -#define OP_SBCS CHECK_PC(OP_SBC, SETCOND_SUB) -#define OP_RSC \ - EMIT2(bt, CONST(0), VARL(C_FLAG)) \ - EMIT0(cmc) \ - EMIT2(sbb, edx, eax) \ - EMIT2(mov, eax, REGREF1(esi)) -#define OP_RSCS CHECK_PC(OP_RSC, SETCOND_SUB) -#define OP_TST \ - EMIT2(and, eax, edx) \ - SETCOND_LOGICAL -#define OP_TEQ \ - EMIT2(xor, eax, edx) \ - SETCOND_LOGICAL -#define OP_CMP \ - EMIT2(sub, eax, edx) \ - SETCOND_SUB -#define OP_CMN \ - EMIT2(add, eax, edx) \ - SETCOND_ADD -#define OP_ORR \ - EMIT2(or, eax, edx) \ - EMIT2(mov, edx, REGREF1(esi)) -#define OP_ORRS CHECK_PC(OP_ORR, SETCOND_LOGICAL) -#define OP_MOV \ - EMIT2(mov, eax, REGREF1(esi)) -#define OP_MOVS CHECK_PC(EMIT2(test,eax,eax) EMIT2(mov,eax,REGREF1(esi)), SETCOND_LOGICAL) -#define OP_BIC \ - EMIT1(not, eax) \ - EMIT2(and, eax, edx) \ - EMIT2(mov, edx, REGREF1(esi)) -#define OP_BICS CHECK_PC(OP_BIC, SETCOND_LOGICAL) -#define OP_MVN \ - EMIT1(not, eax) \ - EMIT2(mov, eax, REGREF1(esi)) -#define OP_MVNS CHECK_PC(OP_MVN, SETCOND_LOGICAL) - -// ALU cleanup macro -#define ALU_FINISH ALU_TRAILER - -// End of ALU macros -//X//#endif //_MSC_VER - -#ifdef __GNUC__ - -#define ROR_IMM_MSR \ - asm ("ror %%cl, %%eax;" \ - : "=a" (value) \ - : "a" (opcode & 0xFF), "c" (shift)); - -#define ROR_OFFSET \ - asm("ror %%cl, %0" \ - : "=r" (offset) \ - : "0" (offset), "c" (shift)); - -#define RRX_OFFSET \ - asm("btl $0, _C_FLAG;" \ - "rcr $1, %0" \ - : "=r" (offset) \ - : "0" (offset)); - -#else // !__GNUC__, i.e. Visual C++ - -#define ROR_IMM_MSR \ - __asm { \ - __asm mov ecx, shift \ - __asm ror value, cl \ - } - - -#define ROR_OFFSET \ - __asm { \ - __asm mov ecx, shift \ - __asm ror offset, cl \ - } - -#define RRX_OFFSET \ - __asm { \ - __asm bt dword ptr C_FLAG, 0 \ - __asm rcr offset, 1 \ - } - -#endif // !__GNUC__ - -#endif // !__POWERPC__ -#endif // !C_CORE - -// C core - -#define C_SETCOND_LOGICAL \ - N_FLAG = ((s32)res < 0) ? true : false; \ - Z_FLAG = (res == 0) ? true : false; \ - C_FLAG = C_OUT; -#define C_SETCOND_ADD \ - N_FLAG = ((s32)res < 0) ? true : false; \ - Z_FLAG = (res == 0) ? true : false; \ - V_FLAG = ((NEG(lhs) & NEG(rhs) & POS(res)) | \ - (POS(lhs) & POS(rhs) & NEG(res))) ? true : false;\ - C_FLAG = ((NEG(lhs) & NEG(rhs)) | \ - (NEG(lhs) & POS(res)) | \ - (NEG(rhs) & POS(res))) ? true : false; -#define C_SETCOND_SUB \ - N_FLAG = ((s32)res < 0) ? true : false; \ - Z_FLAG = (res == 0) ? true : false; \ - V_FLAG = ((NEG(lhs) & POS(rhs) & POS(res)) | \ - (POS(lhs) & NEG(rhs) & NEG(res))) ? true : false;\ - C_FLAG = ((NEG(lhs) & POS(rhs)) | \ - (NEG(lhs) & POS(res)) | \ - (POS(rhs) & POS(res))) ? true : false; - -#ifndef ALU_INIT_C - #define ALU_INIT_C \ - int dest = (opcode>>12) & 15; \ - bool C_OUT = C_FLAG; \ - u32 value; -#endif -// OP Rd,Rb,Rm LSL # -#ifndef VALUE_LSL_IMM_C - #define VALUE_LSL_IMM_C \ - unsigned int shift = (opcode >> 7) & 0x1F; \ - if (LIKELY(!shift)) { /* LSL #0 most common? */ \ - value = reg[opcode & 0x0F].I; \ - } else { \ - u32 v = reg[opcode & 0x0F].I; \ - C_OUT = (v >> (32 - shift)) & 1 ? true : false; \ - value = v << shift; \ - } -#endif -// OP Rd,Rb,Rm LSL Rs -#ifndef VALUE_LSL_REG_C - #define VALUE_LSL_REG_C \ - unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ - if (LIKELY(shift)) { \ - if (shift == 32) { \ - value = 0; \ - C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false);\ - } else if (LIKELY(shift < 32)) { \ - u32 v = reg[opcode & 0x0F].I; \ - C_OUT = (v >> (32 - shift)) & 1 ? true : false;\ - value = v << shift; \ - } else { \ - value = 0; \ - C_OUT = false; \ - } \ - } else { \ - value = reg[opcode & 0x0F].I; \ - } -#endif -// OP Rd,Rb,Rm LSR # -#ifndef VALUE_LSR_IMM_C - #define VALUE_LSR_IMM_C \ - unsigned int shift = (opcode >> 7) & 0x1F; \ - if (LIKELY(shift)) { \ - u32 v = reg[opcode & 0x0F].I; \ - C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ - value = v >> shift; \ - } else { \ - value = 0; \ - C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false;\ - } -#endif -// OP Rd,Rb,Rm LSR Rs -#ifndef VALUE_LSR_REG_C - #define VALUE_LSR_REG_C \ - unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ - if (LIKELY(shift)) { \ - if (shift == 32) { \ - value = 0; \ - C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false);\ - } else if (LIKELY(shift < 32)) { \ - u32 v = reg[opcode & 0x0F].I; \ - C_OUT = (v >> (shift - 1)) & 1 ? true : false;\ - value = v >> shift; \ - } else { \ - value = 0; \ - C_OUT = false; \ - } \ - } else { \ - value = reg[opcode & 0x0F].I; \ - } -#endif -// OP Rd,Rb,Rm ASR # -#ifndef VALUE_ASR_IMM_C - #define VALUE_ASR_IMM_C \ - unsigned int shift = (opcode >> 7) & 0x1F; \ - if (LIKELY(shift)) { \ - /* VC++ BUG: u32 v; (s32)v>>n is optimized to shr! */ \ - s32 v = reg[opcode & 0x0F].I; \ - C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\ - value = v >> (int)shift; \ - } else { \ - if (reg[opcode & 0x0F].I & 0x80000000) { \ - value = 0xFFFFFFFF; \ - C_OUT = true; \ - } else { \ - value = 0; \ - C_OUT = false; \ - } \ - } -#endif -// OP Rd,Rb,Rm ASR Rs -#ifndef VALUE_ASR_REG_C - #define VALUE_ASR_REG_C \ - unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ - if (LIKELY(shift < 32)) { \ - if (LIKELY(shift)) { \ - s32 v = reg[opcode & 0x0F].I; \ - C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\ - value = v >> (int)shift; \ - } else { \ - value = reg[opcode & 0x0F].I; \ - } \ - } else { \ - if (reg[opcode & 0x0F].I & 0x80000000) { \ - value = 0xFFFFFFFF; \ - C_OUT = true; \ - } else { \ - value = 0; \ - C_OUT = false; \ - } \ - } -#endif -// OP Rd,Rb,Rm ROR # -#ifndef VALUE_ROR_IMM_C - #define VALUE_ROR_IMM_C \ - unsigned int shift = (opcode >> 7) & 0x1F; \ - if (LIKELY(shift)) { \ - u32 v = reg[opcode & 0x0F].I; \ - C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ - value = ((v << (32 - shift)) | \ - (v >> shift)); \ - } else { \ - u32 v = reg[opcode & 0x0F].I; \ - C_OUT = (v & 1) ? true : false; \ - value = ((v >> 1) | \ - (C_FLAG << 31)); \ - } -#endif -// OP Rd,Rb,Rm ROR Rs -#ifndef VALUE_ROR_REG_C - #define VALUE_ROR_REG_C \ - unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ - if (LIKELY(shift & 0x1F)) { \ - u32 v = reg[opcode & 0x0F].I; \ - C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ - value = ((v << (32 - shift)) | \ - (v >> shift)); \ - } else { \ - value = reg[opcode & 0x0F].I; \ - if (shift) \ - C_OUT = (value & 0x80000000 ? true : false);\ - } -#endif -// OP Rd,Rb,# ROR # -#ifndef VALUE_IMM_C - #define VALUE_IMM_C \ - int shift = (opcode & 0xF00) >> 7; \ - if (UNLIKELY(shift)) { \ - u32 v = opcode & 0xFF; \ - C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ - value = ((v << (32 - shift)) | \ - (v >> shift)); \ - } else { \ - value = opcode & 0xFF; \ - } -#endif - -// Make the non-carry versions default to the carry versions -// (this is fine for C--the compiler will optimize the dead code out) -#ifndef ALU_INIT_NC - #define ALU_INIT_NC ALU_INIT_C -#endif -#ifndef VALUE_LSL_IMM_NC - #define VALUE_LSL_IMM_NC VALUE_LSL_IMM_C -#endif -#ifndef VALUE_LSL_REG_NC - #define VALUE_LSL_REG_NC VALUE_LSL_REG_C -#endif -#ifndef VALUE_LSR_IMM_NC - #define VALUE_LSR_IMM_NC VALUE_LSR_IMM_C -#endif -#ifndef VALUE_LSR_REG_NC - #define VALUE_LSR_REG_NC VALUE_LSR_REG_C -#endif -#ifndef VALUE_ASR_IMM_NC - #define VALUE_ASR_IMM_NC VALUE_ASR_IMM_C -#endif -#ifndef VALUE_ASR_REG_NC - #define VALUE_ASR_REG_NC VALUE_ASR_REG_C -#endif -#ifndef VALUE_ROR_IMM_NC - #define VALUE_ROR_IMM_NC VALUE_ROR_IMM_C -#endif -#ifndef VALUE_ROR_REG_NC - #define VALUE_ROR_REG_NC VALUE_ROR_REG_C -#endif -#ifndef VALUE_IMM_NC - #define VALUE_IMM_NC VALUE_IMM_C -#endif - -#define C_CHECK_PC(SETCOND) if (LIKELY(dest != 15)) { SETCOND } -#ifndef OP_AND - #define OP_AND \ - u32 res = reg[(opcode>>16)&15].I & value; \ - reg[dest].I = res; -#endif -#ifndef OP_ANDS - #define OP_ANDS OP_AND C_CHECK_PC(C_SETCOND_LOGICAL) -#endif -#ifndef OP_EOR - #define OP_EOR \ - u32 res = reg[(opcode>>16)&15].I ^ value; \ - reg[dest].I = res; -#endif -#ifndef OP_EORS - #define OP_EORS OP_EOR C_CHECK_PC(C_SETCOND_LOGICAL) -#endif -#ifndef OP_SUB - #define OP_SUB \ - u32 lhs = reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = lhs - rhs; \ - reg[dest].I = res; -#endif -#ifndef OP_SUBS - #define OP_SUBS OP_SUB C_CHECK_PC(C_SETCOND_SUB) -#endif -#ifndef OP_RSB - #define OP_RSB \ - u32 lhs = reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = rhs - lhs; \ - reg[dest].I = res; -#endif -#ifndef OP_RSBS - #define OP_RSBS OP_RSB C_CHECK_PC(C_SETCOND_SUB) -#endif -#ifndef OP_ADD - #define OP_ADD \ - u32 lhs = reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = lhs + rhs; \ - reg[dest].I = res; -#endif -#ifndef OP_ADDS - #define OP_ADDS OP_ADD C_CHECK_PC(C_SETCOND_ADD) -#endif -#ifndef OP_ADC - #define OP_ADC \ - u32 lhs = reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = lhs + rhs + (u32)C_FLAG; \ - reg[dest].I = res; -#endif -#ifndef OP_ADCS - #define OP_ADCS OP_ADC C_CHECK_PC(C_SETCOND_ADD) -#endif -#ifndef OP_SBC - #define OP_SBC \ - u32 lhs = reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = lhs - rhs - !((u32)C_FLAG); \ - reg[dest].I = res; -#endif -#ifndef OP_SBCS - #define OP_SBCS OP_SBC C_CHECK_PC(C_SETCOND_SUB) -#endif -#ifndef OP_RSC - #define OP_RSC \ - u32 lhs = reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = rhs - lhs - !((u32)C_FLAG); \ - reg[dest].I = res; -#endif -#ifndef OP_RSCS - #define OP_RSCS OP_RSC C_CHECK_PC(C_SETCOND_SUB) -#endif -#ifndef OP_TST - #define OP_TST \ - u32 res = reg[(opcode >> 16) & 0x0F].I & value; \ - C_SETCOND_LOGICAL; -#endif -#ifndef OP_TEQ - #define OP_TEQ \ - u32 res = reg[(opcode >> 16) & 0x0F].I ^ value; \ - C_SETCOND_LOGICAL; -#endif -#ifndef OP_CMP - #define OP_CMP \ - u32 lhs = reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = lhs - rhs; \ - C_SETCOND_SUB; -#endif -#ifndef OP_CMN - #define OP_CMN \ - u32 lhs = reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = lhs + rhs; \ - C_SETCOND_ADD; -#endif -#ifndef OP_ORR - #define OP_ORR \ - u32 res = reg[(opcode >> 16) & 0x0F].I | value; \ - reg[dest].I = res; -#endif -#ifndef OP_ORRS - #define OP_ORRS OP_ORR C_CHECK_PC(C_SETCOND_LOGICAL) -#endif -#ifndef OP_MOV - #define OP_MOV \ - u32 res = value; \ - reg[dest].I = res; -#endif -#ifndef OP_MOVS - #define OP_MOVS OP_MOV C_CHECK_PC(C_SETCOND_LOGICAL) -#endif -#ifndef OP_BIC - #define OP_BIC \ - u32 res = reg[(opcode >> 16) & 0x0F].I & (~value); \ - reg[dest].I = res; -#endif -#ifndef OP_BICS - #define OP_BICS OP_BIC C_CHECK_PC(C_SETCOND_LOGICAL) -#endif -#ifndef OP_MVN - #define OP_MVN \ - u32 res = ~value; \ - reg[dest].I = res; -#endif -#ifndef OP_MVNS - #define OP_MVNS OP_MVN C_CHECK_PC(C_SETCOND_LOGICAL) -#endif - -#ifndef SETCOND_NONE - #define SETCOND_NONE /*nothing*/ -#endif -#ifndef SETCOND_MUL - #define SETCOND_MUL \ - N_FLAG = ((s32)reg[dest].I < 0) ? true : false; \ - Z_FLAG = reg[dest].I ? false : true; -#endif -#ifndef SETCOND_MULL - #define SETCOND_MULL \ - N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\ - Z_FLAG = reg[dest].I || reg[acc].I ? false : true; -#endif - -#ifndef ALU_FINISH - #define ALU_FINISH /*nothing*/ -#endif - -#ifndef ROR_IMM_MSR - #define ROR_IMM_MSR \ - u32 v = opcode & 0xff; \ - value = ((v << (32 - shift)) | (v >> shift)); -#endif -#ifndef ROR_OFFSET - #define ROR_OFFSET \ - offset = ((offset << (32 - shift)) | (offset >> shift)); -#endif -#ifndef RRX_OFFSET - #define RRX_OFFSET \ - offset = ((offset >> 1) | ((int)C_FLAG << 31)); -#endif - -// ALU ops (except multiply) ////////////////////////////////////////////// - -// ALU_INIT: init code (ALU_INIT_C or ALU_INIT_NC) -// GETVALUE: load value and shift/rotate (VALUE_XXX) -// OP: ALU operation (OP_XXX) -// MODECHANGE: MODECHANGE_NO or MODECHANGE_YES -// ISREGSHIFT: 1 for insns of the form ...,Rn LSL/etc Rs; 0 otherwise -// ALU_INIT, GETVALUE, OP, and ALU_FINISH are concatenated in order. -#define ALU_INSN(ALU_INIT, GETVALUE, OP, MODECHANGE, ISREGSHIFT) \ - ALU_INIT GETVALUE OP ALU_FINISH; \ - if (LIKELY((opcode & 0x0000F000) != 0x0000F000)) { \ - clockTicks = 1 + ISREGSHIFT \ - + codeTicksAccessSeq32(armNextPC); \ - } else { \ - MODECHANGE; \ - if (armState) { \ - reg[15].I &= 0xFFFFFFFC; \ - armNextPC = reg[15].I; \ - reg[15].I += 4; \ - ARM_PREFETCH; \ - } else { \ - reg[15].I &= 0xFFFFFFFE; \ - armNextPC = reg[15].I; \ - reg[15].I += 2; \ - THUMB_PREFETCH; \ - } \ - clockTicks = 3 + ISREGSHIFT \ - + codeTicksAccess32(armNextPC) \ - + codeTicksAccessSeq32(armNextPC) \ - + codeTicksAccessSeq32(armNextPC); \ - } - -#define MODECHANGE_NO /*nothing*/ -#define MODECHANGE_YES CPUSwitchMode(reg[17].I & 0x1f, false); - -#define DEFINE_ALU_INSN_C(CODE1, CODE2, OP, MODECHANGE) \ - static INSN_REGPARM void arm##CODE1##0(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSL_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - static INSN_REGPARM void arm##CODE1##1(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSL_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - static INSN_REGPARM void arm##CODE1##2(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - static INSN_REGPARM void arm##CODE1##3(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - static INSN_REGPARM void arm##CODE1##4(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ASR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - static INSN_REGPARM void arm##CODE1##5(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ASR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - static INSN_REGPARM void arm##CODE1##6(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ROR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - static INSN_REGPARM void arm##CODE1##7(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ROR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - static INSN_REGPARM void arm##CODE2##0(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); } -#define DEFINE_ALU_INSN_NC(CODE1, CODE2, OP, MODECHANGE) \ - static INSN_REGPARM void arm##CODE1##0(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSL_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - static INSN_REGPARM void arm##CODE1##1(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSL_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - static INSN_REGPARM void arm##CODE1##2(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - static INSN_REGPARM void arm##CODE1##3(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - static INSN_REGPARM void arm##CODE1##4(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ASR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - static INSN_REGPARM void arm##CODE1##5(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ASR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - static INSN_REGPARM void arm##CODE1##6(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ROR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - static INSN_REGPARM void arm##CODE1##7(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ROR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - static INSN_REGPARM void arm##CODE2##0(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); } - -// AND -DEFINE_ALU_INSN_NC(00, 20, AND, NO) -// ANDS -DEFINE_ALU_INSN_C (01, 21, ANDS, YES) - -// EOR -DEFINE_ALU_INSN_NC(02, 22, EOR, NO) -// EORS -DEFINE_ALU_INSN_C (03, 23, EORS, YES) - -// SUB -DEFINE_ALU_INSN_NC(04, 24, SUB, NO) -// SUBS -DEFINE_ALU_INSN_NC(05, 25, SUBS, YES) - -// RSB -DEFINE_ALU_INSN_NC(06, 26, RSB, NO) -// RSBS -DEFINE_ALU_INSN_NC(07, 27, RSBS, YES) - -// ADD -DEFINE_ALU_INSN_NC(08, 28, ADD, NO) -// ADDS -DEFINE_ALU_INSN_NC(09, 29, ADDS, YES) - -// ADC -DEFINE_ALU_INSN_NC(0A, 2A, ADC, NO) -// ADCS -DEFINE_ALU_INSN_NC(0B, 2B, ADCS, YES) - -// SBC -DEFINE_ALU_INSN_NC(0C, 2C, SBC, NO) -// SBCS -DEFINE_ALU_INSN_NC(0D, 2D, SBCS, YES) - -// RSC -DEFINE_ALU_INSN_NC(0E, 2E, RSC, NO) -// RSCS -DEFINE_ALU_INSN_NC(0F, 2F, RSCS, YES) - -// TST -DEFINE_ALU_INSN_C (11, 31, TST, NO) - -// TEQ -DEFINE_ALU_INSN_C (13, 33, TEQ, NO) - -// CMP -DEFINE_ALU_INSN_NC(15, 35, CMP, NO) - -// CMN -DEFINE_ALU_INSN_NC(17, 37, CMN, NO) - -// ORR -DEFINE_ALU_INSN_NC(18, 38, ORR, NO) -// ORRS -DEFINE_ALU_INSN_C (19, 39, ORRS, YES) - -// MOV -DEFINE_ALU_INSN_NC(1A, 3A, MOV, NO) -// MOVS -DEFINE_ALU_INSN_C (1B, 3B, MOVS, YES) - -// BIC -DEFINE_ALU_INSN_NC(1C, 3C, BIC, NO) -// BICS -DEFINE_ALU_INSN_C (1D, 3D, BICS, YES) - -// MVN -DEFINE_ALU_INSN_NC(1E, 3E, MVN, NO) -// MVNS -DEFINE_ALU_INSN_C (1F, 3F, MVNS, YES) - -// Multiply instructions ////////////////////////////////////////////////// - -// OP: OP_MUL, OP_MLA etc. -// SETCOND: SETCOND_NONE, SETCOND_MUL, or SETCOND_MULL -// CYCLES: base cycle count (1, 2, or 3) -#define MUL_INSN(OP, SETCOND, CYCLES) \ - int mult = (opcode & 0x0F); \ - u32 rs = reg[(opcode >> 8) & 0x0F].I; \ - int acc = (opcode >> 12) & 0x0F; /* or destLo */ \ - int dest = (opcode >> 16) & 0x0F; /* or destHi */ \ - OP; \ - SETCOND; \ - if ((s32)rs < 0) \ - rs = ~rs; \ - if ((rs & 0xFFFFFF00) == 0) \ - clockTicks += 0; \ - else if ((rs & 0xFFFF0000) == 0) \ - clockTicks += 1; \ - else if ((rs & 0xFF000000) == 0) \ - clockTicks += 2; \ - else \ - clockTicks += 3; \ - if (busPrefetchCount == 0) \ - busPrefetchCount = ((busPrefetchCount+1)<> 32); -#define OP_MLAL(SIGN) \ - SIGN##64 res = ((SIGN##64)reg[dest].I<<32 | reg[acc].I)\ - + ((SIGN##64)(SIGN##32)reg[mult].I \ - * (SIGN##64)(SIGN##32)rs); \ - reg[acc].I = (u32)res; \ - reg[dest].I = (u32)(res >> 32); -#define OP_UMULL OP_MULL(u) -#define OP_UMLAL OP_MLAL(u) -#define OP_SMULL OP_MULL(s) -#define OP_SMLAL OP_MLAL(s) - -// MUL Rd, Rm, Rs -static INSN_REGPARM void arm009(u32 opcode) { MUL_INSN(OP_MUL, SETCOND_NONE, 1); } -// MULS Rd, Rm, Rs -static INSN_REGPARM void arm019(u32 opcode) { MUL_INSN(OP_MUL, SETCOND_MUL, 1); } - -// MLA Rd, Rm, Rs, Rn -static INSN_REGPARM void arm029(u32 opcode) { MUL_INSN(OP_MLA, SETCOND_NONE, 2); } -// MLAS Rd, Rm, Rs, Rn -static INSN_REGPARM void arm039(u32 opcode) { MUL_INSN(OP_MLA, SETCOND_MUL, 2); } - -// UMULL RdLo, RdHi, Rn, Rs -static INSN_REGPARM void arm089(u32 opcode) { MUL_INSN(OP_UMULL, SETCOND_NONE, 2); } -// UMULLS RdLo, RdHi, Rn, Rs -static INSN_REGPARM void arm099(u32 opcode) { MUL_INSN(OP_UMULL, SETCOND_MULL, 2); } - -// UMLAL RdLo, RdHi, Rn, Rs -static INSN_REGPARM void arm0A9(u32 opcode) { MUL_INSN(OP_UMLAL, SETCOND_NONE, 3); } -// UMLALS RdLo, RdHi, Rn, Rs -static INSN_REGPARM void arm0B9(u32 opcode) { MUL_INSN(OP_UMLAL, SETCOND_MULL, 3); } - -// SMULL RdLo, RdHi, Rm, Rs -static INSN_REGPARM void arm0C9(u32 opcode) { MUL_INSN(OP_SMULL, SETCOND_NONE, 2); } -// SMULLS RdLo, RdHi, Rm, Rs -static INSN_REGPARM void arm0D9(u32 opcode) { MUL_INSN(OP_SMULL, SETCOND_MULL, 2); } - -// SMLAL RdLo, RdHi, Rm, Rs -static INSN_REGPARM void arm0E9(u32 opcode) { MUL_INSN(OP_SMLAL, SETCOND_NONE, 3); } -// SMLALS RdLo, RdHi, Rm, Rs -static INSN_REGPARM void arm0F9(u32 opcode) { MUL_INSN(OP_SMLAL, SETCOND_MULL, 3); } - -// Misc instructions ////////////////////////////////////////////////////// - -// SWP Rd, Rm, [Rn] -static INSN_REGPARM void arm109(u32 opcode) -{ - u32 address = reg[(opcode >> 16) & 15].I; - u32 temp = CPUReadMemory(address); - CPUWriteMemory(address, reg[opcode&15].I); - reg[(opcode >> 12) & 15].I = temp; - clockTicks = 4 + dataTicksAccess32(address) + dataTicksAccess32(address) - + codeTicksAccess32(armNextPC); -} - -// SWPB Rd, Rm, [Rn] -static INSN_REGPARM void arm149(u32 opcode) -{ - u32 address = reg[(opcode >> 16) & 15].I; - u32 temp = CPUReadByte(address); - CPUWriteByte(address, reg[opcode&15].B.B0); - reg[(opcode>>12)&15].I = temp; - clockTicks = 4 + dataTicksAccess32(address) + dataTicksAccess32(address) - + codeTicksAccess32(armNextPC); -} - -// MRS Rd, CPSR -static INSN_REGPARM void arm100(u32 opcode) -{ - if (LIKELY((opcode & 0x0FFF0FFF) == 0x010F0000)) { - CPUUpdateCPSR(); - reg[(opcode >> 12) & 0x0F].I = reg[16].I; - } else { - armUnknownInsn(opcode); - } -} - -// MRS Rd, SPSR -static INSN_REGPARM void arm140(u32 opcode) -{ - if (LIKELY((opcode & 0x0FFF0FFF) == 0x014F0000)) { - reg[(opcode >> 12) & 0x0F].I = reg[17].I; - } else { - armUnknownInsn(opcode); - } -} - -// MSR CPSR_fields, Rm -static INSN_REGPARM void arm120(u32 opcode) -{ - if (LIKELY((opcode & 0x0FF0FFF0) == 0x0120F000)) { - CPUUpdateCPSR(); - u32 value = reg[opcode & 15].I; - u32 newValue = reg[16].I; - if (armMode > 0x10) { - if (opcode & 0x00010000) - newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF); - if (opcode & 0x00020000) - newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00); - if (opcode & 0x00040000) - newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000); - } - if (opcode & 0x00080000) - newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000); - newValue |= 0x10; - CPUSwitchMode(newValue & 0x1F, false); - reg[16].I = newValue; - CPUUpdateFlags(); - if (!armState) { // this should not be allowed, but it seems to work - THUMB_PREFETCH; - reg[15].I = armNextPC + 2; - } - } else { - armUnknownInsn(opcode); - } -} - -// MSR SPSR_fields, Rm -static INSN_REGPARM void arm160(u32 opcode) -{ - if (LIKELY((opcode & 0x0FF0FFF0) == 0x0160F000)) { - u32 value = reg[opcode & 15].I; - if (armMode > 0x10 && armMode < 0x1F) { - if (opcode & 0x00010000) - reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF); - if (opcode & 0x00020000) - reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00); - if (opcode & 0x00040000) - reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000); - if (opcode & 0x00080000) - reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000); - } - } else { - armUnknownInsn(opcode); - } -} - -// MSR CPSR_fields, # -static INSN_REGPARM void arm320(u32 opcode) -{ - if (LIKELY((opcode & 0x0FF0F000) == 0x0320F000)) { - CPUUpdateCPSR(); - u32 value = opcode & 0xFF; - int shift = (opcode & 0xF00) >> 7; - if (shift) { - ROR_IMM_MSR; - } - u32 newValue = reg[16].I; - if (armMode > 0x10) { - if (opcode & 0x00010000) - newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF); - if (opcode & 0x00020000) - newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00); - if (opcode & 0x00040000) - newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000); - } - if (opcode & 0x00080000) - newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000); - - newValue |= 0x10; - - CPUSwitchMode(newValue & 0x1F, false); - reg[16].I = newValue; - CPUUpdateFlags(); - if (!armState) { // this should not be allowed, but it seems to work - THUMB_PREFETCH; - reg[15].I = armNextPC + 2; - } - } else { - armUnknownInsn(opcode); - } -} - -// MSR SPSR_fields, # -static INSN_REGPARM void arm360(u32 opcode) -{ - if (LIKELY((opcode & 0x0FF0F000) == 0x0360F000)) { - if (armMode > 0x10 && armMode < 0x1F) { - u32 value = opcode & 0xFF; - int shift = (opcode & 0xF00) >> 7; - if (shift) { - ROR_IMM_MSR; - } - if (opcode & 0x00010000) - reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF); - if (opcode & 0x00020000) - reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00); - if (opcode & 0x00040000) - reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000); - if (opcode & 0x00080000) - reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000); - } - } else { - armUnknownInsn(opcode); - } -} - -// BX Rm -static INSN_REGPARM void arm121(u32 opcode) -{ - if (LIKELY((opcode & 0x0FFFFFF0) == 0x012FFF10)) { - int base = opcode & 0x0F; - busPrefetchCount = 0; - armState = reg[base].I & 1 ? false : true; - if (armState) { - reg[15].I = reg[base].I & 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - ARM_PREFETCH; - clockTicks = 3 + codeTicksAccessSeq32(armNextPC) - + codeTicksAccessSeq32(armNextPC) - + codeTicksAccess32(armNextPC); - } else { - reg[15].I = reg[base].I & 0xFFFFFFFE; - armNextPC = reg[15].I; - reg[15].I += 2; - THUMB_PREFETCH; - clockTicks = 3 + codeTicksAccessSeq16(armNextPC) - + codeTicksAccessSeq16(armNextPC) - + codeTicksAccess16(armNextPC); - } - } else { - armUnknownInsn(opcode); - } -} - -// Load/store ///////////////////////////////////////////////////////////// - -#define OFFSET_IMM \ - int offset = opcode & 0xFFF; -#define OFFSET_IMM8 \ - int offset = ((opcode & 0x0F) | ((opcode>>4) & 0xF0)); -#define OFFSET_REG \ - int offset = reg[opcode & 15].I; -#define OFFSET_LSL \ - int offset = reg[opcode & 15].I << ((opcode>>7) & 31); -#define OFFSET_LSR \ - int shift = (opcode >> 7) & 31; \ - int offset = shift ? reg[opcode & 15].I >> shift : 0; -#define OFFSET_ASR \ - int shift = (opcode >> 7) & 31; \ - int offset; \ - if (shift) \ - offset = (int)((s32)reg[opcode & 15].I >> shift);\ - else if (reg[opcode & 15].I & 0x80000000) \ - offset = 0xFFFFFFFF; \ - else \ - offset = 0; -#define OFFSET_ROR \ - int shift = (opcode >> 7) & 31; \ - u32 offset = reg[opcode & 15].I; \ - if (shift) { \ - ROR_OFFSET; \ - } else { \ - RRX_OFFSET; \ - } - -#define ADDRESS_POST (reg[base].I) -#define ADDRESS_PREDEC (reg[base].I - offset) -#define ADDRESS_PREINC (reg[base].I + offset) - -#define OP_STR CPUWriteMemory(address, reg[dest].I) -#define OP_STRH CPUWriteHalfWord(address, reg[dest].W.W0) -#define OP_STRB CPUWriteByte(address, reg[dest].B.B0) -#define OP_LDR reg[dest].I = CPUReadMemory(address) -#define OP_LDRH reg[dest].I = CPUReadHalfWord(address) -#define OP_LDRB reg[dest].I = CPUReadByte(address) -#define OP_LDRSH reg[dest].I = (s16)CPUReadHalfWordSigned(address) -#define OP_LDRSB reg[dest].I = (s8)CPUReadByte(address) - -#define WRITEBACK_NONE /*nothing*/ -#define WRITEBACK_PRE reg[base].I = address -#define WRITEBACK_POSTDEC reg[base].I = address - offset -#define WRITEBACK_POSTINC reg[base].I = address + offset - -#define LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS) \ - if (busPrefetchCount == 0) \ - busPrefetch = busPrefetchEnable; \ - int dest = (opcode >> 12) & 15; \ - int base = (opcode >> 16) & 15; \ - CALC_OFFSET; \ - u32 address = CALC_ADDRESS; - -#define STR(CALC_OFFSET, CALC_ADDRESS, STORE_DATA, WRITEBACK1, WRITEBACK2, SIZE) \ - LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS); \ - WRITEBACK1; \ - STORE_DATA; \ - WRITEBACK2; \ - clockTicks = 2 + dataTicksAccess##SIZE(address) \ - + codeTicksAccess32(armNextPC); -#define LDR(CALC_OFFSET, CALC_ADDRESS, LOAD_DATA, WRITEBACK, SIZE) \ - LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS); \ - LOAD_DATA; \ - if (dest != base) \ - { \ - WRITEBACK; \ - } \ - clockTicks = 0; \ - if (dest == 15) { \ - reg[15].I &= 0xFFFFFFFC; \ - armNextPC = reg[15].I; \ - reg[15].I += 4; \ - ARM_PREFETCH; \ - clockTicks += 2 + dataTicksAccessSeq32(address) \ - + dataTicksAccessSeq32(address);\ - } \ - clockTicks += 3 + dataTicksAccess##SIZE(address) \ - + codeTicksAccess32(armNextPC); -#define STR_POSTDEC(CALC_OFFSET, STORE_DATA, SIZE) \ - STR(CALC_OFFSET, ADDRESS_POST, STORE_DATA, WRITEBACK_NONE, WRITEBACK_POSTDEC, SIZE) -#define STR_POSTINC(CALC_OFFSET, STORE_DATA, SIZE) \ - STR(CALC_OFFSET, ADDRESS_POST, STORE_DATA, WRITEBACK_NONE, WRITEBACK_POSTINC, SIZE) -#define STR_PREDEC(CALC_OFFSET, STORE_DATA, SIZE) \ - STR(CALC_OFFSET, ADDRESS_PREDEC, STORE_DATA, WRITEBACK_NONE, WRITEBACK_NONE, SIZE) -#define STR_PREDEC_WB(CALC_OFFSET, STORE_DATA, SIZE) \ - STR(CALC_OFFSET, ADDRESS_PREDEC, STORE_DATA, WRITEBACK_PRE, WRITEBACK_NONE, SIZE) -#define STR_PREINC(CALC_OFFSET, STORE_DATA, SIZE) \ - STR(CALC_OFFSET, ADDRESS_PREINC, STORE_DATA, WRITEBACK_NONE, WRITEBACK_NONE, SIZE) -#define STR_PREINC_WB(CALC_OFFSET, STORE_DATA, SIZE) \ - STR(CALC_OFFSET, ADDRESS_PREINC, STORE_DATA, WRITEBACK_PRE, WRITEBACK_NONE, SIZE) -#define LDR_POSTDEC(CALC_OFFSET, LOAD_DATA, SIZE) \ - LDR(CALC_OFFSET, ADDRESS_POST, LOAD_DATA, WRITEBACK_POSTDEC, SIZE) -#define LDR_POSTINC(CALC_OFFSET, LOAD_DATA, SIZE) \ - LDR(CALC_OFFSET, ADDRESS_POST, LOAD_DATA, WRITEBACK_POSTINC, SIZE) -#define LDR_PREDEC(CALC_OFFSET, LOAD_DATA, SIZE) \ - LDR(CALC_OFFSET, ADDRESS_PREDEC, LOAD_DATA, WRITEBACK_NONE, SIZE) -#define LDR_PREDEC_WB(CALC_OFFSET, LOAD_DATA, SIZE) \ - LDR(CALC_OFFSET, ADDRESS_PREDEC, LOAD_DATA, WRITEBACK_PRE, SIZE) -#define LDR_PREINC(CALC_OFFSET, LOAD_DATA, SIZE) \ - LDR(CALC_OFFSET, ADDRESS_PREINC, LOAD_DATA, WRITEBACK_NONE, SIZE) -#define LDR_PREINC_WB(CALC_OFFSET, LOAD_DATA, SIZE) \ - LDR(CALC_OFFSET, ADDRESS_PREINC, LOAD_DATA, WRITEBACK_PRE, SIZE) - -// STRH Rd, [Rn], -Rm -static INSN_REGPARM void arm00B(u32 opcode) { STR_POSTDEC(OFFSET_REG, OP_STRH, 16); } -// STRH Rd, [Rn], #-offset -static INSN_REGPARM void arm04B(u32 opcode) { STR_POSTDEC(OFFSET_IMM8, OP_STRH, 16); } -// STRH Rd, [Rn], Rm -static INSN_REGPARM void arm08B(u32 opcode) { STR_POSTINC(OFFSET_REG, OP_STRH, 16); } -// STRH Rd, [Rn], #offset -static INSN_REGPARM void arm0CB(u32 opcode) { STR_POSTINC(OFFSET_IMM8, OP_STRH, 16); } -// STRH Rd, [Rn, -Rm] -static INSN_REGPARM void arm10B(u32 opcode) { STR_PREDEC(OFFSET_REG, OP_STRH, 16); } -// STRH Rd, [Rn, -Rm]! -static INSN_REGPARM void arm12B(u32 opcode) { STR_PREDEC_WB(OFFSET_REG, OP_STRH, 16); } -// STRH Rd, [Rn, -#offset] -static INSN_REGPARM void arm14B(u32 opcode) { STR_PREDEC(OFFSET_IMM8, OP_STRH, 16); } -// STRH Rd, [Rn, -#offset]! -static INSN_REGPARM void arm16B(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM8, OP_STRH, 16); } -// STRH Rd, [Rn, Rm] -static INSN_REGPARM void arm18B(u32 opcode) { STR_PREINC(OFFSET_REG, OP_STRH, 16); } -// STRH Rd, [Rn, Rm]! -static INSN_REGPARM void arm1AB(u32 opcode) { STR_PREINC_WB(OFFSET_REG, OP_STRH, 16); } -// STRH Rd, [Rn, #offset] -static INSN_REGPARM void arm1CB(u32 opcode) { STR_PREINC(OFFSET_IMM8, OP_STRH, 16); } -// STRH Rd, [Rn, #offset]! -static INSN_REGPARM void arm1EB(u32 opcode) { STR_PREINC_WB(OFFSET_IMM8, OP_STRH, 16); } - -// LDRH Rd, [Rn], -Rm -static INSN_REGPARM void arm01B(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRH, 16); } -// LDRH Rd, [Rn], #-offset -static INSN_REGPARM void arm05B(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRH, 16); } -// LDRH Rd, [Rn], Rm -static INSN_REGPARM void arm09B(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRH, 16); } -// LDRH Rd, [Rn], #offset -static INSN_REGPARM void arm0DB(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRH, 16); } -// LDRH Rd, [Rn, -Rm] -static INSN_REGPARM void arm11B(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRH, 16); } -// LDRH Rd, [Rn, -Rm]! -static INSN_REGPARM void arm13B(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRH, 16); } -// LDRH Rd, [Rn, -#offset] -static INSN_REGPARM void arm15B(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRH, 16); } -// LDRH Rd, [Rn, -#offset]! -static INSN_REGPARM void arm17B(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRH, 16); } -// LDRH Rd, [Rn, Rm] -static INSN_REGPARM void arm19B(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRH, 16); } -// LDRH Rd, [Rn, Rm]! -static INSN_REGPARM void arm1BB(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRH, 16); } -// LDRH Rd, [Rn, #offset] -static INSN_REGPARM void arm1DB(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRH, 16); } -// LDRH Rd, [Rn, #offset]! -static INSN_REGPARM void arm1FB(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRH, 16); } - -// LDRSB Rd, [Rn], -Rm -static INSN_REGPARM void arm01D(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRSB, 16); } -// LDRSB Rd, [Rn], #-offset -static INSN_REGPARM void arm05D(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRSB, 16); } -// LDRSB Rd, [Rn], Rm -static INSN_REGPARM void arm09D(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRSB, 16); } -// LDRSB Rd, [Rn], #offset -static INSN_REGPARM void arm0DD(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, -Rm] -static INSN_REGPARM void arm11D(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, -Rm]! -static INSN_REGPARM void arm13D(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, -#offset] -static INSN_REGPARM void arm15D(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, -#offset]! -static INSN_REGPARM void arm17D(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, Rm] -static INSN_REGPARM void arm19D(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, Rm]! -static INSN_REGPARM void arm1BD(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, #offset] -static INSN_REGPARM void arm1DD(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, #offset]! -static INSN_REGPARM void arm1FD(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRSB, 16); } - -// LDRSH Rd, [Rn], -Rm -static INSN_REGPARM void arm01F(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRSH, 16); } -// LDRSH Rd, [Rn], #-offset -static INSN_REGPARM void arm05F(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRSH, 16); } -// LDRSH Rd, [Rn], Rm -static INSN_REGPARM void arm09F(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRSH, 16); } -// LDRSH Rd, [Rn], #offset -static INSN_REGPARM void arm0DF(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, -Rm] -static INSN_REGPARM void arm11F(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, -Rm]! -static INSN_REGPARM void arm13F(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, -#offset] -static INSN_REGPARM void arm15F(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, -#offset]! -static INSN_REGPARM void arm17F(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, Rm] -static INSN_REGPARM void arm19F(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, Rm]! -static INSN_REGPARM void arm1BF(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, #offset] -static INSN_REGPARM void arm1DF(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, #offset]! -static INSN_REGPARM void arm1FF(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRSH, 16); } - -// STR[T] Rd, [Rn], -# -// Note: STR and STRT do the same thing on the GBA (likewise for LDR/LDRT etc) -static INSN_REGPARM void arm400(u32 opcode) { STR_POSTDEC(OFFSET_IMM, OP_STR, 32); } -// LDR[T] Rd, [Rn], -# -static INSN_REGPARM void arm410(u32 opcode) { LDR_POSTDEC(OFFSET_IMM, OP_LDR, 32); } -// STRB[T] Rd, [Rn], -# -static INSN_REGPARM void arm440(u32 opcode) { STR_POSTDEC(OFFSET_IMM, OP_STRB, 16); } -// LDRB[T] Rd, [Rn], -# -static INSN_REGPARM void arm450(u32 opcode) { LDR_POSTDEC(OFFSET_IMM, OP_LDRB, 16); } -// STR[T] Rd, [Rn], # -static INSN_REGPARM void arm480(u32 opcode) { STR_POSTINC(OFFSET_IMM, OP_STR, 32); } -// LDR Rd, [Rn], # -static INSN_REGPARM void arm490(u32 opcode) { LDR_POSTINC(OFFSET_IMM, OP_LDR, 32); } -// STRB[T] Rd, [Rn], # -static INSN_REGPARM void arm4C0(u32 opcode) { STR_POSTINC(OFFSET_IMM, OP_STRB, 16); } -// LDRB[T] Rd, [Rn], # -static INSN_REGPARM void arm4D0(u32 opcode) { LDR_POSTINC(OFFSET_IMM, OP_LDRB, 16); } -// STR Rd, [Rn, -#] -static INSN_REGPARM void arm500(u32 opcode) { STR_PREDEC(OFFSET_IMM, OP_STR, 32); } -// LDR Rd, [Rn, -#] -static INSN_REGPARM void arm510(u32 opcode) { LDR_PREDEC(OFFSET_IMM, OP_LDR, 32); } -// STR Rd, [Rn, -#]! -static INSN_REGPARM void arm520(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM, OP_STR, 32); } -// LDR Rd, [Rn, -#]! -static INSN_REGPARM void arm530(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM, OP_LDR, 32); } -// STRB Rd, [Rn, -#] -static INSN_REGPARM void arm540(u32 opcode) { STR_PREDEC(OFFSET_IMM, OP_STRB, 16); } -// LDRB Rd, [Rn, -#] -static INSN_REGPARM void arm550(u32 opcode) { LDR_PREDEC(OFFSET_IMM, OP_LDRB, 16); } -// STRB Rd, [Rn, -#]! -static INSN_REGPARM void arm560(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM, OP_STRB, 16); } -// LDRB Rd, [Rn, -#]! -static INSN_REGPARM void arm570(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM, OP_LDRB, 16); } -// STR Rd, [Rn, #] -static INSN_REGPARM void arm580(u32 opcode) { STR_PREINC(OFFSET_IMM, OP_STR, 32); } -// LDR Rd, [Rn, #] -static INSN_REGPARM void arm590(u32 opcode) { LDR_PREINC(OFFSET_IMM, OP_LDR, 32); } -// STR Rd, [Rn, #]! -static INSN_REGPARM void arm5A0(u32 opcode) { STR_PREINC_WB(OFFSET_IMM, OP_STR, 32); } -// LDR Rd, [Rn, #]! -static INSN_REGPARM void arm5B0(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM, OP_LDR, 32); } -// STRB Rd, [Rn, #] -static INSN_REGPARM void arm5C0(u32 opcode) { STR_PREINC(OFFSET_IMM, OP_STRB, 16); } -// LDRB Rd, [Rn, #] -static INSN_REGPARM void arm5D0(u32 opcode) { LDR_PREINC(OFFSET_IMM, OP_LDRB, 16); } -// STRB Rd, [Rn, #]! -static INSN_REGPARM void arm5E0(u32 opcode) { STR_PREINC_WB(OFFSET_IMM, OP_STRB, 16); } -// LDRB Rd, [Rn, #]! -static INSN_REGPARM void arm5F0(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM, OP_LDRB, 16); } - -// STR[T] Rd, [Rn], -Rm, LSL # -static INSN_REGPARM void arm600(u32 opcode) { STR_POSTDEC(OFFSET_LSL, OP_STR, 32); } -// STR[T] Rd, [Rn], -Rm, LSR # -static INSN_REGPARM void arm602(u32 opcode) { STR_POSTDEC(OFFSET_LSR, OP_STR, 32); } -// STR[T] Rd, [Rn], -Rm, ASR # -static INSN_REGPARM void arm604(u32 opcode) { STR_POSTDEC(OFFSET_ASR, OP_STR, 32); } -// STR[T] Rd, [Rn], -Rm, ROR # -static INSN_REGPARM void arm606(u32 opcode) { STR_POSTDEC(OFFSET_ROR, OP_STR, 32); } -// LDR[T] Rd, [Rn], -Rm, LSL # -static INSN_REGPARM void arm610(u32 opcode) { LDR_POSTDEC(OFFSET_LSL, OP_LDR, 32); } -// LDR[T] Rd, [Rn], -Rm, LSR # -static INSN_REGPARM void arm612(u32 opcode) { LDR_POSTDEC(OFFSET_LSR, OP_LDR, 32); } -// LDR[T] Rd, [Rn], -Rm, ASR # -static INSN_REGPARM void arm614(u32 opcode) { LDR_POSTDEC(OFFSET_ASR, OP_LDR, 32); } -// LDR[T] Rd, [Rn], -Rm, ROR # -static INSN_REGPARM void arm616(u32 opcode) { LDR_POSTDEC(OFFSET_ROR, OP_LDR, 32); } -// STRB[T] Rd, [Rn], -Rm, LSL # -static INSN_REGPARM void arm640(u32 opcode) { STR_POSTDEC(OFFSET_LSL, OP_STRB, 16); } -// STRB[T] Rd, [Rn], -Rm, LSR # -static INSN_REGPARM void arm642(u32 opcode) { STR_POSTDEC(OFFSET_LSR, OP_STRB, 16); } -// STRB[T] Rd, [Rn], -Rm, ASR # -static INSN_REGPARM void arm644(u32 opcode) { STR_POSTDEC(OFFSET_ASR, OP_STRB, 16); } -// STRB[T] Rd, [Rn], -Rm, ROR # -static INSN_REGPARM void arm646(u32 opcode) { STR_POSTDEC(OFFSET_ROR, OP_STRB, 16); } -// LDRB[T] Rd, [Rn], -Rm, LSL # -static INSN_REGPARM void arm650(u32 opcode) { LDR_POSTDEC(OFFSET_LSL, OP_LDRB, 16); } -// LDRB[T] Rd, [Rn], -Rm, LSR # -static INSN_REGPARM void arm652(u32 opcode) { LDR_POSTDEC(OFFSET_LSR, OP_LDRB, 16); } -// LDRB[T] Rd, [Rn], -Rm, ASR # -static INSN_REGPARM void arm654(u32 opcode) { LDR_POSTDEC(OFFSET_ASR, OP_LDRB, 16); } -// LDRB Rd, [Rn], -Rm, ROR # -static INSN_REGPARM void arm656(u32 opcode) { LDR_POSTDEC(OFFSET_ROR, OP_LDRB, 16); } -// STR[T] Rd, [Rn], Rm, LSL # -static INSN_REGPARM void arm680(u32 opcode) { STR_POSTINC(OFFSET_LSL, OP_STR, 32); } -// STR[T] Rd, [Rn], Rm, LSR # -static INSN_REGPARM void arm682(u32 opcode) { STR_POSTINC(OFFSET_LSR, OP_STR, 32); } -// STR[T] Rd, [Rn], Rm, ASR # -static INSN_REGPARM void arm684(u32 opcode) { STR_POSTINC(OFFSET_ASR, OP_STR, 32); } -// STR[T] Rd, [Rn], Rm, ROR # -static INSN_REGPARM void arm686(u32 opcode) { STR_POSTINC(OFFSET_ROR, OP_STR, 32); } -// LDR[T] Rd, [Rn], Rm, LSL # -static INSN_REGPARM void arm690(u32 opcode) { LDR_POSTINC(OFFSET_LSL, OP_LDR, 32); } -// LDR[T] Rd, [Rn], Rm, LSR # -static INSN_REGPARM void arm692(u32 opcode) { LDR_POSTINC(OFFSET_LSR, OP_LDR, 32); } -// LDR[T] Rd, [Rn], Rm, ASR # -static INSN_REGPARM void arm694(u32 opcode) { LDR_POSTINC(OFFSET_ASR, OP_LDR, 32); } -// LDR[T] Rd, [Rn], Rm, ROR # -static INSN_REGPARM void arm696(u32 opcode) { LDR_POSTINC(OFFSET_ROR, OP_LDR, 32); } -// STRB[T] Rd, [Rn], Rm, LSL # -static INSN_REGPARM void arm6C0(u32 opcode) { STR_POSTINC(OFFSET_LSL, OP_STRB, 16); } -// STRB[T] Rd, [Rn], Rm, LSR # -static INSN_REGPARM void arm6C2(u32 opcode) { STR_POSTINC(OFFSET_LSR, OP_STRB, 16); } -// STRB[T] Rd, [Rn], Rm, ASR # -static INSN_REGPARM void arm6C4(u32 opcode) { STR_POSTINC(OFFSET_ASR, OP_STRB, 16); } -// STRB[T] Rd, [Rn], Rm, ROR # -static INSN_REGPARM void arm6C6(u32 opcode) { STR_POSTINC(OFFSET_ROR, OP_STRB, 16); } -// LDRB[T] Rd, [Rn], Rm, LSL # -static INSN_REGPARM void arm6D0(u32 opcode) { LDR_POSTINC(OFFSET_LSL, OP_LDRB, 16); } -// LDRB[T] Rd, [Rn], Rm, LSR # -static INSN_REGPARM void arm6D2(u32 opcode) { LDR_POSTINC(OFFSET_LSR, OP_LDRB, 16); } -// LDRB[T] Rd, [Rn], Rm, ASR # -static INSN_REGPARM void arm6D4(u32 opcode) { LDR_POSTINC(OFFSET_ASR, OP_LDRB, 16); } -// LDRB[T] Rd, [Rn], Rm, ROR # -static INSN_REGPARM void arm6D6(u32 opcode) { LDR_POSTINC(OFFSET_ROR, OP_LDRB, 16); } -// STR Rd, [Rn, -Rm, LSL #] -static INSN_REGPARM void arm700(u32 opcode) { STR_PREDEC(OFFSET_LSL, OP_STR, 32); } -// STR Rd, [Rn, -Rm, LSR #] -static INSN_REGPARM void arm702(u32 opcode) { STR_PREDEC(OFFSET_LSR, OP_STR, 32); } -// STR Rd, [Rn, -Rm, ASR #] -static INSN_REGPARM void arm704(u32 opcode) { STR_PREDEC(OFFSET_ASR, OP_STR, 32); } -// STR Rd, [Rn, -Rm, ROR #] -static INSN_REGPARM void arm706(u32 opcode) { STR_PREDEC(OFFSET_ROR, OP_STR, 32); } -// LDR Rd, [Rn, -Rm, LSL #] -static INSN_REGPARM void arm710(u32 opcode) { LDR_PREDEC(OFFSET_LSL, OP_LDR, 32); } -// LDR Rd, [Rn, -Rm, LSR #] -static INSN_REGPARM void arm712(u32 opcode) { LDR_PREDEC(OFFSET_LSR, OP_LDR, 32); } -// LDR Rd, [Rn, -Rm, ASR #] -static INSN_REGPARM void arm714(u32 opcode) { LDR_PREDEC(OFFSET_ASR, OP_LDR, 32); } -// LDR Rd, [Rn, -Rm, ROR #] -static INSN_REGPARM void arm716(u32 opcode) { LDR_PREDEC(OFFSET_ROR, OP_LDR, 32); } -// STR Rd, [Rn, -Rm, LSL #]! -static INSN_REGPARM void arm720(u32 opcode) { STR_PREDEC_WB(OFFSET_LSL, OP_STR, 32); } -// STR Rd, [Rn, -Rm, LSR #]! -static INSN_REGPARM void arm722(u32 opcode) { STR_PREDEC_WB(OFFSET_LSR, OP_STR, 32); } -// STR Rd, [Rn, -Rm, ASR #]! -static INSN_REGPARM void arm724(u32 opcode) { STR_PREDEC_WB(OFFSET_ASR, OP_STR, 32); } -// STR Rd, [Rn, -Rm, ROR #]! -static INSN_REGPARM void arm726(u32 opcode) { STR_PREDEC_WB(OFFSET_ROR, OP_STR, 32); } -// LDR Rd, [Rn, -Rm, LSL #]! -static INSN_REGPARM void arm730(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSL, OP_LDR, 32); } -// LDR Rd, [Rn, -Rm, LSR #]! -static INSN_REGPARM void arm732(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSR, OP_LDR, 32); } -// LDR Rd, [Rn, -Rm, ASR #]! -static INSN_REGPARM void arm734(u32 opcode) { LDR_PREDEC_WB(OFFSET_ASR, OP_LDR, 32); } -// LDR Rd, [Rn, -Rm, ROR #]! -static INSN_REGPARM void arm736(u32 opcode) { LDR_PREDEC_WB(OFFSET_ROR, OP_LDR, 32); } -// STRB Rd, [Rn, -Rm, LSL #] -static INSN_REGPARM void arm740(u32 opcode) { STR_PREDEC(OFFSET_LSL, OP_STRB, 16); } -// STRB Rd, [Rn, -Rm, LSR #] -static INSN_REGPARM void arm742(u32 opcode) { STR_PREDEC(OFFSET_LSR, OP_STRB, 16); } -// STRB Rd, [Rn, -Rm, ASR #] -static INSN_REGPARM void arm744(u32 opcode) { STR_PREDEC(OFFSET_ASR, OP_STRB, 16); } -// STRB Rd, [Rn, -Rm, ROR #] -static INSN_REGPARM void arm746(u32 opcode) { STR_PREDEC(OFFSET_ROR, OP_STRB, 16); } -// LDRB Rd, [Rn, -Rm, LSL #] -static INSN_REGPARM void arm750(u32 opcode) { LDR_PREDEC(OFFSET_LSL, OP_LDRB, 16); } -// LDRB Rd, [Rn, -Rm, LSR #] -static INSN_REGPARM void arm752(u32 opcode) { LDR_PREDEC(OFFSET_LSR, OP_LDRB, 16); } -// LDRB Rd, [Rn, -Rm, ASR #] -static INSN_REGPARM void arm754(u32 opcode) { LDR_PREDEC(OFFSET_ASR, OP_LDRB, 16); } -// LDRB Rd, [Rn, -Rm, ROR #] -static INSN_REGPARM void arm756(u32 opcode) { LDR_PREDEC(OFFSET_ROR, OP_LDRB, 16); } -// STRB Rd, [Rn, -Rm, LSL #]! -static INSN_REGPARM void arm760(u32 opcode) { STR_PREDEC_WB(OFFSET_LSL, OP_STRB, 16); } -// STRB Rd, [Rn, -Rm, LSR #]! -static INSN_REGPARM void arm762(u32 opcode) { STR_PREDEC_WB(OFFSET_LSR, OP_STRB, 16); } -// STRB Rd, [Rn, -Rm, ASR #]! -static INSN_REGPARM void arm764(u32 opcode) { STR_PREDEC_WB(OFFSET_ASR, OP_STRB, 16); } -// STRB Rd, [Rn, -Rm, ROR #]! -static INSN_REGPARM void arm766(u32 opcode) { STR_PREDEC_WB(OFFSET_ROR, OP_STRB, 16); } -// LDRB Rd, [Rn, -Rm, LSL #]! -static INSN_REGPARM void arm770(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSL, OP_LDRB, 16); } -// LDRB Rd, [Rn, -Rm, LSR #]! -static INSN_REGPARM void arm772(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSR, OP_LDRB, 16); } -// LDRB Rd, [Rn, -Rm, ASR #]! -static INSN_REGPARM void arm774(u32 opcode) { LDR_PREDEC_WB(OFFSET_ASR, OP_LDRB, 16); } -// LDRB Rd, [Rn, -Rm, ROR #]! -static INSN_REGPARM void arm776(u32 opcode) { LDR_PREDEC_WB(OFFSET_ROR, OP_LDRB, 16); } -// STR Rd, [Rn, Rm, LSL #] -static INSN_REGPARM void arm780(u32 opcode) { STR_PREINC(OFFSET_LSL, OP_STR, 32); } -// STR Rd, [Rn, Rm, LSR #] -static INSN_REGPARM void arm782(u32 opcode) { STR_PREINC(OFFSET_LSR, OP_STR, 32); } -// STR Rd, [Rn, Rm, ASR #] -static INSN_REGPARM void arm784(u32 opcode) { STR_PREINC(OFFSET_ASR, OP_STR, 32); } -// STR Rd, [Rn, Rm, ROR #] -static INSN_REGPARM void arm786(u32 opcode) { STR_PREINC(OFFSET_ROR, OP_STR, 32); } -// LDR Rd, [Rn, Rm, LSL #] -static INSN_REGPARM void arm790(u32 opcode) { LDR_PREINC(OFFSET_LSL, OP_LDR, 32); } -// LDR Rd, [Rn, Rm, LSR #] -static INSN_REGPARM void arm792(u32 opcode) { LDR_PREINC(OFFSET_LSR, OP_LDR, 32); } -// LDR Rd, [Rn, Rm, ASR #] -static INSN_REGPARM void arm794(u32 opcode) { LDR_PREINC(OFFSET_ASR, OP_LDR, 32); } -// LDR Rd, [Rn, Rm, ROR #] -static INSN_REGPARM void arm796(u32 opcode) { LDR_PREINC(OFFSET_ROR, OP_LDR, 32); } -// STR Rd, [Rn, Rm, LSL #]! -static INSN_REGPARM void arm7A0(u32 opcode) { STR_PREINC_WB(OFFSET_LSL, OP_STR, 32); } -// STR Rd, [Rn, Rm, LSR #]! -static INSN_REGPARM void arm7A2(u32 opcode) { STR_PREINC_WB(OFFSET_LSR, OP_STR, 32); } -// STR Rd, [Rn, Rm, ASR #]! -static INSN_REGPARM void arm7A4(u32 opcode) { STR_PREINC_WB(OFFSET_ASR, OP_STR, 32); } -// STR Rd, [Rn, Rm, ROR #]! -static INSN_REGPARM void arm7A6(u32 opcode) { STR_PREINC_WB(OFFSET_ROR, OP_STR, 32); } -// LDR Rd, [Rn, Rm, LSL #]! -static INSN_REGPARM void arm7B0(u32 opcode) { LDR_PREINC_WB(OFFSET_LSL, OP_LDR, 32); } -// LDR Rd, [Rn, Rm, LSR #]! -static INSN_REGPARM void arm7B2(u32 opcode) { LDR_PREINC_WB(OFFSET_LSR, OP_LDR, 32); } -// LDR Rd, [Rn, Rm, ASR #]! -static INSN_REGPARM void arm7B4(u32 opcode) { LDR_PREINC_WB(OFFSET_ASR, OP_LDR, 32); } -// LDR Rd, [Rn, Rm, ROR #]! -static INSN_REGPARM void arm7B6(u32 opcode) { LDR_PREINC_WB(OFFSET_ROR, OP_LDR, 32); } -// STRB Rd, [Rn, Rm, LSL #] -static INSN_REGPARM void arm7C0(u32 opcode) { STR_PREINC(OFFSET_LSL, OP_STRB, 16); } -// STRB Rd, [Rn, Rm, LSR #] -static INSN_REGPARM void arm7C2(u32 opcode) { STR_PREINC(OFFSET_LSR, OP_STRB, 16); } -// STRB Rd, [Rn, Rm, ASR #] -static INSN_REGPARM void arm7C4(u32 opcode) { STR_PREINC(OFFSET_ASR, OP_STRB, 16); } -// STRB Rd, [Rn, Rm, ROR #] -static INSN_REGPARM void arm7C6(u32 opcode) { STR_PREINC(OFFSET_ROR, OP_STRB, 16); } -// LDRB Rd, [Rn, Rm, LSL #] -static INSN_REGPARM void arm7D0(u32 opcode) { LDR_PREINC(OFFSET_LSL, OP_LDRB, 16); } -// LDRB Rd, [Rn, Rm, LSR #] -static INSN_REGPARM void arm7D2(u32 opcode) { LDR_PREINC(OFFSET_LSR, OP_LDRB, 16); } -// LDRB Rd, [Rn, Rm, ASR #] -static INSN_REGPARM void arm7D4(u32 opcode) { LDR_PREINC(OFFSET_ASR, OP_LDRB, 16); } -// LDRB Rd, [Rn, Rm, ROR #] -static INSN_REGPARM void arm7D6(u32 opcode) { LDR_PREINC(OFFSET_ROR, OP_LDRB, 16); } -// STRB Rd, [Rn, Rm, LSL #]! -static INSN_REGPARM void arm7E0(u32 opcode) { STR_PREINC_WB(OFFSET_LSL, OP_STRB, 16); } -// STRB Rd, [Rn, Rm, LSR #]! -static INSN_REGPARM void arm7E2(u32 opcode) { STR_PREINC_WB(OFFSET_LSR, OP_STRB, 16); } -// STRB Rd, [Rn, Rm, ASR #]! -static INSN_REGPARM void arm7E4(u32 opcode) { STR_PREINC_WB(OFFSET_ASR, OP_STRB, 16); } -// STRB Rd, [Rn, Rm, ROR #]! -static INSN_REGPARM void arm7E6(u32 opcode) { STR_PREINC_WB(OFFSET_ROR, OP_STRB, 16); } -// LDRB Rd, [Rn, Rm, LSL #]! -static INSN_REGPARM void arm7F0(u32 opcode) { LDR_PREINC_WB(OFFSET_LSL, OP_LDRB, 16); } -// LDRB Rd, [Rn, Rm, LSR #]! -static INSN_REGPARM void arm7F2(u32 opcode) { LDR_PREINC_WB(OFFSET_LSR, OP_LDRB, 16); } -// LDRB Rd, [Rn, Rm, ASR #]! -static INSN_REGPARM void arm7F4(u32 opcode) { LDR_PREINC_WB(OFFSET_ASR, OP_LDRB, 16); } -// LDRB Rd, [Rn, Rm, ROR #]! -static INSN_REGPARM void arm7F6(u32 opcode) { LDR_PREINC_WB(OFFSET_ROR, OP_LDRB, 16); } - -// STM/LDM //////////////////////////////////////////////////////////////// - -#define STM_REG(bit,num) \ - if (opcode & (1U<<(bit))) { \ - CPUWriteMemory(address, reg[(num)].I); \ - if (!count) { \ - clockTicks += 1 + dataTicksAccess32(address);\ - } else { \ - clockTicks += 1 + dataTicksAccessSeq32(address);\ - } \ - count++; \ - address += 4; \ - } -#define STMW_REG(bit,num) \ - if (opcode & (1U<<(bit))) { \ - CPUWriteMemory(address, reg[(num)].I); \ - if (!count) { \ - clockTicks += 1 + dataTicksAccess32(address);\ - } else { \ - clockTicks += 1 + dataTicksAccessSeq32(address);\ - } \ - reg[base].I = temp; \ - count++; \ - address += 4; \ - } -#define LDM_REG(bit,num) \ - if (opcode & (1U<<(bit))) { \ - reg[(num)].I = CPUReadMemory(address); \ - if (!count) { \ - clockTicks += 1 + dataTicksAccess32(address);\ - } else { \ - clockTicks += 1 + dataTicksAccessSeq32(address);\ - } \ - count++; \ - address += 4; \ - } -#define STM_LOW(STORE_REG) \ - STORE_REG(0, 0); \ - STORE_REG(1, 1); \ - STORE_REG(2, 2); \ - STORE_REG(3, 3); \ - STORE_REG(4, 4); \ - STORE_REG(5, 5); \ - STORE_REG(6, 6); \ - STORE_REG(7, 7); -#define STM_HIGH(STORE_REG) \ - STORE_REG(8, 8); \ - STORE_REG(9, 9); \ - STORE_REG(10, 10); \ - STORE_REG(11, 11); \ - STORE_REG(12, 12); \ - STORE_REG(13, 13); \ - STORE_REG(14, 14); -#define STM_HIGH_2(STORE_REG) \ - if (armMode == 0x11) { \ - STORE_REG(8, R8_FIQ); \ - STORE_REG(9, R9_FIQ); \ - STORE_REG(10, R10_FIQ); \ - STORE_REG(11, R11_FIQ); \ - STORE_REG(12, R12_FIQ); \ - } else { \ - STORE_REG(8, 8); \ - STORE_REG(9, 9); \ - STORE_REG(10, 10); \ - STORE_REG(11, 11); \ - STORE_REG(12, 12); \ - } \ - if (armMode != 0x10 && armMode != 0x1F) { \ - STORE_REG(13, R13_USR); \ - STORE_REG(14, R14_USR); \ - } else { \ - STORE_REG(13, 13); \ - STORE_REG(14, 14); \ - } -#define STM_PC \ - if (opcode & (1U<<15)) { \ - CPUWriteMemory(address, reg[15].I+4); \ - if (!count) { \ - clockTicks += 1 + dataTicksAccess32(address);\ - } else { \ - clockTicks += 1 + dataTicksAccessSeq32(address);\ - } \ - count++; \ - } -#define STMW_PC \ - if (opcode & (1U<<15)) { \ - CPUWriteMemory(address, reg[15].I+4); \ - if (!count) { \ - clockTicks += 1 + dataTicksAccess32(address);\ - } else { \ - clockTicks += 1 + dataTicksAccessSeq32(address);\ - } \ - reg[base].I = temp; \ - count++; \ - } -#define LDM_LOW \ - LDM_REG(0, 0); \ - LDM_REG(1, 1); \ - LDM_REG(2, 2); \ - LDM_REG(3, 3); \ - LDM_REG(4, 4); \ - LDM_REG(5, 5); \ - LDM_REG(6, 6); \ - LDM_REG(7, 7); -#define LDM_HIGH \ - LDM_REG(8, 8); \ - LDM_REG(9, 9); \ - LDM_REG(10, 10); \ - LDM_REG(11, 11); \ - LDM_REG(12, 12); \ - LDM_REG(13, 13); \ - LDM_REG(14, 14); -#define LDM_HIGH_2 \ - if (armMode == 0x11) { \ - LDM_REG(8, R8_FIQ); \ - LDM_REG(9, R9_FIQ); \ - LDM_REG(10, R10_FIQ); \ - LDM_REG(11, R11_FIQ); \ - LDM_REG(12, R12_FIQ); \ - } else { \ - LDM_REG(8, 8); \ - LDM_REG(9, 9); \ - LDM_REG(10, 10); \ - LDM_REG(11, 11); \ - LDM_REG(12, 12); \ - } \ - if (armMode != 0x10 && armMode != 0x1F) { \ - LDM_REG(13, R13_USR); \ - LDM_REG(14, R14_USR); \ - } else { \ - LDM_REG(13, 13); \ - LDM_REG(14, 14); \ - } -#define STM_ALL \ - STM_LOW(STM_REG); \ - STM_HIGH(STM_REG); \ - STM_PC; -#define STMW_ALL \ - STM_LOW(STMW_REG); \ - STM_HIGH(STMW_REG); \ - STMW_PC; -#define LDM_ALL \ - LDM_LOW; \ - LDM_HIGH; \ - if (opcode & (1U<<15)) { \ - reg[15].I = CPUReadMemory(address); \ - if (!count) { \ - clockTicks += 1 + dataTicksAccess32(address);\ - } else { \ - clockTicks += 1 + dataTicksAccessSeq32(address);\ - } \ - count++; \ - } \ - if (opcode & (1U<<15)) { \ - armNextPC = reg[15].I; \ - reg[15].I += 4; \ - ARM_PREFETCH; \ - clockTicks += 1 + codeTicksAccessSeq32(armNextPC);\ - } -#define STM_ALL_2 \ - STM_LOW(STM_REG); \ - STM_HIGH_2(STM_REG); \ - STM_PC; -#define STMW_ALL_2 \ - STM_LOW(STMW_REG); \ - STM_HIGH_2(STMW_REG); \ - STMW_PC; -#define LDM_ALL_2 \ - LDM_LOW; \ - if (opcode & (1U<<15)) { \ - LDM_HIGH; \ - reg[15].I = CPUReadMemory(address); \ - if (!count) { \ - clockTicks += 1 + dataTicksAccess32(address); \ - } else { \ - clockTicks += 1 + dataTicksAccessSeq32(address); \ - } \ - count++; \ - } else { \ - LDM_HIGH_2; \ - } -#define LDM_ALL_2B \ - if (opcode & (1U<<15)) { \ - CPUSwitchMode(reg[17].I & 0x1F, false); \ - if (armState) { \ - armNextPC = reg[15].I & 0xFFFFFFFC; \ - reg[15].I = armNextPC + 4; \ - ARM_PREFETCH; \ - } else { \ - armNextPC = reg[15].I & 0xFFFFFFFE; \ - reg[15].I = armNextPC + 2; \ - THUMB_PREFETCH; \ - } \ - clockTicks += 1 + codeTicksAccessSeq32(armNextPC);\ - } - - -// STMDA Rn, {Rlist} -static INSN_REGPARM void arm800(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - int count = 0; - STM_ALL; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMDA Rn, {Rlist} -static INSN_REGPARM void arm810(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess32(armNextPC); -} - -// STMDA Rn!, {Rlist} -static INSN_REGPARM void arm820(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp+4) & 0xFFFFFFFC; - int count = 0; - STMW_ALL; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMDA Rn!, {Rlist} -static INSN_REGPARM void arm830(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess32(armNextPC); - if (!(opcode & (1U << base))) - reg[base].I = temp; -} - -// STMDA Rn, {Rlist}^ -static INSN_REGPARM void arm840(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp+4) & 0xFFFFFFFC; - int count = 0; - STM_ALL_2; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMDA Rn, {Rlist}^ -static INSN_REGPARM void arm850(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL_2; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess32(armNextPC); -} - -// STMDA Rn!, {Rlist}^ -static INSN_REGPARM void arm860(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp+4) & 0xFFFFFFFC; - int count = 0; - STMW_ALL_2; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMDA Rn!, {Rlist}^ -static INSN_REGPARM void arm870(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL_2; - if (!(opcode & (1U << base))) - reg[base].I = temp; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess32(armNextPC); -} - -// STMIA Rn, {Rlist} -static INSN_REGPARM void arm880(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = reg[base].I & 0xFFFFFFFC; - int count = 0; - STM_ALL; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMIA Rn, {Rlist} -static INSN_REGPARM void arm890(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = reg[base].I & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess32(armNextPC); -} - -// STMIA Rn!, {Rlist} -static INSN_REGPARM void arm8A0(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = reg[base].I & 0xFFFFFFFC; - int count = 0; - u32 temp = reg[base].I + - 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); - STMW_ALL; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMIA Rn!, {Rlist} -static INSN_REGPARM void arm8B0(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I + - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = reg[base].I & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess32(armNextPC); - if (!(opcode & (1U << base))) - reg[base].I = temp; -} - -// STMIA Rn, {Rlist}^ -static INSN_REGPARM void arm8C0(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = reg[base].I & 0xFFFFFFFC; - int count = 0; - STM_ALL_2; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMIA Rn, {Rlist}^ -static INSN_REGPARM void arm8D0(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = reg[base].I & 0xFFFFFFFC; - int count = 0; - LDM_ALL_2; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess32(armNextPC); -} - -// STMIA Rn!, {Rlist}^ -static INSN_REGPARM void arm8E0(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = reg[base].I & 0xFFFFFFFC; - int count = 0; - u32 temp = reg[base].I + - 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); - STMW_ALL_2; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMIA Rn!, {Rlist}^ -static INSN_REGPARM void arm8F0(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I + - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = reg[base].I & 0xFFFFFFFC; - int count = 0; - LDM_ALL_2; - if (!(opcode & (1U << base))) - reg[base].I = temp; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess32(armNextPC); -} - -// STMDB Rn, {Rlist} -static INSN_REGPARM void arm900(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - STM_ALL; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMDB Rn, {Rlist} -static INSN_REGPARM void arm910(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess32(armNextPC); -} - -// STMDB Rn!, {Rlist} -static INSN_REGPARM void arm920(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - STMW_ALL; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMDB Rn!, {Rlist} -static INSN_REGPARM void arm930(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess32(armNextPC); - if (!(opcode & (1U << base))) - reg[base].I = temp; -} - -// STMDB Rn, {Rlist}^ -static INSN_REGPARM void arm940(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - STM_ALL_2; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMDB Rn, {Rlist}^ -static INSN_REGPARM void arm950(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - LDM_ALL_2; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess32(armNextPC); -} - -// STMDB Rn!, {Rlist}^ -static INSN_REGPARM void arm960(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - STMW_ALL_2; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMDB Rn!, {Rlist}^ -static INSN_REGPARM void arm970(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - LDM_ALL_2; - if (!(opcode & (1U << base))) - reg[base].I = temp; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess32(armNextPC); -} - -// STMIB Rn, {Rlist} -static INSN_REGPARM void arm980(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - STM_ALL; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMIB Rn, {Rlist} -static INSN_REGPARM void arm990(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess32(armNextPC); -} - -// STMIB Rn!, {Rlist} -static INSN_REGPARM void arm9A0(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - u32 temp = reg[base].I + - 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); - STMW_ALL; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMIB Rn!, {Rlist} -static INSN_REGPARM void arm9B0(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I + - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess32(armNextPC); - if (!(opcode & (1U << base))) - reg[base].I = temp; -} - -// STMIB Rn, {Rlist}^ -static INSN_REGPARM void arm9C0(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - STM_ALL_2; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMIB Rn, {Rlist}^ -static INSN_REGPARM void arm9D0(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL_2; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess32(armNextPC); -} - -// STMIB Rn!, {Rlist}^ -static INSN_REGPARM void arm9E0(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - u32 temp = reg[base].I + - 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); - STMW_ALL_2; - clockTicks += 1 + codeTicksAccess32(armNextPC); -} - -// LDMIB Rn!, {Rlist}^ -static INSN_REGPARM void arm9F0(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I + - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL_2; - if (!(opcode & (1U << base))) - reg[base].I = temp; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess32(armNextPC); -} - -// B/BL/SWI and (unimplemented) coproc support //////////////////////////// - -// B -static INSN_REGPARM void armA00(u32 opcode) -{ - int offset = opcode & 0x00FFFFFF; - if (offset & 0x00800000) - offset |= 0xFF000000; // negative offset - reg[15].I += offset<<2; - armNextPC = reg[15].I; - reg[15].I += 4; - ARM_PREFETCH; - clockTicks = codeTicksAccessSeq32(armNextPC) + 1; - clockTicks += 2 + codeTicksAccess32(armNextPC) - + codeTicksAccessSeq32(armNextPC); - busPrefetchCount = 0; -} - -// BL -static INSN_REGPARM void armB00(u32 opcode) -{ - int offset = opcode & 0x00FFFFFF; - if (offset & 0x00800000) - offset |= 0xFF000000; // negative offset - reg[14].I = reg[15].I - 4; - reg[15].I += offset<<2; - armNextPC = reg[15].I; - reg[15].I += 4; - ARM_PREFETCH; - clockTicks = codeTicksAccessSeq32(armNextPC) + 1; - clockTicks += 2 + codeTicksAccess32(armNextPC) - + codeTicksAccessSeq32(armNextPC); - busPrefetchCount = 0; -} - - -#ifdef GP_SUPPORT -// MRC -static INSN_REGPARM void armE01(u32 opcode) -{ -} -#else - #define armE01 armUnknownInsn -#endif - - -// SWI -static INSN_REGPARM void armF00(u32 opcode) -{ - clockTicks = codeTicksAccessSeq32(armNextPC) + 1; - clockTicks += 2 + codeTicksAccess32(armNextPC) - + codeTicksAccessSeq32(armNextPC); - busPrefetchCount = 0; - CPUSoftwareInterrupt(opcode & 0x00FFFFFF); -} - -// Instruction table ////////////////////////////////////////////////////// - -typedef INSN_REGPARM void (*insnfunc_t)(u32 opcode); -#define REP16(insn) \ - insn,insn,insn,insn,insn,insn,insn,insn,\ - insn,insn,insn,insn,insn,insn,insn,insn -#define REP256(insn) \ - REP16(insn),REP16(insn),REP16(insn),REP16(insn),\ - REP16(insn),REP16(insn),REP16(insn),REP16(insn),\ - REP16(insn),REP16(insn),REP16(insn),REP16(insn),\ - REP16(insn),REP16(insn),REP16(insn),REP16(insn) -#define arm_UI armUnknownInsn -#ifdef BKPT_SUPPORT - #define arm_BP armBreakpoint -#else - #define arm_BP armUnknownInsn -#endif -static insnfunc_t armInsnTable[4096] = { - arm000,arm001,arm002,arm003,arm004,arm005,arm006,arm007, // 000 - arm000,arm009,arm002,arm00B,arm004,arm_UI,arm006,arm_UI, // 008 - arm010,arm011,arm012,arm013,arm014,arm015,arm016,arm017, // 010 - arm010,arm019,arm012,arm01B,arm014,arm01D,arm016,arm01F, // 018 - arm020,arm021,arm022,arm023,arm024,arm025,arm026,arm027, // 020 - arm020,arm029,arm022,arm_UI,arm024,arm_UI,arm026,arm_UI, // 028 - arm030,arm031,arm032,arm033,arm034,arm035,arm036,arm037, // 030 - arm030,arm039,arm032,arm_UI,arm034,arm01D,arm036,arm01F, // 038 - arm040,arm041,arm042,arm043,arm044,arm045,arm046,arm047, // 040 - arm040,arm_UI,arm042,arm04B,arm044,arm_UI,arm046,arm_UI, // 048 - arm050,arm051,arm052,arm053,arm054,arm055,arm056,arm057, // 050 - arm050,arm_UI,arm052,arm05B,arm054,arm05D,arm056,arm05F, // 058 - arm060,arm061,arm062,arm063,arm064,arm065,arm066,arm067, // 060 - arm060,arm_UI,arm062,arm_UI,arm064,arm_UI,arm066,arm_UI, // 068 - arm070,arm071,arm072,arm073,arm074,arm075,arm076,arm077, // 070 - arm070,arm_UI,arm072,arm_UI,arm074,arm05D,arm076,arm05F, // 078 - arm080,arm081,arm082,arm083,arm084,arm085,arm086,arm087, // 080 - arm080,arm089,arm082,arm08B,arm084,arm_UI,arm086,arm_UI, // 088 - arm090,arm091,arm092,arm093,arm094,arm095,arm096,arm097, // 090 - arm090,arm099,arm092,arm09B,arm094,arm09D,arm096,arm09F, // 098 - arm0A0,arm0A1,arm0A2,arm0A3,arm0A4,arm0A5,arm0A6,arm0A7, // 0A0 - arm0A0,arm0A9,arm0A2,arm_UI,arm0A4,arm_UI,arm0A6,arm_UI, // 0A8 - arm0B0,arm0B1,arm0B2,arm0B3,arm0B4,arm0B5,arm0B6,arm0B7, // 0B0 - arm0B0,arm0B9,arm0B2,arm_UI,arm0B4,arm09D,arm0B6,arm09F, // 0B8 - arm0C0,arm0C1,arm0C2,arm0C3,arm0C4,arm0C5,arm0C6,arm0C7, // 0C0 - arm0C0,arm0C9,arm0C2,arm0CB,arm0C4,arm_UI,arm0C6,arm_UI, // 0C8 - arm0D0,arm0D1,arm0D2,arm0D3,arm0D4,arm0D5,arm0D6,arm0D7, // 0D0 - arm0D0,arm0D9,arm0D2,arm0DB,arm0D4,arm0DD,arm0D6,arm0DF, // 0D8 - arm0E0,arm0E1,arm0E2,arm0E3,arm0E4,arm0E5,arm0E6,arm0E7, // 0E0 - arm0E0,arm0E9,arm0E2,arm_UI,arm0E4,arm_UI,arm0E6,arm_UI, // 0E8 - arm0F0,arm0F1,arm0F2,arm0F3,arm0F4,arm0F5,arm0F6,arm0F7, // 0F0 - arm0F0,arm0F9,arm0F2,arm_UI,arm0F4,arm0DD,arm0F6,arm0DF, // 0F8 - - arm100,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 100 - arm_UI,arm109,arm_UI,arm10B,arm_UI,arm_UI,arm_UI,arm_UI, // 108 - arm110,arm111,arm112,arm113,arm114,arm115,arm116,arm117, // 110 - arm110,arm_UI,arm112,arm11B,arm114,arm11D,arm116,arm11F, // 118 - arm120,arm121,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_BP, // 120 - arm_UI,arm_UI,arm_UI,arm12B,arm_UI,arm_UI,arm_UI,arm_UI, // 128 - arm130,arm131,arm132,arm133,arm134,arm135,arm136,arm137, // 130 - arm130,arm_UI,arm132,arm13B,arm134,arm13D,arm136,arm13F, // 138 - arm140,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 140 - arm_UI,arm149,arm_UI,arm14B,arm_UI,arm_UI,arm_UI,arm_UI, // 148 - arm150,arm151,arm152,arm153,arm154,arm155,arm156,arm157, // 150 - arm150,arm_UI,arm152,arm15B,arm154,arm15D,arm156,arm15F, // 158 - arm160,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 160 - arm_UI,arm_UI,arm_UI,arm16B,arm_UI,arm_UI,arm_UI,arm_UI, // 168 - arm170,arm171,arm172,arm173,arm174,arm175,arm176,arm177, // 170 - arm170,arm_UI,arm172,arm17B,arm174,arm17D,arm176,arm17F, // 178 - arm180,arm181,arm182,arm183,arm184,arm185,arm186,arm187, // 180 - arm180,arm_UI,arm182,arm18B,arm184,arm_UI,arm186,arm_UI, // 188 - arm190,arm191,arm192,arm193,arm194,arm195,arm196,arm197, // 190 - arm190,arm_UI,arm192,arm19B,arm194,arm19D,arm196,arm19F, // 198 - arm1A0,arm1A1,arm1A2,arm1A3,arm1A4,arm1A5,arm1A6,arm1A7, // 1A0 - arm1A0,arm_UI,arm1A2,arm1AB,arm1A4,arm_UI,arm1A6,arm_UI, // 1A8 - arm1B0,arm1B1,arm1B2,arm1B3,arm1B4,arm1B5,arm1B6,arm1B7, // 1B0 - arm1B0,arm_UI,arm1B2,arm1BB,arm1B4,arm1BD,arm1B6,arm1BF, // 1B8 - arm1C0,arm1C1,arm1C2,arm1C3,arm1C4,arm1C5,arm1C6,arm1C7, // 1C0 - arm1C0,arm_UI,arm1C2,arm1CB,arm1C4,arm_UI,arm1C6,arm_UI, // 1C8 - arm1D0,arm1D1,arm1D2,arm1D3,arm1D4,arm1D5,arm1D6,arm1D7, // 1D0 - arm1D0,arm_UI,arm1D2,arm1DB,arm1D4,arm1DD,arm1D6,arm1DF, // 1D8 - arm1E0,arm1E1,arm1E2,arm1E3,arm1E4,arm1E5,arm1E6,arm1E7, // 1E0 - arm1E0,arm_UI,arm1E2,arm1EB,arm1E4,arm_UI,arm1E6,arm_UI, // 1E8 - arm1F0,arm1F1,arm1F2,arm1F3,arm1F4,arm1F5,arm1F6,arm1F7, // 1F0 - arm1F0,arm_UI,arm1F2,arm1FB,arm1F4,arm1FD,arm1F6,arm1FF, // 1F8 - - REP16(arm200),REP16(arm210),REP16(arm220),REP16(arm230), // 200 - REP16(arm240),REP16(arm250),REP16(arm260),REP16(arm270), // 240 - REP16(arm280),REP16(arm290),REP16(arm2A0),REP16(arm2B0), // 280 - REP16(arm2C0),REP16(arm2D0),REP16(arm2E0),REP16(arm2F0), // 2C0 - REP16(arm_UI),REP16(arm310),REP16(arm320),REP16(arm330), // 300 - REP16(arm_UI),REP16(arm350),REP16(arm360),REP16(arm370), // 340 - REP16(arm380),REP16(arm390),REP16(arm3A0),REP16(arm3B0), // 380 - REP16(arm3C0),REP16(arm3D0),REP16(arm3E0),REP16(arm3F0), // 3C0 - - REP16(arm400),REP16(arm410),REP16(arm400),REP16(arm410), // 400 - REP16(arm440),REP16(arm450),REP16(arm440),REP16(arm450), // 440 - REP16(arm480),REP16(arm490),REP16(arm480),REP16(arm490), // 480 - REP16(arm4C0),REP16(arm4D0),REP16(arm4C0),REP16(arm4D0), // 4C0 - REP16(arm500),REP16(arm510),REP16(arm520),REP16(arm530), // 500 - REP16(arm540),REP16(arm550),REP16(arm560),REP16(arm570), // 540 - REP16(arm580),REP16(arm590),REP16(arm5A0),REP16(arm5B0), // 580 - REP16(arm5C0),REP16(arm5D0),REP16(arm5E0),REP16(arm5F0), // 5C0 - - arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 600 - arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 608 - arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 610 - arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 618 - arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 620 - arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 628 - arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 630 - arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 638 - arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 640 - arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 648 - arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 650 - arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 658 - arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 660 - arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 668 - arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 670 - arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 678 - arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 680 - arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 688 - arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 690 - arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 698 - arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 6A0 - arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 6A8 - arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 6B0 - arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 6B8 - arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6C0 - arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6C8 - arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6D0 - arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6D8 - arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6E0 - arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6E8 - arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6F0 - arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6F8 - - arm700,arm_UI,arm702,arm_UI,arm704,arm_UI,arm706,arm_UI, // 700 - arm700,arm_UI,arm702,arm_UI,arm704,arm_UI,arm706,arm_UI, // 708 - arm710,arm_UI,arm712,arm_UI,arm714,arm_UI,arm716,arm_UI, // 710 - arm710,arm_UI,arm712,arm_UI,arm714,arm_UI,arm716,arm_UI, // 718 - arm720,arm_UI,arm722,arm_UI,arm724,arm_UI,arm726,arm_UI, // 720 - arm720,arm_UI,arm722,arm_UI,arm724,arm_UI,arm726,arm_UI, // 728 - arm730,arm_UI,arm732,arm_UI,arm734,arm_UI,arm736,arm_UI, // 730 - arm730,arm_UI,arm732,arm_UI,arm734,arm_UI,arm736,arm_UI, // 738 - arm740,arm_UI,arm742,arm_UI,arm744,arm_UI,arm746,arm_UI, // 740 - arm740,arm_UI,arm742,arm_UI,arm744,arm_UI,arm746,arm_UI, // 748 - arm750,arm_UI,arm752,arm_UI,arm754,arm_UI,arm756,arm_UI, // 750 - arm750,arm_UI,arm752,arm_UI,arm754,arm_UI,arm756,arm_UI, // 758 - arm760,arm_UI,arm762,arm_UI,arm764,arm_UI,arm766,arm_UI, // 760 - arm760,arm_UI,arm762,arm_UI,arm764,arm_UI,arm766,arm_UI, // 768 - arm770,arm_UI,arm772,arm_UI,arm774,arm_UI,arm776,arm_UI, // 770 - arm770,arm_UI,arm772,arm_UI,arm774,arm_UI,arm776,arm_UI, // 778 - arm780,arm_UI,arm782,arm_UI,arm784,arm_UI,arm786,arm_UI, // 780 - arm780,arm_UI,arm782,arm_UI,arm784,arm_UI,arm786,arm_UI, // 788 - arm790,arm_UI,arm792,arm_UI,arm794,arm_UI,arm796,arm_UI, // 790 - arm790,arm_UI,arm792,arm_UI,arm794,arm_UI,arm796,arm_UI, // 798 - arm7A0,arm_UI,arm7A2,arm_UI,arm7A4,arm_UI,arm7A6,arm_UI, // 7A0 - arm7A0,arm_UI,arm7A2,arm_UI,arm7A4,arm_UI,arm7A6,arm_UI, // 7A8 - arm7B0,arm_UI,arm7B2,arm_UI,arm7B4,arm_UI,arm7B6,arm_UI, // 7B0 - arm7B0,arm_UI,arm7B2,arm_UI,arm7B4,arm_UI,arm7B6,arm_UI, // 7B8 - arm7C0,arm_UI,arm7C2,arm_UI,arm7C4,arm_UI,arm7C6,arm_UI, // 7C0 - arm7C0,arm_UI,arm7C2,arm_UI,arm7C4,arm_UI,arm7C6,arm_UI, // 7C8 - arm7D0,arm_UI,arm7D2,arm_UI,arm7D4,arm_UI,arm7D6,arm_UI, // 7D0 - arm7D0,arm_UI,arm7D2,arm_UI,arm7D4,arm_UI,arm7D6,arm_UI, // 7D8 - arm7E0,arm_UI,arm7E2,arm_UI,arm7E4,arm_UI,arm7E6,arm_UI, // 7E0 - arm7E0,arm_UI,arm7E2,arm_UI,arm7E4,arm_UI,arm7E6,arm_UI, // 7E8 - arm7F0,arm_UI,arm7F2,arm_UI,arm7F4,arm_UI,arm7F6,arm_UI, // 7F0 - arm7F0,arm_UI,arm7F2,arm_UI,arm7F4,arm_UI,arm7F6,arm_BP, // 7F8 - - REP16(arm800),REP16(arm810),REP16(arm820),REP16(arm830), // 800 - REP16(arm840),REP16(arm850),REP16(arm860),REP16(arm870), // 840 - REP16(arm880),REP16(arm890),REP16(arm8A0),REP16(arm8B0), // 880 - REP16(arm8C0),REP16(arm8D0),REP16(arm8E0),REP16(arm8F0), // 8C0 - REP16(arm900),REP16(arm910),REP16(arm920),REP16(arm930), // 900 - REP16(arm940),REP16(arm950),REP16(arm960),REP16(arm970), // 940 - REP16(arm980),REP16(arm990),REP16(arm9A0),REP16(arm9B0), // 980 - REP16(arm9C0),REP16(arm9D0),REP16(arm9E0),REP16(arm9F0), // 9C0 - - REP256(armA00), // A00 - REP256(armB00), // B00 - REP256(arm_UI), // C00 - REP256(arm_UI), // D00 - - arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E00 - arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E08 - arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E10 - arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E18 - REP16(arm_UI), // E20 - REP16(arm_UI), // E30 - REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // E40 - REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // E80 - REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // EC0 - - REP256(armF00), // F00 -}; - -// Wrapper routine (execution loop) /////////////////////////////////////// - -#include -static void tester(void) { - static int ran=0;if(ran)return;ran=1; - FILE*f=fopen("p:\\timing.txt","w");if(!f)return; - for (int op=/*0*/9; op> 28; - bool cond_res = true; - if (UNLIKELY(cond != 0x0E)) { // most opcodes are AL (always) - switch(cond) { - case 0x00: // EQ - cond_res = Z_FLAG; - break; - case 0x01: // NE - cond_res = !Z_FLAG; - break; - case 0x02: // CS - cond_res = C_FLAG; - break; - case 0x03: // CC - cond_res = !C_FLAG; - break; - case 0x04: // MI - cond_res = N_FLAG; - break; - case 0x05: // PL - cond_res = !N_FLAG; - break; - case 0x06: // VS - cond_res = V_FLAG; - break; - case 0x07: // VC - cond_res = !V_FLAG; - break; - case 0x08: // HI - cond_res = C_FLAG && !Z_FLAG; - break; - case 0x09: // LS - cond_res = !C_FLAG || Z_FLAG; - break; - case 0x0A: // GE - cond_res = N_FLAG == V_FLAG; - break; - case 0x0B: // LT - cond_res = N_FLAG != V_FLAG; - break; - case 0x0C: // GT - cond_res = !Z_FLAG &&(N_FLAG == V_FLAG); - break; - case 0x0D: // LE - cond_res = Z_FLAG || (N_FLAG != V_FLAG); - break; - case 0x0E: // AL (impossible, checked above) - cond_res = true; - break; - case 0x0F: - default: - // ??? - cond_res = false; - break; - } - } - - if (cond_res) - (*armInsnTable[((opcode>>16)&0xFF0) | ((opcode>>4)&0x0F)])(opcode); -#ifdef INSN_COUNTER - count(opcode, cond_res); -#endif - if (clockTicks < 0) - return 0; - if (clockTicks == 0) - clockTicks = 1 + codeTicksAccessSeq32(oldArmNextPC); - cpuTotalTicks += clockTicks; - - } while (cpuTotalTicks +#include +#include +#include +#include + +#include "GBA.h" +#include "GBAcpu.h" +#include "GBAinline.h" +#include "../Globals.h" +#include "../EEprom.h" +#include "../Flash.h" +#include "../Sound.h" +#include "../Sram.h" +#include "../bios.h" +#include "../Cheats.h" +#include "../NLS.h" +#include "../elf.h" +#include "../Util.h" +#include "../Port.h" +#include "../System.h" +#include "agbprint.h" +#ifdef PROFILING +#include "prof/prof.h" +#endif + +#ifdef _MSC_VER + // Disable "empty statement" warnings + #pragma warning(disable: 4390) + // Visual C's inline assembler treats "offset" as a reserved word, so we + // tell it otherwise. If you want to use it, write "OFFSET" in capitals. + #define offset offset_ +#endif + +/////////////////////////////////////////////////////////////////////////// + +static int clockTicks; + +static INSN_REGPARM void armUnknownInsn(u32 opcode) +{ +#ifdef GBA_LOGGING + if (systemVerbose & VERBOSE_UNDEFINED) { + log("Undefined ARM instruction %08x at %08x\n", opcode, + armNextPC-4); + } +#endif + CPUUndefinedException(); +} + +#ifdef BKPT_SUPPORT +static INSN_REGPARM void armBreakpoint(u32 opcode) +{ + reg[15].I -= 4; + armNextPC -= 4; + dbgSignal(5, (opcode & 0x0f) | ((opcode>>4) & 0xfff0)); + clockTicks = -1; +} +#endif + + +// Subroutine to count instructions (for debugging/optimizing) +//#define INSN_COUNTER // comment out if you don't want it +#ifdef INSN_COUNTER +static void count(u32 opcode, int cond_res) +{ + static int insncount = 0; // number of insns seen + static int executed = 0; // number of insns executed + static int mergewith[4096]; // map instructions to routines + static int count[4096]; // count of each 12-bit code + int index = ((opcode>>16)&0xFF0) | ((opcode>>4)&0x0F); + static FILE *outfile = NULL; + + if (!insncount) { + for (int i = 0; i < 4096; i++) { + for (int j = 0; j < i; j++) { + if (armInsnTable[i] == armInsnTable[j]) + break; + } + mergewith[i] = j; + } + outfile = fopen("VBA-armcount.txt", "w"); + } + if (cond_res) { + count[mergewith[index]]++; + executed++; + } + insncount++; + if (outfile && insncount%1000000 == 0) { + fprintf(outfile, "Total instructions: %d\n", insncount); + fprintf(outfile, "Instructions executed: %d\n", executed); + for (int i = 0; i < 4096; i++) { + if (count[i]) + fprintf(outfile, "arm%03X: %d\n", i, count[i]); + } + } +} +#endif + +// Common macros ////////////////////////////////////////////////////////// + +#ifdef BKPT_SUPPORT +#define CONSOLE_OUTPUT(a,b) do { \ + if ((opcode == 0xe0000000) && (reg[0].I == 0xC0DED00D)) { \ + dbgOutput((a), (b)); \ +} while (0) +#else +#define CONSOLE_OUTPUT(a,b) /* nothing */ +#endif + +#define NEG(i) ((i) >> 31) +#define POS(i) ((~(i)) >> 31) + +// The following macros are used for optimization; any not defined for a +// particular compiler/CPU combination default to the C core versions. +// +// ALU_INIT_C: Used at the beginning of ALU instructions (AND/EOR/...). +// (ALU_INIT_NC) Can consist of variable declarations, like the C core, +// or the start of a continued assembly block, like the +// x86-optimized version. The _C version is used when the +// carry flag from the shift operation is needed (logical +// operations that set condition codes, like ANDS); the +// _NC version is used when the carry result is ignored. +// VALUE_XXX: Retrieve the second operand's value for an ALU instruction. +// The _C and _NC versions are used the same way as ALU_INIT. +// OP_XXX: ALU operations. XXX is the instruction name. +// ALU_FINISH: Appended to all ALU instructions. Usually empty, but if +// ALU_INIT started a block ALU_FINISH can be used to end it +// (as with the asm(...) statement in the x86 core). +// SETCOND_NONE: Used in multiply instructions in place of SETCOND_MUL +// when the condition codes are not set. Usually empty. +// SETCOND_MUL: Used in multiply instructions to set the condition codes. +// ROR_IMM_MSR: Used to rotate the immediate operand for MSR. +// ROR_OFFSET: Used to rotate the `offset' parameter for LDR and STR +// instructions. +// RRX_OFFSET: Used to rotate (RRX) the `offset' parameter for LDR and +// STR instructions. + +#ifndef C_CORE + +#if 0 // definitions have changed +//#ifdef __POWERPC__ + #define OP_SUBS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_RSBS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subfco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_ADDS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("addco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_ADCS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("mtspr xer, %4\n" \ + "addeo. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value), \ + "r" (C_FLAG << 29) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_SBCS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("mtspr xer, %4\n" \ + "subfeo. %0, %3, %2\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value), \ + "r" (C_FLAG << 29) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_RSCS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("mtspr xer, %4\n" \ + "subfeo. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value), \ + "r" (C_FLAG << 29) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_CMP \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value) \ + ); \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_CMN \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("addco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value) \ + ); \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + +#else // !__POWERPC__ + +// Macros to emit instructions in the format used by the particular compiler. +// We use GNU assembler syntax: "op src, dest" rather than "op dest, src" + +#ifdef __GNUC__ + #define ALU_HEADER asm("mov %%ecx, %%edi; " + #define ALU_TRAILER : "=D" (opcode) : "c" (opcode) : "eax", "ebx", "edx", "esi") + #define EMIT0(op) #op"; " + #define EMIT1(op,arg) #op" "arg"; " + #define EMIT2(op,src,dest) #op" "src", "dest"; " + #define CONST(val) "$"#val + #define VAR(var) "_"#var + #define VARL(var) "_"#var + #define REGREF1(index) "_reg("index")" + #define REGREF2(index,scale) "_reg(,"index","#scale")" + #define LABEL(n) #n": " + #define LABELREF(n,dir) #n#dir + #define al "%%al" + #define ah "%%ah" + #define eax "%%eax" + #define bl "%%bl" + #define bh "%%bh" + #define ebx "%%ebx" + #define cl "%%cl" + #define ch "%%ch" + #define ecx "%%ecx" + #define dl "%%dl" + #define dh "%%dh" + #define edx "%%edx" + #define esp "%%esp" + #define ebp "%%ebp" + #define esi "%%esi" + #define edi "%%edi" + #define movzx movzb +#else + #define ALU_HEADER __asm { __asm mov ecx, opcode + #define ALU_TRAILER } + #define EMIT0(op) __asm op + #define EMIT1(op,arg) __asm op arg + #define EMIT2(op,src,dest) __asm op dest, src + #define CONST(val) val + #define VAR(var) var + #define VARL(var) dword ptr var + #define REGREF1(index) reg[index] + #define REGREF2(index,scale) reg[index*scale] + #define LABEL(n) __asm l##n: + #define LABELREF(n,dir) l##n +#endif + +//X//#ifndef _MSC_VER +// ALU op register usage: +// EAX -> 2nd operand value, result (RSB/RSC) +// EBX -> C_OUT (carry flag from shift/rotate) +// ECX -> opcode (input), shift/rotate count +// EDX -> Rn (base) value, result (all except RSB/RSC) +// ESI -> Rd (destination) index * 4 + +// Helper macros for loading value / shift count +#define VALUE_LOAD_IMM \ + EMIT2(and, CONST(0x0F), eax) \ + EMIT2(mov, REGREF2(eax,4), eax) \ + EMIT2(shr, CONST(7), ecx) \ + EMIT2(and, CONST(0x1F), ecx) +#define VALUE_LOAD_REG \ + EMIT2(and, CONST(0x0F), eax) \ + EMIT2(mov, REGREF2(eax,4), eax) \ + EMIT2(movzx, ch, ecx) \ + EMIT2(and, CONST(0x0F), ecx) \ + EMIT2(mov, REGREF2(ecx,4), ecx) + +// Helper macros for setting flags +#define SETCOND_LOGICAL \ + EMIT1(sets, VAR(N_FLAG)) \ + EMIT1(setz, VAR(Z_FLAG)) \ + EMIT2(mov, bl, VAR(C_FLAG)) +#define SETCOND_ADD \ + EMIT1(sets, VAR(N_FLAG)) \ + EMIT1(setz, VAR(Z_FLAG)) \ + EMIT1(seto, VAR(V_FLAG)) \ + EMIT1(setc, VAR(C_FLAG)) +#define SETCOND_SUB \ + EMIT1(sets, VAR(N_FLAG)) \ + EMIT1(setz, VAR(Z_FLAG)) \ + EMIT1(seto, VAR(V_FLAG)) \ + EMIT1(setnc, VAR(C_FLAG)) + +// ALU initialization +#define ALU_INIT(LOAD_C_FLAG) \ + ALU_HEADER \ + LOAD_C_FLAG \ + EMIT2(mov, ecx, edx) \ + EMIT2(shr, CONST(14), edx) \ + EMIT2(mov, ecx, eax) \ + EMIT2(mov, ecx, esi) \ + EMIT2(shr, CONST(10), esi) \ + EMIT2(and, CONST(0x3C), edx) \ + EMIT2(mov, REGREF1(edx), edx) \ + EMIT2(and, CONST(0x3C), esi) + +#define LOAD_C_FLAG_YES EMIT2(mov, VAR(C_FLAG), bl) +#define LOAD_C_FLAG_NO /*nothing*/ +#define ALU_INIT_C ALU_INIT(LOAD_C_FLAG_YES) +#define ALU_INIT_NC ALU_INIT(LOAD_C_FLAG_NO) + +// Macros to load the value operand for an ALU op; these all set N/Z +// according to the value + +// OP Rd,Rb,Rm LSL # +#define VALUE_LSL_IMM_C \ + VALUE_LOAD_IMM \ + EMIT1(jnz, LABELREF(1,f)) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(shl, cl, eax) \ + EMIT1(setc, bl) \ + LABEL(0) +#define VALUE_LSL_IMM_NC \ + VALUE_LOAD_IMM \ + EMIT2(shl, cl, eax) + +// OP Rd,Rb,Rm LSL Rs +#define VALUE_LSL_REG_C \ + VALUE_LOAD_REG \ + EMIT2(test, cl, cl) \ + EMIT1(jz, LABELREF(0,f)) \ + EMIT2(cmp, CONST(0x20), cl) \ + EMIT1(je, LABELREF(1,f)) \ + EMIT1(ja, LABELREF(2,f)) \ + EMIT2(shl, cl, eax) \ + EMIT1(setc, bl) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(test, CONST(1), al) \ + EMIT1(setnz, bl) \ + EMIT2(xor, eax, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(2) \ + EMIT2(xor, ebx, ebx) \ + EMIT2(xor, eax, eax) \ + LABEL(0) +#define VALUE_LSL_REG_NC \ + VALUE_LOAD_REG \ + EMIT2(cmp, CONST(0x20), cl) \ + EMIT1(jae, LABELREF(1,f)) \ + EMIT2(shl, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(xor, eax, eax) \ + LABEL(0) + +// OP Rd,Rb,Rm LSR # +#define VALUE_LSR_IMM_C \ + VALUE_LOAD_IMM \ + EMIT1(jz, LABELREF(1,f)) \ + EMIT2(shr, cl, eax) \ + EMIT1(setc, bl) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(test, eax, eax) \ + EMIT1(sets, bl) \ + EMIT2(xor, eax, eax) \ + LABEL(0) +#define VALUE_LSR_IMM_NC \ + VALUE_LOAD_IMM \ + EMIT1(jz, LABELREF(1,f)) \ + EMIT2(shr, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(xor, eax, eax) \ + LABEL(0) + +// OP Rd,Rb,Rm LSR Rs +#define VALUE_LSR_REG_C \ + VALUE_LOAD_REG \ + EMIT2(test, cl, cl) \ + EMIT1(jz, LABELREF(0,f)) \ + EMIT2(cmp, CONST(0x20), cl) \ + EMIT1(je, LABELREF(1,f)) \ + EMIT1(ja, LABELREF(2,f)) \ + EMIT2(shr, cl, eax) \ + EMIT1(setc, bl) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(test, eax, eax) \ + EMIT1(sets, bl) \ + EMIT2(xor, eax, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(2) \ + EMIT2(xor, ebx, ebx) \ + EMIT2(xor, eax, eax) \ + LABEL(0) +#define VALUE_LSR_REG_NC \ + VALUE_LOAD_REG \ + EMIT2(cmp, CONST(0x20), cl) \ + EMIT1(jae, LABELREF(1,f)) \ + EMIT2(shr, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(xor, eax, eax) \ + LABEL(0) + +// OP Rd,Rb,Rm ASR # +#define VALUE_ASR_IMM_C \ + VALUE_LOAD_IMM \ + EMIT1(jz, LABELREF(1,f)) \ + EMIT2(sar, cl, eax) \ + EMIT1(setc, bl) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(sar, CONST(31), eax) \ + EMIT1(sets, bl) \ + LABEL(0) +#define VALUE_ASR_IMM_NC \ + VALUE_LOAD_IMM \ + EMIT1(jz, LABELREF(1,f)) \ + EMIT2(sar, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(sar, CONST(31), eax) \ + LABEL(0) + +// OP Rd,Rb,Rm ASR Rs +#define VALUE_ASR_REG_C \ + VALUE_LOAD_REG \ + EMIT2(test, cl, cl) \ + EMIT1(jz, LABELREF(0,f)) \ + EMIT2(cmp, CONST(0x20), cl) \ + EMIT1(jae, LABELREF(1,f)) \ + EMIT2(sar, cl, eax) \ + EMIT1(setc, bl) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(sar, CONST(31), eax) \ + EMIT1(sets, bl) \ + LABEL(0) +#define VALUE_ASR_REG_NC \ + VALUE_LOAD_REG \ + EMIT2(cmp, CONST(0x20), cl) \ + EMIT1(jae, LABELREF(1,f)) \ + EMIT2(sar, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(sar, CONST(31), eax) \ + LABEL(0) + +// OP Rd,Rb,Rm ROR # +#define VALUE_ROR_IMM_C \ + VALUE_LOAD_IMM \ + EMIT1(jz, LABELREF(1,f)) \ + EMIT2(ror, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(bt, CONST(0), ebx) \ + EMIT2(rcr, CONST(1), eax) \ + LABEL(0) \ + EMIT1(setc, bl) +#define VALUE_ROR_IMM_NC \ + VALUE_LOAD_IMM \ + EMIT1(jz, LABELREF(1,f)) \ + EMIT2(ror, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(bt, CONST(0), VARL(C_FLAG)) \ + EMIT2(rcr, CONST(1), eax) \ + LABEL(0) + +// OP Rd,Rb,Rm ROR Rs +#define VALUE_ROR_REG_C \ + VALUE_LOAD_REG \ + EMIT2(bt, CONST(0), ebx) \ + EMIT2(ror, cl, eax) \ + EMIT1(setc, bl) +#define VALUE_ROR_REG_NC \ + VALUE_LOAD_REG \ + EMIT2(ror, cl, eax) + +// OP Rd,Rb,# ROR # +#define VALUE_IMM_C \ + EMIT2(movzx, ch, ecx) \ + EMIT2(add, ecx, ecx) \ + EMIT2(movzx, al, eax) \ + EMIT2(bt, CONST(0), ebx) \ + EMIT2(ror, cl, eax) \ + EMIT1(setc, bl) +#define VALUE_IMM_NC \ + EMIT2(movzx, ch, ecx) \ + EMIT2(add, ecx, ecx) \ + EMIT2(movzx, al, eax) \ + EMIT2(ror, cl, eax) + +// Macros to perform ALU ops + +// Set condition codes iff the destination register is not R15 (PC) +#define CHECK_PC(OP, SETCOND) \ + EMIT2(cmp, CONST(0x3C), esi) \ + EMIT1(je, LABELREF(8,f)) \ + OP SETCOND \ + EMIT1(jmp, LABELREF(9,f)) \ + LABEL(8) \ + OP \ + LABEL(9) + +#define OP_AND \ + EMIT2(and, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_ANDS CHECK_PC(OP_AND, SETCOND_LOGICAL) +#define OP_EOR \ + EMIT2(xor, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_EORS CHECK_PC(OP_EOR, SETCOND_LOGICAL) +#define OP_SUB \ + EMIT2(sub, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_SUBS CHECK_PC(OP_SUB, SETCOND_SUB) +#define OP_RSB \ + EMIT2(sub, edx, eax) \ + EMIT2(mov, eax, REGREF1(esi)) +#define OP_RSBS CHECK_PC(OP_RSB, SETCOND_SUB) +#define OP_ADD \ + EMIT2(add, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_ADDS CHECK_PC(OP_ADD, SETCOND_ADD) +#define OP_ADC \ + EMIT2(bt, CONST(0), VARL(C_FLAG)) \ + EMIT2(adc, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_ADCS CHECK_PC(OP_ADC, SETCOND_ADD) +#define OP_SBC \ + EMIT2(bt, CONST(0), VARL(C_FLAG)) \ + EMIT0(cmc) \ + EMIT2(sbb, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_SBCS CHECK_PC(OP_SBC, SETCOND_SUB) +#define OP_RSC \ + EMIT2(bt, CONST(0), VARL(C_FLAG)) \ + EMIT0(cmc) \ + EMIT2(sbb, edx, eax) \ + EMIT2(mov, eax, REGREF1(esi)) +#define OP_RSCS CHECK_PC(OP_RSC, SETCOND_SUB) +#define OP_TST \ + EMIT2(and, eax, edx) \ + SETCOND_LOGICAL +#define OP_TEQ \ + EMIT2(xor, eax, edx) \ + SETCOND_LOGICAL +#define OP_CMP \ + EMIT2(sub, eax, edx) \ + SETCOND_SUB +#define OP_CMN \ + EMIT2(add, eax, edx) \ + SETCOND_ADD +#define OP_ORR \ + EMIT2(or, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_ORRS CHECK_PC(OP_ORR, SETCOND_LOGICAL) +#define OP_MOV \ + EMIT2(mov, eax, REGREF1(esi)) +#define OP_MOVS CHECK_PC(EMIT2(test,eax,eax) EMIT2(mov,eax,REGREF1(esi)), SETCOND_LOGICAL) +#define OP_BIC \ + EMIT1(not, eax) \ + EMIT2(and, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_BICS CHECK_PC(OP_BIC, SETCOND_LOGICAL) +#define OP_MVN \ + EMIT1(not, eax) \ + EMIT2(mov, eax, REGREF1(esi)) +#define OP_MVNS CHECK_PC(OP_MVN, SETCOND_LOGICAL) + +// ALU cleanup macro +#define ALU_FINISH ALU_TRAILER + +// End of ALU macros +//X//#endif //_MSC_VER + +#ifdef __GNUC__ + +#define ROR_IMM_MSR \ + asm ("ror %%cl, %%eax;" \ + : "=a" (value) \ + : "a" (opcode & 0xFF), "c" (shift)); + +#define ROR_OFFSET \ + asm("ror %%cl, %0" \ + : "=r" (offset) \ + : "0" (offset), "c" (shift)); + +#define RRX_OFFSET \ + asm("btl $0, _C_FLAG;" \ + "rcr $1, %0" \ + : "=r" (offset) \ + : "0" (offset)); + +#else // !__GNUC__, i.e. Visual C++ + +#define ROR_IMM_MSR \ + __asm { \ + __asm mov ecx, shift \ + __asm ror value, cl \ + } + + +#define ROR_OFFSET \ + __asm { \ + __asm mov ecx, shift \ + __asm ror offset, cl \ + } + +#define RRX_OFFSET \ + __asm { \ + __asm bt dword ptr C_FLAG, 0 \ + __asm rcr offset, 1 \ + } + +#endif // !__GNUC__ + +#endif // !__POWERPC__ +#endif // !C_CORE + +// C core + +#define C_SETCOND_LOGICAL \ + N_FLAG = ((s32)res < 0) ? true : false; \ + Z_FLAG = (res == 0) ? true : false; \ + C_FLAG = C_OUT; +#define C_SETCOND_ADD \ + N_FLAG = ((s32)res < 0) ? true : false; \ + Z_FLAG = (res == 0) ? true : false; \ + V_FLAG = ((NEG(lhs) & NEG(rhs) & POS(res)) | \ + (POS(lhs) & POS(rhs) & NEG(res))) ? true : false;\ + C_FLAG = ((NEG(lhs) & NEG(rhs)) | \ + (NEG(lhs) & POS(res)) | \ + (NEG(rhs) & POS(res))) ? true : false; +#define C_SETCOND_SUB \ + N_FLAG = ((s32)res < 0) ? true : false; \ + Z_FLAG = (res == 0) ? true : false; \ + V_FLAG = ((NEG(lhs) & POS(rhs) & POS(res)) | \ + (POS(lhs) & NEG(rhs) & NEG(res))) ? true : false;\ + C_FLAG = ((NEG(lhs) & POS(rhs)) | \ + (NEG(lhs) & POS(res)) | \ + (POS(rhs) & POS(res))) ? true : false; + +#ifndef ALU_INIT_C + #define ALU_INIT_C \ + int dest = (opcode>>12) & 15; \ + bool C_OUT = C_FLAG; \ + u32 value; +#endif +// OP Rd,Rb,Rm LSL # +#ifndef VALUE_LSL_IMM_C + #define VALUE_LSL_IMM_C \ + unsigned int shift = (opcode >> 7) & 0x1F; \ + if (LIKELY(!shift)) { /* LSL #0 most common? */ \ + value = reg[opcode & 0x0F].I; \ + } else { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (32 - shift)) & 1 ? true : false; \ + value = v << shift; \ + } +#endif +// OP Rd,Rb,Rm LSL Rs +#ifndef VALUE_LSL_REG_C + #define VALUE_LSL_REG_C \ + unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ + if (LIKELY(shift)) { \ + if (shift == 32) { \ + value = 0; \ + C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false);\ + } else if (LIKELY(shift < 32)) { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (32 - shift)) & 1 ? true : false;\ + value = v << shift; \ + } else { \ + value = 0; \ + C_OUT = false; \ + } \ + } else { \ + value = reg[opcode & 0x0F].I; \ + } +#endif +// OP Rd,Rb,Rm LSR # +#ifndef VALUE_LSR_IMM_C + #define VALUE_LSR_IMM_C \ + unsigned int shift = (opcode >> 7) & 0x1F; \ + if (LIKELY(shift)) { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ + value = v >> shift; \ + } else { \ + value = 0; \ + C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false;\ + } +#endif +// OP Rd,Rb,Rm LSR Rs +#ifndef VALUE_LSR_REG_C + #define VALUE_LSR_REG_C \ + unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ + if (LIKELY(shift)) { \ + if (shift == 32) { \ + value = 0; \ + C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false);\ + } else if (LIKELY(shift < 32)) { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (shift - 1)) & 1 ? true : false;\ + value = v >> shift; \ + } else { \ + value = 0; \ + C_OUT = false; \ + } \ + } else { \ + value = reg[opcode & 0x0F].I; \ + } +#endif +// OP Rd,Rb,Rm ASR # +#ifndef VALUE_ASR_IMM_C + #define VALUE_ASR_IMM_C \ + unsigned int shift = (opcode >> 7) & 0x1F; \ + if (LIKELY(shift)) { \ + /* VC++ BUG: u32 v; (s32)v>>n is optimized to shr! */ \ + s32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\ + value = v >> (int)shift; \ + } else { \ + if (reg[opcode & 0x0F].I & 0x80000000) { \ + value = 0xFFFFFFFF; \ + C_OUT = true; \ + } else { \ + value = 0; \ + C_OUT = false; \ + } \ + } +#endif +// OP Rd,Rb,Rm ASR Rs +#ifndef VALUE_ASR_REG_C + #define VALUE_ASR_REG_C \ + unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ + if (LIKELY(shift < 32)) { \ + if (LIKELY(shift)) { \ + s32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\ + value = v >> (int)shift; \ + } else { \ + value = reg[opcode & 0x0F].I; \ + } \ + } else { \ + if (reg[opcode & 0x0F].I & 0x80000000) { \ + value = 0xFFFFFFFF; \ + C_OUT = true; \ + } else { \ + value = 0; \ + C_OUT = false; \ + } \ + } +#endif +// OP Rd,Rb,Rm ROR # +#ifndef VALUE_ROR_IMM_C + #define VALUE_ROR_IMM_C \ + unsigned int shift = (opcode >> 7) & 0x1F; \ + if (LIKELY(shift)) { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ + value = ((v << (32 - shift)) | \ + (v >> shift)); \ + } else { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v & 1) ? true : false; \ + value = ((v >> 1) | \ + (C_FLAG << 31)); \ + } +#endif +// OP Rd,Rb,Rm ROR Rs +#ifndef VALUE_ROR_REG_C + #define VALUE_ROR_REG_C \ + unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ + if (LIKELY(shift & 0x1F)) { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ + value = ((v << (32 - shift)) | \ + (v >> shift)); \ + } else { \ + value = reg[opcode & 0x0F].I; \ + if (shift) \ + C_OUT = (value & 0x80000000 ? true : false);\ + } +#endif +// OP Rd,Rb,# ROR # +#ifndef VALUE_IMM_C + #define VALUE_IMM_C \ + int shift = (opcode & 0xF00) >> 7; \ + if (UNLIKELY(shift)) { \ + u32 v = opcode & 0xFF; \ + C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ + value = ((v << (32 - shift)) | \ + (v >> shift)); \ + } else { \ + value = opcode & 0xFF; \ + } +#endif + +// Make the non-carry versions default to the carry versions +// (this is fine for C--the compiler will optimize the dead code out) +#ifndef ALU_INIT_NC + #define ALU_INIT_NC ALU_INIT_C +#endif +#ifndef VALUE_LSL_IMM_NC + #define VALUE_LSL_IMM_NC VALUE_LSL_IMM_C +#endif +#ifndef VALUE_LSL_REG_NC + #define VALUE_LSL_REG_NC VALUE_LSL_REG_C +#endif +#ifndef VALUE_LSR_IMM_NC + #define VALUE_LSR_IMM_NC VALUE_LSR_IMM_C +#endif +#ifndef VALUE_LSR_REG_NC + #define VALUE_LSR_REG_NC VALUE_LSR_REG_C +#endif +#ifndef VALUE_ASR_IMM_NC + #define VALUE_ASR_IMM_NC VALUE_ASR_IMM_C +#endif +#ifndef VALUE_ASR_REG_NC + #define VALUE_ASR_REG_NC VALUE_ASR_REG_C +#endif +#ifndef VALUE_ROR_IMM_NC + #define VALUE_ROR_IMM_NC VALUE_ROR_IMM_C +#endif +#ifndef VALUE_ROR_REG_NC + #define VALUE_ROR_REG_NC VALUE_ROR_REG_C +#endif +#ifndef VALUE_IMM_NC + #define VALUE_IMM_NC VALUE_IMM_C +#endif + +#define C_CHECK_PC(SETCOND) if (LIKELY(dest != 15)) { SETCOND } +#ifndef OP_AND + #define OP_AND \ + u32 res = reg[(opcode>>16)&15].I & value; \ + reg[dest].I = res; +#endif +#ifndef OP_ANDS + #define OP_ANDS OP_AND C_CHECK_PC(C_SETCOND_LOGICAL) +#endif +#ifndef OP_EOR + #define OP_EOR \ + u32 res = reg[(opcode>>16)&15].I ^ value; \ + reg[dest].I = res; +#endif +#ifndef OP_EORS + #define OP_EORS OP_EOR C_CHECK_PC(C_SETCOND_LOGICAL) +#endif +#ifndef OP_SUB + #define OP_SUB \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = lhs - rhs; \ + reg[dest].I = res; +#endif +#ifndef OP_SUBS + #define OP_SUBS OP_SUB C_CHECK_PC(C_SETCOND_SUB) +#endif +#ifndef OP_RSB + #define OP_RSB \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = rhs - lhs; \ + reg[dest].I = res; +#endif +#ifndef OP_RSBS + #define OP_RSBS OP_RSB C_CHECK_PC(C_SETCOND_SUB) +#endif +#ifndef OP_ADD + #define OP_ADD \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = lhs + rhs; \ + reg[dest].I = res; +#endif +#ifndef OP_ADDS + #define OP_ADDS OP_ADD C_CHECK_PC(C_SETCOND_ADD) +#endif +#ifndef OP_ADC + #define OP_ADC \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = lhs + rhs + (u32)C_FLAG; \ + reg[dest].I = res; +#endif +#ifndef OP_ADCS + #define OP_ADCS OP_ADC C_CHECK_PC(C_SETCOND_ADD) +#endif +#ifndef OP_SBC + #define OP_SBC \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = lhs - rhs - !((u32)C_FLAG); \ + reg[dest].I = res; +#endif +#ifndef OP_SBCS + #define OP_SBCS OP_SBC C_CHECK_PC(C_SETCOND_SUB) +#endif +#ifndef OP_RSC + #define OP_RSC \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = rhs - lhs - !((u32)C_FLAG); \ + reg[dest].I = res; +#endif +#ifndef OP_RSCS + #define OP_RSCS OP_RSC C_CHECK_PC(C_SETCOND_SUB) +#endif +#ifndef OP_TST + #define OP_TST \ + u32 res = reg[(opcode >> 16) & 0x0F].I & value; \ + C_SETCOND_LOGICAL; +#endif +#ifndef OP_TEQ + #define OP_TEQ \ + u32 res = reg[(opcode >> 16) & 0x0F].I ^ value; \ + C_SETCOND_LOGICAL; +#endif +#ifndef OP_CMP + #define OP_CMP \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = lhs - rhs; \ + C_SETCOND_SUB; +#endif +#ifndef OP_CMN + #define OP_CMN \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = lhs + rhs; \ + C_SETCOND_ADD; +#endif +#ifndef OP_ORR + #define OP_ORR \ + u32 res = reg[(opcode >> 16) & 0x0F].I | value; \ + reg[dest].I = res; +#endif +#ifndef OP_ORRS + #define OP_ORRS OP_ORR C_CHECK_PC(C_SETCOND_LOGICAL) +#endif +#ifndef OP_MOV + #define OP_MOV \ + u32 res = value; \ + reg[dest].I = res; +#endif +#ifndef OP_MOVS + #define OP_MOVS OP_MOV C_CHECK_PC(C_SETCOND_LOGICAL) +#endif +#ifndef OP_BIC + #define OP_BIC \ + u32 res = reg[(opcode >> 16) & 0x0F].I & (~value); \ + reg[dest].I = res; +#endif +#ifndef OP_BICS + #define OP_BICS OP_BIC C_CHECK_PC(C_SETCOND_LOGICAL) +#endif +#ifndef OP_MVN + #define OP_MVN \ + u32 res = ~value; \ + reg[dest].I = res; +#endif +#ifndef OP_MVNS + #define OP_MVNS OP_MVN C_CHECK_PC(C_SETCOND_LOGICAL) +#endif + +#ifndef SETCOND_NONE + #define SETCOND_NONE /*nothing*/ +#endif +#ifndef SETCOND_MUL + #define SETCOND_MUL \ + N_FLAG = ((s32)reg[dest].I < 0) ? true : false; \ + Z_FLAG = reg[dest].I ? false : true; +#endif +#ifndef SETCOND_MULL + #define SETCOND_MULL \ + N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\ + Z_FLAG = reg[dest].I || reg[acc].I ? false : true; +#endif + +#ifndef ALU_FINISH + #define ALU_FINISH /*nothing*/ +#endif + +#ifndef ROR_IMM_MSR + #define ROR_IMM_MSR \ + u32 v = opcode & 0xff; \ + value = ((v << (32 - shift)) | (v >> shift)); +#endif +#ifndef ROR_OFFSET + #define ROR_OFFSET \ + offset = ((offset << (32 - shift)) | (offset >> shift)); +#endif +#ifndef RRX_OFFSET + #define RRX_OFFSET \ + offset = ((offset >> 1) | ((int)C_FLAG << 31)); +#endif + +// ALU ops (except multiply) ////////////////////////////////////////////// + +// ALU_INIT: init code (ALU_INIT_C or ALU_INIT_NC) +// GETVALUE: load value and shift/rotate (VALUE_XXX) +// OP: ALU operation (OP_XXX) +// MODECHANGE: MODECHANGE_NO or MODECHANGE_YES +// ISREGSHIFT: 1 for insns of the form ...,Rn LSL/etc Rs; 0 otherwise +// ALU_INIT, GETVALUE, OP, and ALU_FINISH are concatenated in order. +#define ALU_INSN(ALU_INIT, GETVALUE, OP, MODECHANGE, ISREGSHIFT) \ + ALU_INIT GETVALUE OP ALU_FINISH; \ + if (LIKELY((opcode & 0x0000F000) != 0x0000F000)) { \ + clockTicks = 1 + ISREGSHIFT \ + + codeTicksAccessSeq32(armNextPC); \ + } else { \ + MODECHANGE; \ + if (armState) { \ + reg[15].I &= 0xFFFFFFFC; \ + armNextPC = reg[15].I; \ + reg[15].I += 4; \ + ARM_PREFETCH; \ + } else { \ + reg[15].I &= 0xFFFFFFFE; \ + armNextPC = reg[15].I; \ + reg[15].I += 2; \ + THUMB_PREFETCH; \ + } \ + clockTicks = 3 + ISREGSHIFT \ + + codeTicksAccess32(armNextPC) \ + + codeTicksAccessSeq32(armNextPC) \ + + codeTicksAccessSeq32(armNextPC); \ + } + +#define MODECHANGE_NO /*nothing*/ +#define MODECHANGE_YES CPUSwitchMode(reg[17].I & 0x1f, false); + +#define DEFINE_ALU_INSN_C(CODE1, CODE2, OP, MODECHANGE) \ + static INSN_REGPARM void arm##CODE1##0(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSL_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##1(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSL_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE1##2(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##3(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE1##4(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ASR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##5(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ASR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE1##6(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ROR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##7(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ROR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE2##0(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); } +#define DEFINE_ALU_INSN_NC(CODE1, CODE2, OP, MODECHANGE) \ + static INSN_REGPARM void arm##CODE1##0(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSL_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##1(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSL_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE1##2(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##3(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE1##4(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ASR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##5(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ASR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE1##6(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ROR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##7(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ROR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE2##0(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); } + +// AND +DEFINE_ALU_INSN_NC(00, 20, AND, NO) +// ANDS +DEFINE_ALU_INSN_C (01, 21, ANDS, YES) + +// EOR +DEFINE_ALU_INSN_NC(02, 22, EOR, NO) +// EORS +DEFINE_ALU_INSN_C (03, 23, EORS, YES) + +// SUB +DEFINE_ALU_INSN_NC(04, 24, SUB, NO) +// SUBS +DEFINE_ALU_INSN_NC(05, 25, SUBS, YES) + +// RSB +DEFINE_ALU_INSN_NC(06, 26, RSB, NO) +// RSBS +DEFINE_ALU_INSN_NC(07, 27, RSBS, YES) + +// ADD +DEFINE_ALU_INSN_NC(08, 28, ADD, NO) +// ADDS +DEFINE_ALU_INSN_NC(09, 29, ADDS, YES) + +// ADC +DEFINE_ALU_INSN_NC(0A, 2A, ADC, NO) +// ADCS +DEFINE_ALU_INSN_NC(0B, 2B, ADCS, YES) + +// SBC +DEFINE_ALU_INSN_NC(0C, 2C, SBC, NO) +// SBCS +DEFINE_ALU_INSN_NC(0D, 2D, SBCS, YES) + +// RSC +DEFINE_ALU_INSN_NC(0E, 2E, RSC, NO) +// RSCS +DEFINE_ALU_INSN_NC(0F, 2F, RSCS, YES) + +// TST +DEFINE_ALU_INSN_C (11, 31, TST, NO) + +// TEQ +DEFINE_ALU_INSN_C (13, 33, TEQ, NO) + +// CMP +DEFINE_ALU_INSN_NC(15, 35, CMP, NO) + +// CMN +DEFINE_ALU_INSN_NC(17, 37, CMN, NO) + +// ORR +DEFINE_ALU_INSN_NC(18, 38, ORR, NO) +// ORRS +DEFINE_ALU_INSN_C (19, 39, ORRS, YES) + +// MOV +DEFINE_ALU_INSN_NC(1A, 3A, MOV, NO) +// MOVS +DEFINE_ALU_INSN_C (1B, 3B, MOVS, YES) + +// BIC +DEFINE_ALU_INSN_NC(1C, 3C, BIC, NO) +// BICS +DEFINE_ALU_INSN_C (1D, 3D, BICS, YES) + +// MVN +DEFINE_ALU_INSN_NC(1E, 3E, MVN, NO) +// MVNS +DEFINE_ALU_INSN_C (1F, 3F, MVNS, YES) + +// Multiply instructions ////////////////////////////////////////////////// + +// OP: OP_MUL, OP_MLA etc. +// SETCOND: SETCOND_NONE, SETCOND_MUL, or SETCOND_MULL +// CYCLES: base cycle count (1, 2, or 3) +#define MUL_INSN(OP, SETCOND, CYCLES) \ + int mult = (opcode & 0x0F); \ + u32 rs = reg[(opcode >> 8) & 0x0F].I; \ + int acc = (opcode >> 12) & 0x0F; /* or destLo */ \ + int dest = (opcode >> 16) & 0x0F; /* or destHi */ \ + OP; \ + SETCOND; \ + if ((s32)rs < 0) \ + rs = ~rs; \ + if ((rs & 0xFFFFFF00) == 0) \ + clockTicks += 0; \ + else if ((rs & 0xFFFF0000) == 0) \ + clockTicks += 1; \ + else if ((rs & 0xFF000000) == 0) \ + clockTicks += 2; \ + else \ + clockTicks += 3; \ + if (busPrefetchCount == 0) \ + busPrefetchCount = ((busPrefetchCount+1)<> 32); +#define OP_MLAL(SIGN) \ + SIGN##64 res = ((SIGN##64)reg[dest].I<<32 | reg[acc].I)\ + + ((SIGN##64)(SIGN##32)reg[mult].I \ + * (SIGN##64)(SIGN##32)rs); \ + reg[acc].I = (u32)res; \ + reg[dest].I = (u32)(res >> 32); +#define OP_UMULL OP_MULL(u) +#define OP_UMLAL OP_MLAL(u) +#define OP_SMULL OP_MULL(s) +#define OP_SMLAL OP_MLAL(s) + +// MUL Rd, Rm, Rs +static INSN_REGPARM void arm009(u32 opcode) { MUL_INSN(OP_MUL, SETCOND_NONE, 1); } +// MULS Rd, Rm, Rs +static INSN_REGPARM void arm019(u32 opcode) { MUL_INSN(OP_MUL, SETCOND_MUL, 1); } + +// MLA Rd, Rm, Rs, Rn +static INSN_REGPARM void arm029(u32 opcode) { MUL_INSN(OP_MLA, SETCOND_NONE, 2); } +// MLAS Rd, Rm, Rs, Rn +static INSN_REGPARM void arm039(u32 opcode) { MUL_INSN(OP_MLA, SETCOND_MUL, 2); } + +// UMULL RdLo, RdHi, Rn, Rs +static INSN_REGPARM void arm089(u32 opcode) { MUL_INSN(OP_UMULL, SETCOND_NONE, 2); } +// UMULLS RdLo, RdHi, Rn, Rs +static INSN_REGPARM void arm099(u32 opcode) { MUL_INSN(OP_UMULL, SETCOND_MULL, 2); } + +// UMLAL RdLo, RdHi, Rn, Rs +static INSN_REGPARM void arm0A9(u32 opcode) { MUL_INSN(OP_UMLAL, SETCOND_NONE, 3); } +// UMLALS RdLo, RdHi, Rn, Rs +static INSN_REGPARM void arm0B9(u32 opcode) { MUL_INSN(OP_UMLAL, SETCOND_MULL, 3); } + +// SMULL RdLo, RdHi, Rm, Rs +static INSN_REGPARM void arm0C9(u32 opcode) { MUL_INSN(OP_SMULL, SETCOND_NONE, 2); } +// SMULLS RdLo, RdHi, Rm, Rs +static INSN_REGPARM void arm0D9(u32 opcode) { MUL_INSN(OP_SMULL, SETCOND_MULL, 2); } + +// SMLAL RdLo, RdHi, Rm, Rs +static INSN_REGPARM void arm0E9(u32 opcode) { MUL_INSN(OP_SMLAL, SETCOND_NONE, 3); } +// SMLALS RdLo, RdHi, Rm, Rs +static INSN_REGPARM void arm0F9(u32 opcode) { MUL_INSN(OP_SMLAL, SETCOND_MULL, 3); } + +// Misc instructions ////////////////////////////////////////////////////// + +// SWP Rd, Rm, [Rn] +static INSN_REGPARM void arm109(u32 opcode) +{ + u32 address = reg[(opcode >> 16) & 15].I; + u32 temp = CPUReadMemory(address); + CPUWriteMemory(address, reg[opcode&15].I); + reg[(opcode >> 12) & 15].I = temp; + clockTicks = 4 + dataTicksAccess32(address) + dataTicksAccess32(address) + + codeTicksAccess32(armNextPC); +} + +// SWPB Rd, Rm, [Rn] +static INSN_REGPARM void arm149(u32 opcode) +{ + u32 address = reg[(opcode >> 16) & 15].I; + u32 temp = CPUReadByte(address); + CPUWriteByte(address, reg[opcode&15].B.B0); + reg[(opcode>>12)&15].I = temp; + clockTicks = 4 + dataTicksAccess32(address) + dataTicksAccess32(address) + + codeTicksAccess32(armNextPC); +} + +// MRS Rd, CPSR +static INSN_REGPARM void arm100(u32 opcode) +{ + if (LIKELY((opcode & 0x0FFF0FFF) == 0x010F0000)) { + CPUUpdateCPSR(); + reg[(opcode >> 12) & 0x0F].I = reg[16].I; + } else { + armUnknownInsn(opcode); + } +} + +// MRS Rd, SPSR +static INSN_REGPARM void arm140(u32 opcode) +{ + if (LIKELY((opcode & 0x0FFF0FFF) == 0x014F0000)) { + reg[(opcode >> 12) & 0x0F].I = reg[17].I; + } else { + armUnknownInsn(opcode); + } +} + +// MSR CPSR_fields, Rm +static INSN_REGPARM void arm120(u32 opcode) +{ + if (LIKELY((opcode & 0x0FF0FFF0) == 0x0120F000)) { + CPUUpdateCPSR(); + u32 value = reg[opcode & 15].I; + u32 newValue = reg[16].I; + if (armMode > 0x10) { + if (opcode & 0x00010000) + newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF); + if (opcode & 0x00020000) + newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00); + if (opcode & 0x00040000) + newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000); + } + if (opcode & 0x00080000) + newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000); + newValue |= 0x10; + CPUSwitchMode(newValue & 0x1F, false); + reg[16].I = newValue; + CPUUpdateFlags(); + if (!armState) { // this should not be allowed, but it seems to work + THUMB_PREFETCH; + reg[15].I = armNextPC + 2; + } + } else { + armUnknownInsn(opcode); + } +} + +// MSR SPSR_fields, Rm +static INSN_REGPARM void arm160(u32 opcode) +{ + if (LIKELY((opcode & 0x0FF0FFF0) == 0x0160F000)) { + u32 value = reg[opcode & 15].I; + if (armMode > 0x10 && armMode < 0x1F) { + if (opcode & 0x00010000) + reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF); + if (opcode & 0x00020000) + reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00); + if (opcode & 0x00040000) + reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000); + if (opcode & 0x00080000) + reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000); + } + } else { + armUnknownInsn(opcode); + } +} + +// MSR CPSR_fields, # +static INSN_REGPARM void arm320(u32 opcode) +{ + if (LIKELY((opcode & 0x0FF0F000) == 0x0320F000)) { + CPUUpdateCPSR(); + u32 value = opcode & 0xFF; + int shift = (opcode & 0xF00) >> 7; + if (shift) { + ROR_IMM_MSR; + } + u32 newValue = reg[16].I; + if (armMode > 0x10) { + if (opcode & 0x00010000) + newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF); + if (opcode & 0x00020000) + newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00); + if (opcode & 0x00040000) + newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000); + } + if (opcode & 0x00080000) + newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000); + + newValue |= 0x10; + + CPUSwitchMode(newValue & 0x1F, false); + reg[16].I = newValue; + CPUUpdateFlags(); + if (!armState) { // this should not be allowed, but it seems to work + THUMB_PREFETCH; + reg[15].I = armNextPC + 2; + } + } else { + armUnknownInsn(opcode); + } +} + +// MSR SPSR_fields, # +static INSN_REGPARM void arm360(u32 opcode) +{ + if (LIKELY((opcode & 0x0FF0F000) == 0x0360F000)) { + if (armMode > 0x10 && armMode < 0x1F) { + u32 value = opcode & 0xFF; + int shift = (opcode & 0xF00) >> 7; + if (shift) { + ROR_IMM_MSR; + } + if (opcode & 0x00010000) + reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF); + if (opcode & 0x00020000) + reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00); + if (opcode & 0x00040000) + reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000); + if (opcode & 0x00080000) + reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000); + } + } else { + armUnknownInsn(opcode); + } +} + +// BX Rm +static INSN_REGPARM void arm121(u32 opcode) +{ + if (LIKELY((opcode & 0x0FFFFFF0) == 0x012FFF10)) { + int base = opcode & 0x0F; + busPrefetchCount = 0; + armState = reg[base].I & 1 ? false : true; + if (armState) { + reg[15].I = reg[base].I & 0xFFFFFFFC; + armNextPC = reg[15].I; + reg[15].I += 4; + ARM_PREFETCH; + clockTicks = 3 + codeTicksAccessSeq32(armNextPC) + + codeTicksAccessSeq32(armNextPC) + + codeTicksAccess32(armNextPC); + } else { + reg[15].I = reg[base].I & 0xFFFFFFFE; + armNextPC = reg[15].I; + reg[15].I += 2; + THUMB_PREFETCH; + clockTicks = 3 + codeTicksAccessSeq16(armNextPC) + + codeTicksAccessSeq16(armNextPC) + + codeTicksAccess16(armNextPC); + } + } else { + armUnknownInsn(opcode); + } +} + +// Load/store ///////////////////////////////////////////////////////////// + +#define OFFSET_IMM \ + int offset = opcode & 0xFFF; +#define OFFSET_IMM8 \ + int offset = ((opcode & 0x0F) | ((opcode>>4) & 0xF0)); +#define OFFSET_REG \ + int offset = reg[opcode & 15].I; +#define OFFSET_LSL \ + int offset = reg[opcode & 15].I << ((opcode>>7) & 31); +#define OFFSET_LSR \ + int shift = (opcode >> 7) & 31; \ + int offset = shift ? reg[opcode & 15].I >> shift : 0; +#define OFFSET_ASR \ + int shift = (opcode >> 7) & 31; \ + int offset; \ + if (shift) \ + offset = (int)((s32)reg[opcode & 15].I >> shift);\ + else if (reg[opcode & 15].I & 0x80000000) \ + offset = 0xFFFFFFFF; \ + else \ + offset = 0; +#define OFFSET_ROR \ + int shift = (opcode >> 7) & 31; \ + u32 offset = reg[opcode & 15].I; \ + if (shift) { \ + ROR_OFFSET; \ + } else { \ + RRX_OFFSET; \ + } + +#define ADDRESS_POST (reg[base].I) +#define ADDRESS_PREDEC (reg[base].I - offset) +#define ADDRESS_PREINC (reg[base].I + offset) + +#define OP_STR CPUWriteMemory(address, reg[dest].I) +#define OP_STRH CPUWriteHalfWord(address, reg[dest].W.W0) +#define OP_STRB CPUWriteByte(address, reg[dest].B.B0) +#define OP_LDR reg[dest].I = CPUReadMemory(address) +#define OP_LDRH reg[dest].I = CPUReadHalfWord(address) +#define OP_LDRB reg[dest].I = CPUReadByte(address) +#define OP_LDRSH reg[dest].I = (s16)CPUReadHalfWordSigned(address) +#define OP_LDRSB reg[dest].I = (s8)CPUReadByte(address) + +#define WRITEBACK_NONE /*nothing*/ +#define WRITEBACK_PRE reg[base].I = address +#define WRITEBACK_POSTDEC reg[base].I = address - offset +#define WRITEBACK_POSTINC reg[base].I = address + offset + +#define LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS) \ + if (busPrefetchCount == 0) \ + busPrefetch = busPrefetchEnable; \ + int dest = (opcode >> 12) & 15; \ + int base = (opcode >> 16) & 15; \ + CALC_OFFSET; \ + u32 address = CALC_ADDRESS; + +#define STR(CALC_OFFSET, CALC_ADDRESS, STORE_DATA, WRITEBACK1, WRITEBACK2, SIZE) \ + LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS); \ + WRITEBACK1; \ + STORE_DATA; \ + WRITEBACK2; \ + clockTicks = 2 + dataTicksAccess##SIZE(address) \ + + codeTicksAccess32(armNextPC); +#define LDR(CALC_OFFSET, CALC_ADDRESS, LOAD_DATA, WRITEBACK, SIZE) \ + LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS); \ + LOAD_DATA; \ + if (dest != base) \ + { \ + WRITEBACK; \ + } \ + clockTicks = 0; \ + if (dest == 15) { \ + reg[15].I &= 0xFFFFFFFC; \ + armNextPC = reg[15].I; \ + reg[15].I += 4; \ + ARM_PREFETCH; \ + clockTicks += 2 + dataTicksAccessSeq32(address) \ + + dataTicksAccessSeq32(address);\ + } \ + clockTicks += 3 + dataTicksAccess##SIZE(address) \ + + codeTicksAccess32(armNextPC); +#define STR_POSTDEC(CALC_OFFSET, STORE_DATA, SIZE) \ + STR(CALC_OFFSET, ADDRESS_POST, STORE_DATA, WRITEBACK_NONE, WRITEBACK_POSTDEC, SIZE) +#define STR_POSTINC(CALC_OFFSET, STORE_DATA, SIZE) \ + STR(CALC_OFFSET, ADDRESS_POST, STORE_DATA, WRITEBACK_NONE, WRITEBACK_POSTINC, SIZE) +#define STR_PREDEC(CALC_OFFSET, STORE_DATA, SIZE) \ + STR(CALC_OFFSET, ADDRESS_PREDEC, STORE_DATA, WRITEBACK_NONE, WRITEBACK_NONE, SIZE) +#define STR_PREDEC_WB(CALC_OFFSET, STORE_DATA, SIZE) \ + STR(CALC_OFFSET, ADDRESS_PREDEC, STORE_DATA, WRITEBACK_PRE, WRITEBACK_NONE, SIZE) +#define STR_PREINC(CALC_OFFSET, STORE_DATA, SIZE) \ + STR(CALC_OFFSET, ADDRESS_PREINC, STORE_DATA, WRITEBACK_NONE, WRITEBACK_NONE, SIZE) +#define STR_PREINC_WB(CALC_OFFSET, STORE_DATA, SIZE) \ + STR(CALC_OFFSET, ADDRESS_PREINC, STORE_DATA, WRITEBACK_PRE, WRITEBACK_NONE, SIZE) +#define LDR_POSTDEC(CALC_OFFSET, LOAD_DATA, SIZE) \ + LDR(CALC_OFFSET, ADDRESS_POST, LOAD_DATA, WRITEBACK_POSTDEC, SIZE) +#define LDR_POSTINC(CALC_OFFSET, LOAD_DATA, SIZE) \ + LDR(CALC_OFFSET, ADDRESS_POST, LOAD_DATA, WRITEBACK_POSTINC, SIZE) +#define LDR_PREDEC(CALC_OFFSET, LOAD_DATA, SIZE) \ + LDR(CALC_OFFSET, ADDRESS_PREDEC, LOAD_DATA, WRITEBACK_NONE, SIZE) +#define LDR_PREDEC_WB(CALC_OFFSET, LOAD_DATA, SIZE) \ + LDR(CALC_OFFSET, ADDRESS_PREDEC, LOAD_DATA, WRITEBACK_PRE, SIZE) +#define LDR_PREINC(CALC_OFFSET, LOAD_DATA, SIZE) \ + LDR(CALC_OFFSET, ADDRESS_PREINC, LOAD_DATA, WRITEBACK_NONE, SIZE) +#define LDR_PREINC_WB(CALC_OFFSET, LOAD_DATA, SIZE) \ + LDR(CALC_OFFSET, ADDRESS_PREINC, LOAD_DATA, WRITEBACK_PRE, SIZE) + +// STRH Rd, [Rn], -Rm +static INSN_REGPARM void arm00B(u32 opcode) { STR_POSTDEC(OFFSET_REG, OP_STRH, 16); } +// STRH Rd, [Rn], #-offset +static INSN_REGPARM void arm04B(u32 opcode) { STR_POSTDEC(OFFSET_IMM8, OP_STRH, 16); } +// STRH Rd, [Rn], Rm +static INSN_REGPARM void arm08B(u32 opcode) { STR_POSTINC(OFFSET_REG, OP_STRH, 16); } +// STRH Rd, [Rn], #offset +static INSN_REGPARM void arm0CB(u32 opcode) { STR_POSTINC(OFFSET_IMM8, OP_STRH, 16); } +// STRH Rd, [Rn, -Rm] +static INSN_REGPARM void arm10B(u32 opcode) { STR_PREDEC(OFFSET_REG, OP_STRH, 16); } +// STRH Rd, [Rn, -Rm]! +static INSN_REGPARM void arm12B(u32 opcode) { STR_PREDEC_WB(OFFSET_REG, OP_STRH, 16); } +// STRH Rd, [Rn, -#offset] +static INSN_REGPARM void arm14B(u32 opcode) { STR_PREDEC(OFFSET_IMM8, OP_STRH, 16); } +// STRH Rd, [Rn, -#offset]! +static INSN_REGPARM void arm16B(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM8, OP_STRH, 16); } +// STRH Rd, [Rn, Rm] +static INSN_REGPARM void arm18B(u32 opcode) { STR_PREINC(OFFSET_REG, OP_STRH, 16); } +// STRH Rd, [Rn, Rm]! +static INSN_REGPARM void arm1AB(u32 opcode) { STR_PREINC_WB(OFFSET_REG, OP_STRH, 16); } +// STRH Rd, [Rn, #offset] +static INSN_REGPARM void arm1CB(u32 opcode) { STR_PREINC(OFFSET_IMM8, OP_STRH, 16); } +// STRH Rd, [Rn, #offset]! +static INSN_REGPARM void arm1EB(u32 opcode) { STR_PREINC_WB(OFFSET_IMM8, OP_STRH, 16); } + +// LDRH Rd, [Rn], -Rm +static INSN_REGPARM void arm01B(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRH, 16); } +// LDRH Rd, [Rn], #-offset +static INSN_REGPARM void arm05B(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRH, 16); } +// LDRH Rd, [Rn], Rm +static INSN_REGPARM void arm09B(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRH, 16); } +// LDRH Rd, [Rn], #offset +static INSN_REGPARM void arm0DB(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRH, 16); } +// LDRH Rd, [Rn, -Rm] +static INSN_REGPARM void arm11B(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRH, 16); } +// LDRH Rd, [Rn, -Rm]! +static INSN_REGPARM void arm13B(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRH, 16); } +// LDRH Rd, [Rn, -#offset] +static INSN_REGPARM void arm15B(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRH, 16); } +// LDRH Rd, [Rn, -#offset]! +static INSN_REGPARM void arm17B(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRH, 16); } +// LDRH Rd, [Rn, Rm] +static INSN_REGPARM void arm19B(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRH, 16); } +// LDRH Rd, [Rn, Rm]! +static INSN_REGPARM void arm1BB(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRH, 16); } +// LDRH Rd, [Rn, #offset] +static INSN_REGPARM void arm1DB(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRH, 16); } +// LDRH Rd, [Rn, #offset]! +static INSN_REGPARM void arm1FB(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRH, 16); } + +// LDRSB Rd, [Rn], -Rm +static INSN_REGPARM void arm01D(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRSB, 16); } +// LDRSB Rd, [Rn], #-offset +static INSN_REGPARM void arm05D(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRSB, 16); } +// LDRSB Rd, [Rn], Rm +static INSN_REGPARM void arm09D(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRSB, 16); } +// LDRSB Rd, [Rn], #offset +static INSN_REGPARM void arm0DD(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, -Rm] +static INSN_REGPARM void arm11D(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, -Rm]! +static INSN_REGPARM void arm13D(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, -#offset] +static INSN_REGPARM void arm15D(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, -#offset]! +static INSN_REGPARM void arm17D(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, Rm] +static INSN_REGPARM void arm19D(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, Rm]! +static INSN_REGPARM void arm1BD(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, #offset] +static INSN_REGPARM void arm1DD(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, #offset]! +static INSN_REGPARM void arm1FD(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRSB, 16); } + +// LDRSH Rd, [Rn], -Rm +static INSN_REGPARM void arm01F(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRSH, 16); } +// LDRSH Rd, [Rn], #-offset +static INSN_REGPARM void arm05F(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRSH, 16); } +// LDRSH Rd, [Rn], Rm +static INSN_REGPARM void arm09F(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRSH, 16); } +// LDRSH Rd, [Rn], #offset +static INSN_REGPARM void arm0DF(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, -Rm] +static INSN_REGPARM void arm11F(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, -Rm]! +static INSN_REGPARM void arm13F(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, -#offset] +static INSN_REGPARM void arm15F(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, -#offset]! +static INSN_REGPARM void arm17F(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, Rm] +static INSN_REGPARM void arm19F(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, Rm]! +static INSN_REGPARM void arm1BF(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, #offset] +static INSN_REGPARM void arm1DF(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, #offset]! +static INSN_REGPARM void arm1FF(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRSH, 16); } + +// STR[T] Rd, [Rn], -# +// Note: STR and STRT do the same thing on the GBA (likewise for LDR/LDRT etc) +static INSN_REGPARM void arm400(u32 opcode) { STR_POSTDEC(OFFSET_IMM, OP_STR, 32); } +// LDR[T] Rd, [Rn], -# +static INSN_REGPARM void arm410(u32 opcode) { LDR_POSTDEC(OFFSET_IMM, OP_LDR, 32); } +// STRB[T] Rd, [Rn], -# +static INSN_REGPARM void arm440(u32 opcode) { STR_POSTDEC(OFFSET_IMM, OP_STRB, 16); } +// LDRB[T] Rd, [Rn], -# +static INSN_REGPARM void arm450(u32 opcode) { LDR_POSTDEC(OFFSET_IMM, OP_LDRB, 16); } +// STR[T] Rd, [Rn], # +static INSN_REGPARM void arm480(u32 opcode) { STR_POSTINC(OFFSET_IMM, OP_STR, 32); } +// LDR Rd, [Rn], # +static INSN_REGPARM void arm490(u32 opcode) { LDR_POSTINC(OFFSET_IMM, OP_LDR, 32); } +// STRB[T] Rd, [Rn], # +static INSN_REGPARM void arm4C0(u32 opcode) { STR_POSTINC(OFFSET_IMM, OP_STRB, 16); } +// LDRB[T] Rd, [Rn], # +static INSN_REGPARM void arm4D0(u32 opcode) { LDR_POSTINC(OFFSET_IMM, OP_LDRB, 16); } +// STR Rd, [Rn, -#] +static INSN_REGPARM void arm500(u32 opcode) { STR_PREDEC(OFFSET_IMM, OP_STR, 32); } +// LDR Rd, [Rn, -#] +static INSN_REGPARM void arm510(u32 opcode) { LDR_PREDEC(OFFSET_IMM, OP_LDR, 32); } +// STR Rd, [Rn, -#]! +static INSN_REGPARM void arm520(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM, OP_STR, 32); } +// LDR Rd, [Rn, -#]! +static INSN_REGPARM void arm530(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM, OP_LDR, 32); } +// STRB Rd, [Rn, -#] +static INSN_REGPARM void arm540(u32 opcode) { STR_PREDEC(OFFSET_IMM, OP_STRB, 16); } +// LDRB Rd, [Rn, -#] +static INSN_REGPARM void arm550(u32 opcode) { LDR_PREDEC(OFFSET_IMM, OP_LDRB, 16); } +// STRB Rd, [Rn, -#]! +static INSN_REGPARM void arm560(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM, OP_STRB, 16); } +// LDRB Rd, [Rn, -#]! +static INSN_REGPARM void arm570(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM, OP_LDRB, 16); } +// STR Rd, [Rn, #] +static INSN_REGPARM void arm580(u32 opcode) { STR_PREINC(OFFSET_IMM, OP_STR, 32); } +// LDR Rd, [Rn, #] +static INSN_REGPARM void arm590(u32 opcode) { LDR_PREINC(OFFSET_IMM, OP_LDR, 32); } +// STR Rd, [Rn, #]! +static INSN_REGPARM void arm5A0(u32 opcode) { STR_PREINC_WB(OFFSET_IMM, OP_STR, 32); } +// LDR Rd, [Rn, #]! +static INSN_REGPARM void arm5B0(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM, OP_LDR, 32); } +// STRB Rd, [Rn, #] +static INSN_REGPARM void arm5C0(u32 opcode) { STR_PREINC(OFFSET_IMM, OP_STRB, 16); } +// LDRB Rd, [Rn, #] +static INSN_REGPARM void arm5D0(u32 opcode) { LDR_PREINC(OFFSET_IMM, OP_LDRB, 16); } +// STRB Rd, [Rn, #]! +static INSN_REGPARM void arm5E0(u32 opcode) { STR_PREINC_WB(OFFSET_IMM, OP_STRB, 16); } +// LDRB Rd, [Rn, #]! +static INSN_REGPARM void arm5F0(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM, OP_LDRB, 16); } + +// STR[T] Rd, [Rn], -Rm, LSL # +static INSN_REGPARM void arm600(u32 opcode) { STR_POSTDEC(OFFSET_LSL, OP_STR, 32); } +// STR[T] Rd, [Rn], -Rm, LSR # +static INSN_REGPARM void arm602(u32 opcode) { STR_POSTDEC(OFFSET_LSR, OP_STR, 32); } +// STR[T] Rd, [Rn], -Rm, ASR # +static INSN_REGPARM void arm604(u32 opcode) { STR_POSTDEC(OFFSET_ASR, OP_STR, 32); } +// STR[T] Rd, [Rn], -Rm, ROR # +static INSN_REGPARM void arm606(u32 opcode) { STR_POSTDEC(OFFSET_ROR, OP_STR, 32); } +// LDR[T] Rd, [Rn], -Rm, LSL # +static INSN_REGPARM void arm610(u32 opcode) { LDR_POSTDEC(OFFSET_LSL, OP_LDR, 32); } +// LDR[T] Rd, [Rn], -Rm, LSR # +static INSN_REGPARM void arm612(u32 opcode) { LDR_POSTDEC(OFFSET_LSR, OP_LDR, 32); } +// LDR[T] Rd, [Rn], -Rm, ASR # +static INSN_REGPARM void arm614(u32 opcode) { LDR_POSTDEC(OFFSET_ASR, OP_LDR, 32); } +// LDR[T] Rd, [Rn], -Rm, ROR # +static INSN_REGPARM void arm616(u32 opcode) { LDR_POSTDEC(OFFSET_ROR, OP_LDR, 32); } +// STRB[T] Rd, [Rn], -Rm, LSL # +static INSN_REGPARM void arm640(u32 opcode) { STR_POSTDEC(OFFSET_LSL, OP_STRB, 16); } +// STRB[T] Rd, [Rn], -Rm, LSR # +static INSN_REGPARM void arm642(u32 opcode) { STR_POSTDEC(OFFSET_LSR, OP_STRB, 16); } +// STRB[T] Rd, [Rn], -Rm, ASR # +static INSN_REGPARM void arm644(u32 opcode) { STR_POSTDEC(OFFSET_ASR, OP_STRB, 16); } +// STRB[T] Rd, [Rn], -Rm, ROR # +static INSN_REGPARM void arm646(u32 opcode) { STR_POSTDEC(OFFSET_ROR, OP_STRB, 16); } +// LDRB[T] Rd, [Rn], -Rm, LSL # +static INSN_REGPARM void arm650(u32 opcode) { LDR_POSTDEC(OFFSET_LSL, OP_LDRB, 16); } +// LDRB[T] Rd, [Rn], -Rm, LSR # +static INSN_REGPARM void arm652(u32 opcode) { LDR_POSTDEC(OFFSET_LSR, OP_LDRB, 16); } +// LDRB[T] Rd, [Rn], -Rm, ASR # +static INSN_REGPARM void arm654(u32 opcode) { LDR_POSTDEC(OFFSET_ASR, OP_LDRB, 16); } +// LDRB Rd, [Rn], -Rm, ROR # +static INSN_REGPARM void arm656(u32 opcode) { LDR_POSTDEC(OFFSET_ROR, OP_LDRB, 16); } +// STR[T] Rd, [Rn], Rm, LSL # +static INSN_REGPARM void arm680(u32 opcode) { STR_POSTINC(OFFSET_LSL, OP_STR, 32); } +// STR[T] Rd, [Rn], Rm, LSR # +static INSN_REGPARM void arm682(u32 opcode) { STR_POSTINC(OFFSET_LSR, OP_STR, 32); } +// STR[T] Rd, [Rn], Rm, ASR # +static INSN_REGPARM void arm684(u32 opcode) { STR_POSTINC(OFFSET_ASR, OP_STR, 32); } +// STR[T] Rd, [Rn], Rm, ROR # +static INSN_REGPARM void arm686(u32 opcode) { STR_POSTINC(OFFSET_ROR, OP_STR, 32); } +// LDR[T] Rd, [Rn], Rm, LSL # +static INSN_REGPARM void arm690(u32 opcode) { LDR_POSTINC(OFFSET_LSL, OP_LDR, 32); } +// LDR[T] Rd, [Rn], Rm, LSR # +static INSN_REGPARM void arm692(u32 opcode) { LDR_POSTINC(OFFSET_LSR, OP_LDR, 32); } +// LDR[T] Rd, [Rn], Rm, ASR # +static INSN_REGPARM void arm694(u32 opcode) { LDR_POSTINC(OFFSET_ASR, OP_LDR, 32); } +// LDR[T] Rd, [Rn], Rm, ROR # +static INSN_REGPARM void arm696(u32 opcode) { LDR_POSTINC(OFFSET_ROR, OP_LDR, 32); } +// STRB[T] Rd, [Rn], Rm, LSL # +static INSN_REGPARM void arm6C0(u32 opcode) { STR_POSTINC(OFFSET_LSL, OP_STRB, 16); } +// STRB[T] Rd, [Rn], Rm, LSR # +static INSN_REGPARM void arm6C2(u32 opcode) { STR_POSTINC(OFFSET_LSR, OP_STRB, 16); } +// STRB[T] Rd, [Rn], Rm, ASR # +static INSN_REGPARM void arm6C4(u32 opcode) { STR_POSTINC(OFFSET_ASR, OP_STRB, 16); } +// STRB[T] Rd, [Rn], Rm, ROR # +static INSN_REGPARM void arm6C6(u32 opcode) { STR_POSTINC(OFFSET_ROR, OP_STRB, 16); } +// LDRB[T] Rd, [Rn], Rm, LSL # +static INSN_REGPARM void arm6D0(u32 opcode) { LDR_POSTINC(OFFSET_LSL, OP_LDRB, 16); } +// LDRB[T] Rd, [Rn], Rm, LSR # +static INSN_REGPARM void arm6D2(u32 opcode) { LDR_POSTINC(OFFSET_LSR, OP_LDRB, 16); } +// LDRB[T] Rd, [Rn], Rm, ASR # +static INSN_REGPARM void arm6D4(u32 opcode) { LDR_POSTINC(OFFSET_ASR, OP_LDRB, 16); } +// LDRB[T] Rd, [Rn], Rm, ROR # +static INSN_REGPARM void arm6D6(u32 opcode) { LDR_POSTINC(OFFSET_ROR, OP_LDRB, 16); } +// STR Rd, [Rn, -Rm, LSL #] +static INSN_REGPARM void arm700(u32 opcode) { STR_PREDEC(OFFSET_LSL, OP_STR, 32); } +// STR Rd, [Rn, -Rm, LSR #] +static INSN_REGPARM void arm702(u32 opcode) { STR_PREDEC(OFFSET_LSR, OP_STR, 32); } +// STR Rd, [Rn, -Rm, ASR #] +static INSN_REGPARM void arm704(u32 opcode) { STR_PREDEC(OFFSET_ASR, OP_STR, 32); } +// STR Rd, [Rn, -Rm, ROR #] +static INSN_REGPARM void arm706(u32 opcode) { STR_PREDEC(OFFSET_ROR, OP_STR, 32); } +// LDR Rd, [Rn, -Rm, LSL #] +static INSN_REGPARM void arm710(u32 opcode) { LDR_PREDEC(OFFSET_LSL, OP_LDR, 32); } +// LDR Rd, [Rn, -Rm, LSR #] +static INSN_REGPARM void arm712(u32 opcode) { LDR_PREDEC(OFFSET_LSR, OP_LDR, 32); } +// LDR Rd, [Rn, -Rm, ASR #] +static INSN_REGPARM void arm714(u32 opcode) { LDR_PREDEC(OFFSET_ASR, OP_LDR, 32); } +// LDR Rd, [Rn, -Rm, ROR #] +static INSN_REGPARM void arm716(u32 opcode) { LDR_PREDEC(OFFSET_ROR, OP_LDR, 32); } +// STR Rd, [Rn, -Rm, LSL #]! +static INSN_REGPARM void arm720(u32 opcode) { STR_PREDEC_WB(OFFSET_LSL, OP_STR, 32); } +// STR Rd, [Rn, -Rm, LSR #]! +static INSN_REGPARM void arm722(u32 opcode) { STR_PREDEC_WB(OFFSET_LSR, OP_STR, 32); } +// STR Rd, [Rn, -Rm, ASR #]! +static INSN_REGPARM void arm724(u32 opcode) { STR_PREDEC_WB(OFFSET_ASR, OP_STR, 32); } +// STR Rd, [Rn, -Rm, ROR #]! +static INSN_REGPARM void arm726(u32 opcode) { STR_PREDEC_WB(OFFSET_ROR, OP_STR, 32); } +// LDR Rd, [Rn, -Rm, LSL #]! +static INSN_REGPARM void arm730(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSL, OP_LDR, 32); } +// LDR Rd, [Rn, -Rm, LSR #]! +static INSN_REGPARM void arm732(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSR, OP_LDR, 32); } +// LDR Rd, [Rn, -Rm, ASR #]! +static INSN_REGPARM void arm734(u32 opcode) { LDR_PREDEC_WB(OFFSET_ASR, OP_LDR, 32); } +// LDR Rd, [Rn, -Rm, ROR #]! +static INSN_REGPARM void arm736(u32 opcode) { LDR_PREDEC_WB(OFFSET_ROR, OP_LDR, 32); } +// STRB Rd, [Rn, -Rm, LSL #] +static INSN_REGPARM void arm740(u32 opcode) { STR_PREDEC(OFFSET_LSL, OP_STRB, 16); } +// STRB Rd, [Rn, -Rm, LSR #] +static INSN_REGPARM void arm742(u32 opcode) { STR_PREDEC(OFFSET_LSR, OP_STRB, 16); } +// STRB Rd, [Rn, -Rm, ASR #] +static INSN_REGPARM void arm744(u32 opcode) { STR_PREDEC(OFFSET_ASR, OP_STRB, 16); } +// STRB Rd, [Rn, -Rm, ROR #] +static INSN_REGPARM void arm746(u32 opcode) { STR_PREDEC(OFFSET_ROR, OP_STRB, 16); } +// LDRB Rd, [Rn, -Rm, LSL #] +static INSN_REGPARM void arm750(u32 opcode) { LDR_PREDEC(OFFSET_LSL, OP_LDRB, 16); } +// LDRB Rd, [Rn, -Rm, LSR #] +static INSN_REGPARM void arm752(u32 opcode) { LDR_PREDEC(OFFSET_LSR, OP_LDRB, 16); } +// LDRB Rd, [Rn, -Rm, ASR #] +static INSN_REGPARM void arm754(u32 opcode) { LDR_PREDEC(OFFSET_ASR, OP_LDRB, 16); } +// LDRB Rd, [Rn, -Rm, ROR #] +static INSN_REGPARM void arm756(u32 opcode) { LDR_PREDEC(OFFSET_ROR, OP_LDRB, 16); } +// STRB Rd, [Rn, -Rm, LSL #]! +static INSN_REGPARM void arm760(u32 opcode) { STR_PREDEC_WB(OFFSET_LSL, OP_STRB, 16); } +// STRB Rd, [Rn, -Rm, LSR #]! +static INSN_REGPARM void arm762(u32 opcode) { STR_PREDEC_WB(OFFSET_LSR, OP_STRB, 16); } +// STRB Rd, [Rn, -Rm, ASR #]! +static INSN_REGPARM void arm764(u32 opcode) { STR_PREDEC_WB(OFFSET_ASR, OP_STRB, 16); } +// STRB Rd, [Rn, -Rm, ROR #]! +static INSN_REGPARM void arm766(u32 opcode) { STR_PREDEC_WB(OFFSET_ROR, OP_STRB, 16); } +// LDRB Rd, [Rn, -Rm, LSL #]! +static INSN_REGPARM void arm770(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSL, OP_LDRB, 16); } +// LDRB Rd, [Rn, -Rm, LSR #]! +static INSN_REGPARM void arm772(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSR, OP_LDRB, 16); } +// LDRB Rd, [Rn, -Rm, ASR #]! +static INSN_REGPARM void arm774(u32 opcode) { LDR_PREDEC_WB(OFFSET_ASR, OP_LDRB, 16); } +// LDRB Rd, [Rn, -Rm, ROR #]! +static INSN_REGPARM void arm776(u32 opcode) { LDR_PREDEC_WB(OFFSET_ROR, OP_LDRB, 16); } +// STR Rd, [Rn, Rm, LSL #] +static INSN_REGPARM void arm780(u32 opcode) { STR_PREINC(OFFSET_LSL, OP_STR, 32); } +// STR Rd, [Rn, Rm, LSR #] +static INSN_REGPARM void arm782(u32 opcode) { STR_PREINC(OFFSET_LSR, OP_STR, 32); } +// STR Rd, [Rn, Rm, ASR #] +static INSN_REGPARM void arm784(u32 opcode) { STR_PREINC(OFFSET_ASR, OP_STR, 32); } +// STR Rd, [Rn, Rm, ROR #] +static INSN_REGPARM void arm786(u32 opcode) { STR_PREINC(OFFSET_ROR, OP_STR, 32); } +// LDR Rd, [Rn, Rm, LSL #] +static INSN_REGPARM void arm790(u32 opcode) { LDR_PREINC(OFFSET_LSL, OP_LDR, 32); } +// LDR Rd, [Rn, Rm, LSR #] +static INSN_REGPARM void arm792(u32 opcode) { LDR_PREINC(OFFSET_LSR, OP_LDR, 32); } +// LDR Rd, [Rn, Rm, ASR #] +static INSN_REGPARM void arm794(u32 opcode) { LDR_PREINC(OFFSET_ASR, OP_LDR, 32); } +// LDR Rd, [Rn, Rm, ROR #] +static INSN_REGPARM void arm796(u32 opcode) { LDR_PREINC(OFFSET_ROR, OP_LDR, 32); } +// STR Rd, [Rn, Rm, LSL #]! +static INSN_REGPARM void arm7A0(u32 opcode) { STR_PREINC_WB(OFFSET_LSL, OP_STR, 32); } +// STR Rd, [Rn, Rm, LSR #]! +static INSN_REGPARM void arm7A2(u32 opcode) { STR_PREINC_WB(OFFSET_LSR, OP_STR, 32); } +// STR Rd, [Rn, Rm, ASR #]! +static INSN_REGPARM void arm7A4(u32 opcode) { STR_PREINC_WB(OFFSET_ASR, OP_STR, 32); } +// STR Rd, [Rn, Rm, ROR #]! +static INSN_REGPARM void arm7A6(u32 opcode) { STR_PREINC_WB(OFFSET_ROR, OP_STR, 32); } +// LDR Rd, [Rn, Rm, LSL #]! +static INSN_REGPARM void arm7B0(u32 opcode) { LDR_PREINC_WB(OFFSET_LSL, OP_LDR, 32); } +// LDR Rd, [Rn, Rm, LSR #]! +static INSN_REGPARM void arm7B2(u32 opcode) { LDR_PREINC_WB(OFFSET_LSR, OP_LDR, 32); } +// LDR Rd, [Rn, Rm, ASR #]! +static INSN_REGPARM void arm7B4(u32 opcode) { LDR_PREINC_WB(OFFSET_ASR, OP_LDR, 32); } +// LDR Rd, [Rn, Rm, ROR #]! +static INSN_REGPARM void arm7B6(u32 opcode) { LDR_PREINC_WB(OFFSET_ROR, OP_LDR, 32); } +// STRB Rd, [Rn, Rm, LSL #] +static INSN_REGPARM void arm7C0(u32 opcode) { STR_PREINC(OFFSET_LSL, OP_STRB, 16); } +// STRB Rd, [Rn, Rm, LSR #] +static INSN_REGPARM void arm7C2(u32 opcode) { STR_PREINC(OFFSET_LSR, OP_STRB, 16); } +// STRB Rd, [Rn, Rm, ASR #] +static INSN_REGPARM void arm7C4(u32 opcode) { STR_PREINC(OFFSET_ASR, OP_STRB, 16); } +// STRB Rd, [Rn, Rm, ROR #] +static INSN_REGPARM void arm7C6(u32 opcode) { STR_PREINC(OFFSET_ROR, OP_STRB, 16); } +// LDRB Rd, [Rn, Rm, LSL #] +static INSN_REGPARM void arm7D0(u32 opcode) { LDR_PREINC(OFFSET_LSL, OP_LDRB, 16); } +// LDRB Rd, [Rn, Rm, LSR #] +static INSN_REGPARM void arm7D2(u32 opcode) { LDR_PREINC(OFFSET_LSR, OP_LDRB, 16); } +// LDRB Rd, [Rn, Rm, ASR #] +static INSN_REGPARM void arm7D4(u32 opcode) { LDR_PREINC(OFFSET_ASR, OP_LDRB, 16); } +// LDRB Rd, [Rn, Rm, ROR #] +static INSN_REGPARM void arm7D6(u32 opcode) { LDR_PREINC(OFFSET_ROR, OP_LDRB, 16); } +// STRB Rd, [Rn, Rm, LSL #]! +static INSN_REGPARM void arm7E0(u32 opcode) { STR_PREINC_WB(OFFSET_LSL, OP_STRB, 16); } +// STRB Rd, [Rn, Rm, LSR #]! +static INSN_REGPARM void arm7E2(u32 opcode) { STR_PREINC_WB(OFFSET_LSR, OP_STRB, 16); } +// STRB Rd, [Rn, Rm, ASR #]! +static INSN_REGPARM void arm7E4(u32 opcode) { STR_PREINC_WB(OFFSET_ASR, OP_STRB, 16); } +// STRB Rd, [Rn, Rm, ROR #]! +static INSN_REGPARM void arm7E6(u32 opcode) { STR_PREINC_WB(OFFSET_ROR, OP_STRB, 16); } +// LDRB Rd, [Rn, Rm, LSL #]! +static INSN_REGPARM void arm7F0(u32 opcode) { LDR_PREINC_WB(OFFSET_LSL, OP_LDRB, 16); } +// LDRB Rd, [Rn, Rm, LSR #]! +static INSN_REGPARM void arm7F2(u32 opcode) { LDR_PREINC_WB(OFFSET_LSR, OP_LDRB, 16); } +// LDRB Rd, [Rn, Rm, ASR #]! +static INSN_REGPARM void arm7F4(u32 opcode) { LDR_PREINC_WB(OFFSET_ASR, OP_LDRB, 16); } +// LDRB Rd, [Rn, Rm, ROR #]! +static INSN_REGPARM void arm7F6(u32 opcode) { LDR_PREINC_WB(OFFSET_ROR, OP_LDRB, 16); } + +// STM/LDM //////////////////////////////////////////////////////////////// + +#define STM_REG(bit,num) \ + if (opcode & (1U<<(bit))) { \ + CPUWriteMemory(address, reg[(num)].I); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address);\ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address);\ + } \ + count++; \ + address += 4; \ + } +#define STMW_REG(bit,num) \ + if (opcode & (1U<<(bit))) { \ + CPUWriteMemory(address, reg[(num)].I); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address);\ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address);\ + } \ + reg[base].I = temp; \ + count++; \ + address += 4; \ + } +#define LDM_REG(bit,num) \ + if (opcode & (1U<<(bit))) { \ + reg[(num)].I = CPUReadMemory(address); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address);\ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address);\ + } \ + count++; \ + address += 4; \ + } +#define STM_LOW(STORE_REG) \ + STORE_REG(0, 0); \ + STORE_REG(1, 1); \ + STORE_REG(2, 2); \ + STORE_REG(3, 3); \ + STORE_REG(4, 4); \ + STORE_REG(5, 5); \ + STORE_REG(6, 6); \ + STORE_REG(7, 7); +#define STM_HIGH(STORE_REG) \ + STORE_REG(8, 8); \ + STORE_REG(9, 9); \ + STORE_REG(10, 10); \ + STORE_REG(11, 11); \ + STORE_REG(12, 12); \ + STORE_REG(13, 13); \ + STORE_REG(14, 14); +#define STM_HIGH_2(STORE_REG) \ + if (armMode == 0x11) { \ + STORE_REG(8, R8_FIQ); \ + STORE_REG(9, R9_FIQ); \ + STORE_REG(10, R10_FIQ); \ + STORE_REG(11, R11_FIQ); \ + STORE_REG(12, R12_FIQ); \ + } else { \ + STORE_REG(8, 8); \ + STORE_REG(9, 9); \ + STORE_REG(10, 10); \ + STORE_REG(11, 11); \ + STORE_REG(12, 12); \ + } \ + if (armMode != 0x10 && armMode != 0x1F) { \ + STORE_REG(13, R13_USR); \ + STORE_REG(14, R14_USR); \ + } else { \ + STORE_REG(13, 13); \ + STORE_REG(14, 14); \ + } +#define STM_PC \ + if (opcode & (1U<<15)) { \ + CPUWriteMemory(address, reg[15].I+4); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address);\ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address);\ + } \ + count++; \ + } +#define STMW_PC \ + if (opcode & (1U<<15)) { \ + CPUWriteMemory(address, reg[15].I+4); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address);\ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address);\ + } \ + reg[base].I = temp; \ + count++; \ + } +#define LDM_LOW \ + LDM_REG(0, 0); \ + LDM_REG(1, 1); \ + LDM_REG(2, 2); \ + LDM_REG(3, 3); \ + LDM_REG(4, 4); \ + LDM_REG(5, 5); \ + LDM_REG(6, 6); \ + LDM_REG(7, 7); +#define LDM_HIGH \ + LDM_REG(8, 8); \ + LDM_REG(9, 9); \ + LDM_REG(10, 10); \ + LDM_REG(11, 11); \ + LDM_REG(12, 12); \ + LDM_REG(13, 13); \ + LDM_REG(14, 14); +#define LDM_HIGH_2 \ + if (armMode == 0x11) { \ + LDM_REG(8, R8_FIQ); \ + LDM_REG(9, R9_FIQ); \ + LDM_REG(10, R10_FIQ); \ + LDM_REG(11, R11_FIQ); \ + LDM_REG(12, R12_FIQ); \ + } else { \ + LDM_REG(8, 8); \ + LDM_REG(9, 9); \ + LDM_REG(10, 10); \ + LDM_REG(11, 11); \ + LDM_REG(12, 12); \ + } \ + if (armMode != 0x10 && armMode != 0x1F) { \ + LDM_REG(13, R13_USR); \ + LDM_REG(14, R14_USR); \ + } else { \ + LDM_REG(13, 13); \ + LDM_REG(14, 14); \ + } +#define STM_ALL \ + STM_LOW(STM_REG); \ + STM_HIGH(STM_REG); \ + STM_PC; +#define STMW_ALL \ + STM_LOW(STMW_REG); \ + STM_HIGH(STMW_REG); \ + STMW_PC; +#define LDM_ALL \ + LDM_LOW; \ + LDM_HIGH; \ + if (opcode & (1U<<15)) { \ + reg[15].I = CPUReadMemory(address); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address);\ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address);\ + } \ + count++; \ + } \ + if (opcode & (1U<<15)) { \ + armNextPC = reg[15].I; \ + reg[15].I += 4; \ + ARM_PREFETCH; \ + clockTicks += 1 + codeTicksAccessSeq32(armNextPC);\ + } +#define STM_ALL_2 \ + STM_LOW(STM_REG); \ + STM_HIGH_2(STM_REG); \ + STM_PC; +#define STMW_ALL_2 \ + STM_LOW(STMW_REG); \ + STM_HIGH_2(STMW_REG); \ + STMW_PC; +#define LDM_ALL_2 \ + LDM_LOW; \ + if (opcode & (1U<<15)) { \ + LDM_HIGH; \ + reg[15].I = CPUReadMemory(address); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address); \ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address); \ + } \ + count++; \ + } else { \ + LDM_HIGH_2; \ + } +#define LDM_ALL_2B \ + if (opcode & (1U<<15)) { \ + CPUSwitchMode(reg[17].I & 0x1F, false); \ + if (armState) { \ + armNextPC = reg[15].I & 0xFFFFFFFC; \ + reg[15].I = armNextPC + 4; \ + ARM_PREFETCH; \ + } else { \ + armNextPC = reg[15].I & 0xFFFFFFFE; \ + reg[15].I = armNextPC + 2; \ + THUMB_PREFETCH; \ + } \ + clockTicks += 1 + codeTicksAccessSeq32(armNextPC);\ + } + + +// STMDA Rn, {Rlist} +static INSN_REGPARM void arm800(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp + 4) & 0xFFFFFFFC; + int count = 0; + STM_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDA Rn, {Rlist} +static INSN_REGPARM void arm810(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp + 4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMDA Rn!, {Rlist} +static INSN_REGPARM void arm820(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp+4) & 0xFFFFFFFC; + int count = 0; + STMW_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDA Rn!, {Rlist} +static INSN_REGPARM void arm830(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp + 4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); + if (!(opcode & (1U << base))) + reg[base].I = temp; +} + +// STMDA Rn, {Rlist}^ +static INSN_REGPARM void arm840(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp+4) & 0xFFFFFFFC; + int count = 0; + STM_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDA Rn, {Rlist}^ +static INSN_REGPARM void arm850(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp + 4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMDA Rn!, {Rlist}^ +static INSN_REGPARM void arm860(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp+4) & 0xFFFFFFFC; + int count = 0; + STMW_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDA Rn!, {Rlist}^ +static INSN_REGPARM void arm870(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp + 4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + if (!(opcode & (1U << base))) + reg[base].I = temp; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMIA Rn, {Rlist} +static INSN_REGPARM void arm880(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + STM_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIA Rn, {Rlist} +static INSN_REGPARM void arm890(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMIA Rn!, {Rlist} +static INSN_REGPARM void arm8A0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); + STMW_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIA Rn!, {Rlist} +static INSN_REGPARM void arm8B0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); + if (!(opcode & (1U << base))) + reg[base].I = temp; +} + +// STMIA Rn, {Rlist}^ +static INSN_REGPARM void arm8C0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + STM_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIA Rn, {Rlist}^ +static INSN_REGPARM void arm8D0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMIA Rn!, {Rlist}^ +static INSN_REGPARM void arm8E0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); + STMW_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIA Rn!, {Rlist}^ +static INSN_REGPARM void arm8F0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + if (!(opcode & (1U << base))) + reg[base].I = temp; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMDB Rn, {Rlist} +static INSN_REGPARM void arm900(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + STM_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDB Rn, {Rlist} +static INSN_REGPARM void arm910(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMDB Rn!, {Rlist} +static INSN_REGPARM void arm920(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + STMW_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDB Rn!, {Rlist} +static INSN_REGPARM void arm930(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); + if (!(opcode & (1U << base))) + reg[base].I = temp; +} + +// STMDB Rn, {Rlist}^ +static INSN_REGPARM void arm940(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + STM_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDB Rn, {Rlist}^ +static INSN_REGPARM void arm950(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMDB Rn!, {Rlist}^ +static INSN_REGPARM void arm960(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + STMW_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDB Rn!, {Rlist}^ +static INSN_REGPARM void arm970(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + if (!(opcode & (1U << base))) + reg[base].I = temp; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMIB Rn, {Rlist} +static INSN_REGPARM void arm980(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + STM_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIB Rn, {Rlist} +static INSN_REGPARM void arm990(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMIB Rn!, {Rlist} +static INSN_REGPARM void arm9A0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); + STMW_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIB Rn!, {Rlist} +static INSN_REGPARM void arm9B0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); + if (!(opcode & (1U << base))) + reg[base].I = temp; +} + +// STMIB Rn, {Rlist}^ +static INSN_REGPARM void arm9C0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + STM_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIB Rn, {Rlist}^ +static INSN_REGPARM void arm9D0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMIB Rn!, {Rlist}^ +static INSN_REGPARM void arm9E0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); + STMW_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIB Rn!, {Rlist}^ +static INSN_REGPARM void arm9F0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + if (!(opcode & (1U << base))) + reg[base].I = temp; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// B/BL/SWI and (unimplemented) coproc support //////////////////////////// + +// B +static INSN_REGPARM void armA00(u32 opcode) +{ + int offset = opcode & 0x00FFFFFF; + if (offset & 0x00800000) + offset |= 0xFF000000; // negative offset + reg[15].I += offset<<2; + armNextPC = reg[15].I; + reg[15].I += 4; + ARM_PREFETCH; + clockTicks = codeTicksAccessSeq32(armNextPC) + 1; + clockTicks += 2 + codeTicksAccess32(armNextPC) + + codeTicksAccessSeq32(armNextPC); + busPrefetchCount = 0; +} + +// BL +static INSN_REGPARM void armB00(u32 opcode) +{ + int offset = opcode & 0x00FFFFFF; + if (offset & 0x00800000) + offset |= 0xFF000000; // negative offset + reg[14].I = reg[15].I - 4; + reg[15].I += offset<<2; + armNextPC = reg[15].I; + reg[15].I += 4; + ARM_PREFETCH; + clockTicks = codeTicksAccessSeq32(armNextPC) + 1; + clockTicks += 2 + codeTicksAccess32(armNextPC) + + codeTicksAccessSeq32(armNextPC); + busPrefetchCount = 0; +} + + +#ifdef GP_SUPPORT +// MRC +static INSN_REGPARM void armE01(u32 opcode) +{ +} +#else + #define armE01 armUnknownInsn +#endif + + +// SWI +static INSN_REGPARM void armF00(u32 opcode) +{ + clockTicks = codeTicksAccessSeq32(armNextPC) + 1; + clockTicks += 2 + codeTicksAccess32(armNextPC) + + codeTicksAccessSeq32(armNextPC); + busPrefetchCount = 0; + CPUSoftwareInterrupt(opcode & 0x00FFFFFF); +} + +// Instruction table ////////////////////////////////////////////////////// + +typedef INSN_REGPARM void (*insnfunc_t)(u32 opcode); +#define REP16(insn) \ + insn,insn,insn,insn,insn,insn,insn,insn,\ + insn,insn,insn,insn,insn,insn,insn,insn +#define REP256(insn) \ + REP16(insn),REP16(insn),REP16(insn),REP16(insn),\ + REP16(insn),REP16(insn),REP16(insn),REP16(insn),\ + REP16(insn),REP16(insn),REP16(insn),REP16(insn),\ + REP16(insn),REP16(insn),REP16(insn),REP16(insn) +#define arm_UI armUnknownInsn +#ifdef BKPT_SUPPORT + #define arm_BP armBreakpoint +#else + #define arm_BP armUnknownInsn +#endif +static insnfunc_t armInsnTable[4096] = { + arm000,arm001,arm002,arm003,arm004,arm005,arm006,arm007, // 000 + arm000,arm009,arm002,arm00B,arm004,arm_UI,arm006,arm_UI, // 008 + arm010,arm011,arm012,arm013,arm014,arm015,arm016,arm017, // 010 + arm010,arm019,arm012,arm01B,arm014,arm01D,arm016,arm01F, // 018 + arm020,arm021,arm022,arm023,arm024,arm025,arm026,arm027, // 020 + arm020,arm029,arm022,arm_UI,arm024,arm_UI,arm026,arm_UI, // 028 + arm030,arm031,arm032,arm033,arm034,arm035,arm036,arm037, // 030 + arm030,arm039,arm032,arm_UI,arm034,arm01D,arm036,arm01F, // 038 + arm040,arm041,arm042,arm043,arm044,arm045,arm046,arm047, // 040 + arm040,arm_UI,arm042,arm04B,arm044,arm_UI,arm046,arm_UI, // 048 + arm050,arm051,arm052,arm053,arm054,arm055,arm056,arm057, // 050 + arm050,arm_UI,arm052,arm05B,arm054,arm05D,arm056,arm05F, // 058 + arm060,arm061,arm062,arm063,arm064,arm065,arm066,arm067, // 060 + arm060,arm_UI,arm062,arm_UI,arm064,arm_UI,arm066,arm_UI, // 068 + arm070,arm071,arm072,arm073,arm074,arm075,arm076,arm077, // 070 + arm070,arm_UI,arm072,arm_UI,arm074,arm05D,arm076,arm05F, // 078 + arm080,arm081,arm082,arm083,arm084,arm085,arm086,arm087, // 080 + arm080,arm089,arm082,arm08B,arm084,arm_UI,arm086,arm_UI, // 088 + arm090,arm091,arm092,arm093,arm094,arm095,arm096,arm097, // 090 + arm090,arm099,arm092,arm09B,arm094,arm09D,arm096,arm09F, // 098 + arm0A0,arm0A1,arm0A2,arm0A3,arm0A4,arm0A5,arm0A6,arm0A7, // 0A0 + arm0A0,arm0A9,arm0A2,arm_UI,arm0A4,arm_UI,arm0A6,arm_UI, // 0A8 + arm0B0,arm0B1,arm0B2,arm0B3,arm0B4,arm0B5,arm0B6,arm0B7, // 0B0 + arm0B0,arm0B9,arm0B2,arm_UI,arm0B4,arm09D,arm0B6,arm09F, // 0B8 + arm0C0,arm0C1,arm0C2,arm0C3,arm0C4,arm0C5,arm0C6,arm0C7, // 0C0 + arm0C0,arm0C9,arm0C2,arm0CB,arm0C4,arm_UI,arm0C6,arm_UI, // 0C8 + arm0D0,arm0D1,arm0D2,arm0D3,arm0D4,arm0D5,arm0D6,arm0D7, // 0D0 + arm0D0,arm0D9,arm0D2,arm0DB,arm0D4,arm0DD,arm0D6,arm0DF, // 0D8 + arm0E0,arm0E1,arm0E2,arm0E3,arm0E4,arm0E5,arm0E6,arm0E7, // 0E0 + arm0E0,arm0E9,arm0E2,arm_UI,arm0E4,arm_UI,arm0E6,arm_UI, // 0E8 + arm0F0,arm0F1,arm0F2,arm0F3,arm0F4,arm0F5,arm0F6,arm0F7, // 0F0 + arm0F0,arm0F9,arm0F2,arm_UI,arm0F4,arm0DD,arm0F6,arm0DF, // 0F8 + + arm100,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 100 + arm_UI,arm109,arm_UI,arm10B,arm_UI,arm_UI,arm_UI,arm_UI, // 108 + arm110,arm111,arm112,arm113,arm114,arm115,arm116,arm117, // 110 + arm110,arm_UI,arm112,arm11B,arm114,arm11D,arm116,arm11F, // 118 + arm120,arm121,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_BP, // 120 + arm_UI,arm_UI,arm_UI,arm12B,arm_UI,arm_UI,arm_UI,arm_UI, // 128 + arm130,arm131,arm132,arm133,arm134,arm135,arm136,arm137, // 130 + arm130,arm_UI,arm132,arm13B,arm134,arm13D,arm136,arm13F, // 138 + arm140,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 140 + arm_UI,arm149,arm_UI,arm14B,arm_UI,arm_UI,arm_UI,arm_UI, // 148 + arm150,arm151,arm152,arm153,arm154,arm155,arm156,arm157, // 150 + arm150,arm_UI,arm152,arm15B,arm154,arm15D,arm156,arm15F, // 158 + arm160,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 160 + arm_UI,arm_UI,arm_UI,arm16B,arm_UI,arm_UI,arm_UI,arm_UI, // 168 + arm170,arm171,arm172,arm173,arm174,arm175,arm176,arm177, // 170 + arm170,arm_UI,arm172,arm17B,arm174,arm17D,arm176,arm17F, // 178 + arm180,arm181,arm182,arm183,arm184,arm185,arm186,arm187, // 180 + arm180,arm_UI,arm182,arm18B,arm184,arm_UI,arm186,arm_UI, // 188 + arm190,arm191,arm192,arm193,arm194,arm195,arm196,arm197, // 190 + arm190,arm_UI,arm192,arm19B,arm194,arm19D,arm196,arm19F, // 198 + arm1A0,arm1A1,arm1A2,arm1A3,arm1A4,arm1A5,arm1A6,arm1A7, // 1A0 + arm1A0,arm_UI,arm1A2,arm1AB,arm1A4,arm_UI,arm1A6,arm_UI, // 1A8 + arm1B0,arm1B1,arm1B2,arm1B3,arm1B4,arm1B5,arm1B6,arm1B7, // 1B0 + arm1B0,arm_UI,arm1B2,arm1BB,arm1B4,arm1BD,arm1B6,arm1BF, // 1B8 + arm1C0,arm1C1,arm1C2,arm1C3,arm1C4,arm1C5,arm1C6,arm1C7, // 1C0 + arm1C0,arm_UI,arm1C2,arm1CB,arm1C4,arm_UI,arm1C6,arm_UI, // 1C8 + arm1D0,arm1D1,arm1D2,arm1D3,arm1D4,arm1D5,arm1D6,arm1D7, // 1D0 + arm1D0,arm_UI,arm1D2,arm1DB,arm1D4,arm1DD,arm1D6,arm1DF, // 1D8 + arm1E0,arm1E1,arm1E2,arm1E3,arm1E4,arm1E5,arm1E6,arm1E7, // 1E0 + arm1E0,arm_UI,arm1E2,arm1EB,arm1E4,arm_UI,arm1E6,arm_UI, // 1E8 + arm1F0,arm1F1,arm1F2,arm1F3,arm1F4,arm1F5,arm1F6,arm1F7, // 1F0 + arm1F0,arm_UI,arm1F2,arm1FB,arm1F4,arm1FD,arm1F6,arm1FF, // 1F8 + + REP16(arm200),REP16(arm210),REP16(arm220),REP16(arm230), // 200 + REP16(arm240),REP16(arm250),REP16(arm260),REP16(arm270), // 240 + REP16(arm280),REP16(arm290),REP16(arm2A0),REP16(arm2B0), // 280 + REP16(arm2C0),REP16(arm2D0),REP16(arm2E0),REP16(arm2F0), // 2C0 + REP16(arm_UI),REP16(arm310),REP16(arm320),REP16(arm330), // 300 + REP16(arm_UI),REP16(arm350),REP16(arm360),REP16(arm370), // 340 + REP16(arm380),REP16(arm390),REP16(arm3A0),REP16(arm3B0), // 380 + REP16(arm3C0),REP16(arm3D0),REP16(arm3E0),REP16(arm3F0), // 3C0 + + REP16(arm400),REP16(arm410),REP16(arm400),REP16(arm410), // 400 + REP16(arm440),REP16(arm450),REP16(arm440),REP16(arm450), // 440 + REP16(arm480),REP16(arm490),REP16(arm480),REP16(arm490), // 480 + REP16(arm4C0),REP16(arm4D0),REP16(arm4C0),REP16(arm4D0), // 4C0 + REP16(arm500),REP16(arm510),REP16(arm520),REP16(arm530), // 500 + REP16(arm540),REP16(arm550),REP16(arm560),REP16(arm570), // 540 + REP16(arm580),REP16(arm590),REP16(arm5A0),REP16(arm5B0), // 580 + REP16(arm5C0),REP16(arm5D0),REP16(arm5E0),REP16(arm5F0), // 5C0 + + arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 600 + arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 608 + arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 610 + arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 618 + arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 620 + arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 628 + arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 630 + arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 638 + arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 640 + arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 648 + arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 650 + arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 658 + arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 660 + arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 668 + arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 670 + arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 678 + arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 680 + arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 688 + arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 690 + arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 698 + arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 6A0 + arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 6A8 + arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 6B0 + arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 6B8 + arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6C0 + arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6C8 + arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6D0 + arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6D8 + arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6E0 + arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6E8 + arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6F0 + arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6F8 + + arm700,arm_UI,arm702,arm_UI,arm704,arm_UI,arm706,arm_UI, // 700 + arm700,arm_UI,arm702,arm_UI,arm704,arm_UI,arm706,arm_UI, // 708 + arm710,arm_UI,arm712,arm_UI,arm714,arm_UI,arm716,arm_UI, // 710 + arm710,arm_UI,arm712,arm_UI,arm714,arm_UI,arm716,arm_UI, // 718 + arm720,arm_UI,arm722,arm_UI,arm724,arm_UI,arm726,arm_UI, // 720 + arm720,arm_UI,arm722,arm_UI,arm724,arm_UI,arm726,arm_UI, // 728 + arm730,arm_UI,arm732,arm_UI,arm734,arm_UI,arm736,arm_UI, // 730 + arm730,arm_UI,arm732,arm_UI,arm734,arm_UI,arm736,arm_UI, // 738 + arm740,arm_UI,arm742,arm_UI,arm744,arm_UI,arm746,arm_UI, // 740 + arm740,arm_UI,arm742,arm_UI,arm744,arm_UI,arm746,arm_UI, // 748 + arm750,arm_UI,arm752,arm_UI,arm754,arm_UI,arm756,arm_UI, // 750 + arm750,arm_UI,arm752,arm_UI,arm754,arm_UI,arm756,arm_UI, // 758 + arm760,arm_UI,arm762,arm_UI,arm764,arm_UI,arm766,arm_UI, // 760 + arm760,arm_UI,arm762,arm_UI,arm764,arm_UI,arm766,arm_UI, // 768 + arm770,arm_UI,arm772,arm_UI,arm774,arm_UI,arm776,arm_UI, // 770 + arm770,arm_UI,arm772,arm_UI,arm774,arm_UI,arm776,arm_UI, // 778 + arm780,arm_UI,arm782,arm_UI,arm784,arm_UI,arm786,arm_UI, // 780 + arm780,arm_UI,arm782,arm_UI,arm784,arm_UI,arm786,arm_UI, // 788 + arm790,arm_UI,arm792,arm_UI,arm794,arm_UI,arm796,arm_UI, // 790 + arm790,arm_UI,arm792,arm_UI,arm794,arm_UI,arm796,arm_UI, // 798 + arm7A0,arm_UI,arm7A2,arm_UI,arm7A4,arm_UI,arm7A6,arm_UI, // 7A0 + arm7A0,arm_UI,arm7A2,arm_UI,arm7A4,arm_UI,arm7A6,arm_UI, // 7A8 + arm7B0,arm_UI,arm7B2,arm_UI,arm7B4,arm_UI,arm7B6,arm_UI, // 7B0 + arm7B0,arm_UI,arm7B2,arm_UI,arm7B4,arm_UI,arm7B6,arm_UI, // 7B8 + arm7C0,arm_UI,arm7C2,arm_UI,arm7C4,arm_UI,arm7C6,arm_UI, // 7C0 + arm7C0,arm_UI,arm7C2,arm_UI,arm7C4,arm_UI,arm7C6,arm_UI, // 7C8 + arm7D0,arm_UI,arm7D2,arm_UI,arm7D4,arm_UI,arm7D6,arm_UI, // 7D0 + arm7D0,arm_UI,arm7D2,arm_UI,arm7D4,arm_UI,arm7D6,arm_UI, // 7D8 + arm7E0,arm_UI,arm7E2,arm_UI,arm7E4,arm_UI,arm7E6,arm_UI, // 7E0 + arm7E0,arm_UI,arm7E2,arm_UI,arm7E4,arm_UI,arm7E6,arm_UI, // 7E8 + arm7F0,arm_UI,arm7F2,arm_UI,arm7F4,arm_UI,arm7F6,arm_UI, // 7F0 + arm7F0,arm_UI,arm7F2,arm_UI,arm7F4,arm_UI,arm7F6,arm_BP, // 7F8 + + REP16(arm800),REP16(arm810),REP16(arm820),REP16(arm830), // 800 + REP16(arm840),REP16(arm850),REP16(arm860),REP16(arm870), // 840 + REP16(arm880),REP16(arm890),REP16(arm8A0),REP16(arm8B0), // 880 + REP16(arm8C0),REP16(arm8D0),REP16(arm8E0),REP16(arm8F0), // 8C0 + REP16(arm900),REP16(arm910),REP16(arm920),REP16(arm930), // 900 + REP16(arm940),REP16(arm950),REP16(arm960),REP16(arm970), // 940 + REP16(arm980),REP16(arm990),REP16(arm9A0),REP16(arm9B0), // 980 + REP16(arm9C0),REP16(arm9D0),REP16(arm9E0),REP16(arm9F0), // 9C0 + + REP256(armA00), // A00 + REP256(armB00), // B00 + REP256(arm_UI), // C00 + REP256(arm_UI), // D00 + + arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E00 + arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E08 + arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E10 + arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E18 + REP16(arm_UI), // E20 + REP16(arm_UI), // E30 + REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // E40 + REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // E80 + REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // EC0 + + REP256(armF00), // F00 +}; + +// Wrapper routine (execution loop) /////////////////////////////////////// + +#include +static void tester(void) { + static int ran=0;if(ran)return;ran=1; + FILE*f=fopen("p:\\timing.txt","w");if(!f)return; + for (int op=/*0*/9; op> 28; + bool cond_res = true; + if (UNLIKELY(cond != 0x0E)) { // most opcodes are AL (always) + switch(cond) { + case 0x00: // EQ + cond_res = Z_FLAG; + break; + case 0x01: // NE + cond_res = !Z_FLAG; + break; + case 0x02: // CS + cond_res = C_FLAG; + break; + case 0x03: // CC + cond_res = !C_FLAG; + break; + case 0x04: // MI + cond_res = N_FLAG; + break; + case 0x05: // PL + cond_res = !N_FLAG; + break; + case 0x06: // VS + cond_res = V_FLAG; + break; + case 0x07: // VC + cond_res = !V_FLAG; + break; + case 0x08: // HI + cond_res = C_FLAG && !Z_FLAG; + break; + case 0x09: // LS + cond_res = !C_FLAG || Z_FLAG; + break; + case 0x0A: // GE + cond_res = N_FLAG == V_FLAG; + break; + case 0x0B: // LT + cond_res = N_FLAG != V_FLAG; + break; + case 0x0C: // GT + cond_res = !Z_FLAG &&(N_FLAG == V_FLAG); + break; + case 0x0D: // LE + cond_res = Z_FLAG || (N_FLAG != V_FLAG); + break; + case 0x0E: // AL (impossible, checked above) + cond_res = true; + break; + case 0x0F: + default: + // ??? + cond_res = false; + break; + } + } + + if (cond_res) + (*armInsnTable[((opcode>>16)&0xFF0) | ((opcode>>4)&0x0F)])(opcode); +#ifdef INSN_COUNTER + count(opcode, cond_res); +#endif + if (clockTicks < 0) + return 0; + if (clockTicks == 0) + clockTicks = 1 + codeTicksAccessSeq32(oldArmNextPC); + cpuTotalTicks += clockTicks; + + } while (cpuTotalTicks -#include -#include -#include -#include - -#include "GBA.h" -#include "GBAcpu.h" -#include "GBAinline.h" -#include "../Globals.h" -#include "../EEprom.h" -#include "../Flash.h" -#include "../Sound.h" -#include "../Sram.h" -#include "../bios.h" -#include "../Cheats.h" -#include "../NLS.h" -#include "../elf.h" -#include "../Util.h" -#include "../Port.h" -#include "../System.h" -#include "agbprint.h" -#ifdef PROFILING -#include "prof/prof.h" -#endif - -#ifdef _MSC_VER -#define snprintf _snprintf -#endif - -/////////////////////////////////////////////////////////////////////////// - -static int clockTicks; - -static INSN_REGPARM void thumbUnknownInsn(u32 opcode) -{ -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_UNDEFINED) - log("Undefined THUMB instruction %04x at %08x\n", opcode, armNextPC-2); -#endif - CPUUndefinedException(); -} - -#ifdef BKPT_SUPPORT -static INSN_REGPARM void thumbBreakpoint(u32 opcode) -{ - reg[15].I -= 2; - armNextPC -= 2; - dbgSignal(5, opcode & 255); - clockTicks = -1; -} -#endif - -// Common macros ////////////////////////////////////////////////////////// - -#ifdef BKPT_SUPPORT -# define THUMB_CONSOLE_OUTPUT(a,b) do { \ - if ((opcode == 0x4000) && (reg[0].I == 0xC0DED00D)) { \ - dbgOutput((a), (b)); \ - } \ -} while (0) -# define UPDATE_OLDREG do { \ - if (debugger_last) { \ - snprintf(oldbuffer, sizeof(oldbuffer), "%08X", \ - armState ? reg[15].I - 4 : reg[15].I - 2); \ - int i; \ - for (i = 0; i < 18; i++) { \ - oldreg[i] = reg[i].I; \ - } \ - } \ -} while (0) -#else -# define THUMB_CONSOLE_OUTPUT(a,b) -# define UPDATE_OLDREG -#endif - -#define NEG(i) ((i) >> 31) -#define POS(i) ((~(i)) >> 31) - -#ifndef C_CORE -#ifdef __GNUC__ -#ifdef __POWERPC__ - #define ADD_RD_RS_RN(N) \ - { \ - register int Flags; \ - register int Result; \ - asm volatile("addco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[source].I), \ - "r" (reg[N].I) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define ADD_RD_RS_O3(N) \ - { \ - register int Flags; \ - register int Result; \ - asm volatile("addco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[source].I), \ - "r" (N) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define ADD_RD_RS_O3_0 ADD_RD_RS_O3 - #define ADD_RN_O8(d) \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("addco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[(d)].I), \ - "r" (opcode & 255) \ - ); \ - reg[(d)].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define CMN_RD_RS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("addco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[dest].I), \ - "r" (value) \ - ); \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define ADC_RD_RS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("mtspr xer, %4\n" \ - "addeo. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[dest].I), \ - "r" (value), \ - "r" (C_FLAG << 29) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define SUB_RD_RS_RN(N) \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[source].I), \ - "r" (reg[N].I) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define SUB_RD_RS_O3(N) \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[source].I), \ - "r" (N) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define SUB_RD_RS_O3_0 SUB_RD_RS_O3 - #define SUB_RN_O8(d) \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[(d)].I), \ - "r" (opcode & 255) \ - ); \ - reg[(d)].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define CMP_RN_O8(d) \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[(d)].I), \ - "r" (opcode & 255) \ - ); \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define SBC_RD_RS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("mtspr xer, %4\n" \ - "subfeo. %0, %3, %2\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[dest].I), \ - "r" (value), \ - "r" (C_FLAG << 29) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define NEG_RD_RS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subfco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[source].I), \ - "r" (0) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define CMP_RD_RS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[dest].I), \ - "r" (value) \ - ); \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } -#else - #define ADD_RN_O8(d) \ - asm ("andl $0xFF, %%eax;"\ - "addl %%eax, %0;"\ - "setsb _N_FLAG;"\ - "setzb _Z_FLAG;"\ - "setcb _C_FLAG;"\ - "setob _V_FLAG;"\ - : "=m" (reg[(d)].I)); - #define CMN_RD_RS \ - asm ("add %0, %1;"\ - "setsb _N_FLAG;"\ - "setzb _Z_FLAG;"\ - "setcb _C_FLAG;"\ - "setob _V_FLAG;"\ - : \ - : "r" (value), "r" (reg[dest].I):"1"); - #define ADC_RD_RS \ - asm ("bt $0, _C_FLAG;"\ - "adc %1, %%ebx;"\ - "setsb _N_FLAG;"\ - "setzb _Z_FLAG;"\ - "setcb _C_FLAG;"\ - "setob _V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[dest].I)); - #define SUB_RN_O8(d) \ - asm ("andl $0xFF, %%eax;"\ - "subl %%eax, %0;"\ - "setsb _N_FLAG;"\ - "setzb _Z_FLAG;"\ - "setncb _C_FLAG;"\ - "setob _V_FLAG;"\ - : "=m" (reg[(d)].I)); - #define MOV_RN_O8(d) \ - asm ("andl $0xFF, %%eax;"\ - "movb $0, _N_FLAG;"\ - "movl %%eax, %0;"\ - "setzb _Z_FLAG;"\ - : "=m" (reg[(d)].I)); - #define CMP_RN_O8(d) \ - asm ("andl $0xFF, %%eax;"\ - "cmpl %%eax, %0;"\ - "setsb _N_FLAG;"\ - "setzb _Z_FLAG;"\ - "setncb _C_FLAG;"\ - "setob _V_FLAG;"\ - : \ - : "m" (reg[(d)].I)); - #define SBC_RD_RS \ - asm volatile ("bt $0, _C_FLAG;"\ - "cmc;"\ - "sbb %1, %%ebx;"\ - "setsb _N_FLAG;"\ - "setzb _Z_FLAG;"\ - "setncb _C_FLAG;"\ - "setob _V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[dest].I) : "cc", "memory"); - #define LSL_RD_RS \ - asm ("shl %%cl, %%eax;"\ - "setcb _C_FLAG;"\ - : "=a" (value)\ - : "a" (reg[dest].I), "c" (value)); - #define LSR_RD_RS \ - asm ("shr %%cl, %%eax;"\ - "setcb _C_FLAG;"\ - : "=a" (value)\ - : "a" (reg[dest].I), "c" (value)); - #define ASR_RD_RS \ - asm ("sar %%cl, %%eax;"\ - "setcb _C_FLAG;"\ - : "=a" (value)\ - : "a" (reg[dest].I), "c" (value)); - #define ROR_RD_RS \ - asm ("ror %%cl, %%eax;"\ - "setcb _C_FLAG;"\ - : "=a" (value)\ - : "a" (reg[dest].I), "c" (value)); - #define NEG_RD_RS \ - asm ("neg %%ebx;"\ - "setsb _N_FLAG;"\ - "setzb _Z_FLAG;"\ - "setncb _C_FLAG;"\ - "setob _V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "b" (reg[source].I)); - #define CMP_RD_RS \ - asm ("sub %0, %1;"\ - "setsb _N_FLAG;"\ - "setzb _Z_FLAG;"\ - "setncb _C_FLAG;"\ - "setob _V_FLAG;"\ - : \ - : "r" (value), "r" (reg[dest].I):"1"); - #define IMM5_INSN(OP,N) \ - asm("movl %%eax,%%ecx;" \ - "shrl $1,%%eax;" \ - "andl $7,%%ecx;" \ - "andl $0x1C,%%eax;" \ - "movl _reg(%%eax),%%edx;" \ - OP \ - "setsb _N_FLAG;" \ - "setzb _Z_FLAG;" \ - "movl %%edx,_reg(,%%ecx,4);" \ - : : "i" (N)) - #define IMM5_INSN_0(OP) \ - asm("movl %%eax,%%ecx;" \ - "shrl $1,%%eax;" \ - "andl $7,%%ecx;" \ - "andl $0x1C,%%eax;" \ - "movl _reg(%%eax),%%edx;" \ - OP \ - "setsb _N_FLAG;" \ - "setzb _Z_FLAG;" \ - "movl %%edx,_reg(,%%ecx,4);" \ - : : ) - #define IMM5_LSL \ - "shll %0,%%edx;"\ - "setcb _C_FLAG;" - #define IMM5_LSL_0 \ - "testl %%edx,%%edx;" - #define IMM5_LSR \ - "shrl %0,%%edx;"\ - "setcb _C_FLAG;" - #define IMM5_LSR_0 \ - "testl %%edx,%%edx;"\ - "setsb _C_FLAG;"\ - "xorl %%edx,%%edx;" - #define IMM5_ASR \ - "sarl %0,%%edx;"\ - "setcb _C_FLAG;" - #define IMM5_ASR_0 \ - "sarl $31,%%edx;"\ - "setsb _C_FLAG;" - #define THREEARG_INSN(OP,N) \ - asm("movl %%eax,%%edx;" \ - "shrl $1,%%edx;" \ - "andl $0x1C,%%edx;" \ - "andl $7,%%eax;" \ - "movl _reg(%%edx),%%ecx;" \ - OP(N) \ - "setsb _N_FLAG;" \ - "setzb _Z_FLAG;" \ - "movl %%ecx,_reg(,%%eax,4)"::) - #define ADD_RD_RS_RN(N) \ - "add (_reg+"#N"*4),%%ecx;" \ - "setcb _C_FLAG;" \ - "setob _V_FLAG;" - #define ADD_RD_RS_O3(N) \ - "add $"#N",%%ecx;" \ - "setcb _C_FLAG;" \ - "setob _V_FLAG;" - #define ADD_RD_RS_O3_0(N) \ - "movb $0,_C_FLAG;" \ - "add $0,%%ecx;" \ - "movb $0,_V_FLAG;" - #define SUB_RD_RS_RN(N) \ - "sub (_reg+"#N"*4),%%ecx;" \ - "setncb _C_FLAG;" \ - "setob _V_FLAG;" - #define SUB_RD_RS_O3(N) \ - "sub $"#N",%%ecx;" \ - "setncb _C_FLAG;" \ - "setob _V_FLAG;" - #define SUB_RD_RS_O3_0(N) \ - "movb $1,_C_FLAG;" \ - "sub $0,%%ecx;" \ - "movb $0,_V_FLAG;" -#endif -#else // !__GNUC__ - #define ADD_RD_RS_RN(N) \ - {\ - __asm mov eax, source\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm add ebx, dword ptr [OFFSET reg+4*N]\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - #define ADD_RD_RS_O3(N) \ - {\ - __asm mov eax, source\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm add ebx, N\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - #define ADD_RD_RS_O3_0 \ - {\ - __asm mov eax, source\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm add ebx, 0\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm mov byte ptr C_FLAG, 0\ - __asm mov byte ptr V_FLAG, 0\ - } - #define ADD_RN_O8(d) \ - {\ - __asm mov ebx, opcode\ - __asm and ebx, 255\ - __asm add dword ptr [OFFSET reg+4*(d)], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - #define CMN_RD_RS \ - {\ - __asm mov eax, dest\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm add ebx, value\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - #define ADC_RD_RS \ - {\ - __asm mov ebx, dest\ - __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ - __asm bt word ptr C_FLAG, 0\ - __asm adc ebx, value\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - #define SUB_RD_RS_RN(N) \ - {\ - __asm mov eax, source\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm sub ebx, dword ptr [OFFSET reg+4*N]\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - #define SUB_RD_RS_O3(N) \ - {\ - __asm mov eax, source\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm sub ebx, N\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - #define SUB_RD_RS_O3_0 \ - {\ - __asm mov eax, source\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm sub ebx, 0\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm mov byte ptr C_FLAG, 1\ - __asm mov byte ptr V_FLAG, 0\ - } - #define SUB_RN_O8(d) \ - {\ - __asm mov ebx, opcode\ - __asm and ebx, 255\ - __asm sub dword ptr [OFFSET reg + 4*(d)], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - #define MOV_RN_O8(d) \ - {\ - __asm mov eax, opcode\ - __asm and eax, 255\ - __asm mov dword ptr [OFFSET reg+4*(d)], eax\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - } - #define CMP_RN_O8(d) \ - {\ - __asm mov eax, dword ptr [OFFSET reg+4*(d)]\ - __asm mov ebx, opcode\ - __asm and ebx, 255\ - __asm sub eax, ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - #define SBC_RD_RS \ - {\ - __asm mov ebx, dest\ - __asm mov ebx, dword ptr [OFFSET reg + 4*ebx]\ - __asm mov eax, value\ - __asm bt word ptr C_FLAG, 0\ - __asm cmc\ - __asm sbb ebx, eax\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg + 4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - #define LSL_RD_RM_I5 \ - {\ - __asm mov eax, source\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr shift\ - __asm shl eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } - #define LSL_RD_RS \ - {\ - __asm mov eax, dest\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr value\ - __asm shl eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } - #define LSR_RD_RM_I5 \ - {\ - __asm mov eax, source\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr shift\ - __asm shr eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } - #define LSR_RD_RS \ - {\ - __asm mov eax, dest\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr value\ - __asm shr eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } - #define ASR_RD_RM_I5 \ - {\ - __asm mov eax, source\ - __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ - __asm mov cl, byte ptr shift\ - __asm sar eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } - #define ASR_RD_RS \ - {\ - __asm mov eax, dest\ - __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ - __asm mov cl, byte ptr value\ - __asm sar eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } - #define ROR_RD_RS \ - {\ - __asm mov eax, dest\ - __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ - __asm mov cl, byte ptr value\ - __asm ror eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } - #define NEG_RD_RS \ - {\ - __asm mov ebx, source\ - __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ - __asm neg ebx\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax],ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - #define CMP_RD_RS \ - {\ - __asm mov eax, dest\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm sub ebx, value\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#endif -#endif - -// C core -#ifndef ADDCARRY - #define ADDCARRY(a, b, c) \ - C_FLAG = ((NEG(a) & NEG(b)) |\ - (NEG(a) & POS(c)) |\ - (NEG(b) & POS(c))) ? true : false; -#endif -#ifndef ADDOVERFLOW - #define ADDOVERFLOW(a, b, c) \ - V_FLAG = ((NEG(a) & NEG(b) & POS(c)) |\ - (POS(a) & POS(b) & NEG(c))) ? true : false; -#endif -#ifndef SUBCARRY - #define SUBCARRY(a, b, c) \ - C_FLAG = ((NEG(a) & POS(b)) |\ - (NEG(a) & POS(c)) |\ - (POS(b) & POS(c))) ? true : false; -#endif -#ifndef SUBOVERFLOW - #define SUBOVERFLOW(a, b, c)\ - V_FLAG = ((NEG(a) & POS(b) & POS(c)) |\ - (POS(a) & NEG(b) & NEG(c))) ? true : false; -#endif -#ifndef ADD_RD_RS_RN - #define ADD_RD_RS_RN(N) \ - {\ - u32 lhs = reg[source].I;\ - u32 rhs = reg[N].I;\ - u32 res = lhs + rhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } -#endif -#ifndef ADD_RD_RS_O3 - #define ADD_RD_RS_O3(N) \ - {\ - u32 lhs = reg[source].I;\ - u32 rhs = N;\ - u32 res = lhs + rhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } -#endif -#ifndef ADD_RD_RS_O3_0 -# define ADD_RD_RS_O3_0 ADD_RD_RS_O3 -#endif -#ifndef ADD_RN_O8 - #define ADD_RN_O8(d) \ - {\ - u32 lhs = reg[(d)].I;\ - u32 rhs = (opcode & 255);\ - u32 res = lhs + rhs;\ - reg[(d)].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } -#endif -#ifndef CMN_RD_RS - #define CMN_RD_RS \ - {\ - u32 lhs = reg[dest].I;\ - u32 rhs = value;\ - u32 res = lhs + rhs;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } -#endif -#ifndef ADC_RD_RS - #define ADC_RD_RS \ - {\ - u32 lhs = reg[dest].I;\ - u32 rhs = value;\ - u32 res = lhs + rhs + (u32)C_FLAG;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } -#endif -#ifndef SUB_RD_RS_RN - #define SUB_RD_RS_RN(N) \ - {\ - u32 lhs = reg[source].I;\ - u32 rhs = reg[N].I;\ - u32 res = lhs - rhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#endif -#ifndef SUB_RD_RS_O3 - #define SUB_RD_RS_O3(N) \ - {\ - u32 lhs = reg[source].I;\ - u32 rhs = N;\ - u32 res = lhs - rhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#endif -#ifndef SUB_RD_RS_O3_0 -# define SUB_RD_RS_O3_0 SUB_RD_RS_O3 -#endif -#ifndef SUB_RN_O8 - #define SUB_RN_O8(d) \ - {\ - u32 lhs = reg[(d)].I;\ - u32 rhs = (opcode & 255);\ - u32 res = lhs - rhs;\ - reg[(d)].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#endif -#ifndef MOV_RN_O8 - #define MOV_RN_O8(d) \ - {\ - reg[d].I = opcode & 255;\ - N_FLAG = false;\ - Z_FLAG = (reg[d].I ? false : true);\ - } -#endif -#ifndef CMP_RN_O8 - #define CMP_RN_O8(d) \ - {\ - u32 lhs = reg[(d)].I;\ - u32 rhs = (opcode & 255);\ - u32 res = lhs - rhs;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#endif -#ifndef SBC_RD_RS - #define SBC_RD_RS \ - {\ - u32 lhs = reg[dest].I;\ - u32 rhs = value;\ - u32 res = lhs - rhs - !((u32)C_FLAG);\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#endif -#ifndef LSL_RD_RM_I5 - #define LSL_RD_RM_I5 \ - {\ - C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false;\ - value = reg[source].I << shift;\ - } -#endif -#ifndef LSL_RD_RS - #define LSL_RD_RS \ - {\ - C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false;\ - value = reg[dest].I << value;\ - } -#endif -#ifndef LSR_RD_RM_I5 - #define LSR_RD_RM_I5 \ - {\ - C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false;\ - value = reg[source].I >> shift;\ - } -#endif -#ifndef LSR_RD_RS - #define LSR_RD_RS \ - {\ - C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\ - value = reg[dest].I >> value;\ - } -#endif -#ifndef ASR_RD_RM_I5 - #define ASR_RD_RM_I5 \ - {\ - C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false;\ - value = (s32)reg[source].I >> (int)shift;\ - } -#endif -#ifndef ASR_RD_RS - #define ASR_RD_RS \ - {\ - C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false;\ - value = (s32)reg[dest].I >> (int)value;\ - } -#endif -#ifndef ROR_RD_RS - #define ROR_RD_RS \ - {\ - C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\ - value = ((reg[dest].I << (32 - value)) |\ - (reg[dest].I >> value));\ - } -#endif -#ifndef NEG_RD_RS - #define NEG_RD_RS \ - {\ - u32 lhs = reg[source].I;\ - u32 rhs = 0;\ - u32 res = rhs - lhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(rhs, lhs, res);\ - SUBOVERFLOW(rhs, lhs, res);\ - } -#endif -#ifndef CMP_RD_RS - #define CMP_RD_RS \ - {\ - u32 lhs = reg[dest].I;\ - u32 rhs = value;\ - u32 res = lhs - rhs;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#endif -#ifndef IMM5_INSN - #define IMM5_INSN(OP,N) \ - int dest = opcode & 0x07;\ - int source = (opcode >> 3) & 0x07;\ - u32 value;\ - OP(N);\ - reg[dest].I = value;\ - N_FLAG = (value & 0x80000000 ? true : false);\ - Z_FLAG = (value ? false : true); - #define IMM5_INSN_0(OP) \ - int dest = opcode & 0x07;\ - int source = (opcode >> 3) & 0x07;\ - u32 value;\ - OP;\ - reg[dest].I = value;\ - N_FLAG = (value & 0x80000000 ? true : false);\ - Z_FLAG = (value ? false : true); - #define IMM5_LSL(N) \ - int shift = N;\ - LSL_RD_RM_I5; - #define IMM5_LSL_0 \ - value = reg[source].I; - #define IMM5_LSR(N) \ - int shift = N;\ - LSR_RD_RM_I5; - #define IMM5_LSR_0 \ - C_FLAG = reg[source].I & 0x80000000 ? true : false;\ - value = 0; - #define IMM5_ASR(N) \ - int shift = N;\ - ASR_RD_RM_I5; - #define IMM5_ASR_0 \ - if(reg[source].I & 0x80000000) {\ - value = 0xFFFFFFFF;\ - C_FLAG = true;\ - } else {\ - value = 0;\ - C_FLAG = false;\ - } -#endif -#ifndef THREEARG_INSN - #define THREEARG_INSN(OP,N) \ - int dest = opcode & 0x07; \ - int source = (opcode >> 3) & 0x07; \ - OP(N); -#endif - -// Shift instructions ///////////////////////////////////////////////////// - -#define DEFINE_IMM5_INSN(OP,BASE) \ - static INSN_REGPARM void thumb##BASE##_00(u32 opcode) { IMM5_INSN_0(OP##_0); } \ - static INSN_REGPARM void thumb##BASE##_01(u32 opcode) { IMM5_INSN(OP, 1); } \ - static INSN_REGPARM void thumb##BASE##_02(u32 opcode) { IMM5_INSN(OP, 2); } \ - static INSN_REGPARM void thumb##BASE##_03(u32 opcode) { IMM5_INSN(OP, 3); } \ - static INSN_REGPARM void thumb##BASE##_04(u32 opcode) { IMM5_INSN(OP, 4); } \ - static INSN_REGPARM void thumb##BASE##_05(u32 opcode) { IMM5_INSN(OP, 5); } \ - static INSN_REGPARM void thumb##BASE##_06(u32 opcode) { IMM5_INSN(OP, 6); } \ - static INSN_REGPARM void thumb##BASE##_07(u32 opcode) { IMM5_INSN(OP, 7); } \ - static INSN_REGPARM void thumb##BASE##_08(u32 opcode) { IMM5_INSN(OP, 8); } \ - static INSN_REGPARM void thumb##BASE##_09(u32 opcode) { IMM5_INSN(OP, 9); } \ - static INSN_REGPARM void thumb##BASE##_0A(u32 opcode) { IMM5_INSN(OP,10); } \ - static INSN_REGPARM void thumb##BASE##_0B(u32 opcode) { IMM5_INSN(OP,11); } \ - static INSN_REGPARM void thumb##BASE##_0C(u32 opcode) { IMM5_INSN(OP,12); } \ - static INSN_REGPARM void thumb##BASE##_0D(u32 opcode) { IMM5_INSN(OP,13); } \ - static INSN_REGPARM void thumb##BASE##_0E(u32 opcode) { IMM5_INSN(OP,14); } \ - static INSN_REGPARM void thumb##BASE##_0F(u32 opcode) { IMM5_INSN(OP,15); } \ - static INSN_REGPARM void thumb##BASE##_10(u32 opcode) { IMM5_INSN(OP,16); } \ - static INSN_REGPARM void thumb##BASE##_11(u32 opcode) { IMM5_INSN(OP,17); } \ - static INSN_REGPARM void thumb##BASE##_12(u32 opcode) { IMM5_INSN(OP,18); } \ - static INSN_REGPARM void thumb##BASE##_13(u32 opcode) { IMM5_INSN(OP,19); } \ - static INSN_REGPARM void thumb##BASE##_14(u32 opcode) { IMM5_INSN(OP,20); } \ - static INSN_REGPARM void thumb##BASE##_15(u32 opcode) { IMM5_INSN(OP,21); } \ - static INSN_REGPARM void thumb##BASE##_16(u32 opcode) { IMM5_INSN(OP,22); } \ - static INSN_REGPARM void thumb##BASE##_17(u32 opcode) { IMM5_INSN(OP,23); } \ - static INSN_REGPARM void thumb##BASE##_18(u32 opcode) { IMM5_INSN(OP,24); } \ - static INSN_REGPARM void thumb##BASE##_19(u32 opcode) { IMM5_INSN(OP,25); } \ - static INSN_REGPARM void thumb##BASE##_1A(u32 opcode) { IMM5_INSN(OP,26); } \ - static INSN_REGPARM void thumb##BASE##_1B(u32 opcode) { IMM5_INSN(OP,27); } \ - static INSN_REGPARM void thumb##BASE##_1C(u32 opcode) { IMM5_INSN(OP,28); } \ - static INSN_REGPARM void thumb##BASE##_1D(u32 opcode) { IMM5_INSN(OP,29); } \ - static INSN_REGPARM void thumb##BASE##_1E(u32 opcode) { IMM5_INSN(OP,30); } \ - static INSN_REGPARM void thumb##BASE##_1F(u32 opcode) { IMM5_INSN(OP,31); } - -// LSL Rd, Rm, #Imm 5 -DEFINE_IMM5_INSN(IMM5_LSL,00) -// LSR Rd, Rm, #Imm 5 -DEFINE_IMM5_INSN(IMM5_LSR,08) -// ASR Rd, Rm, #Imm 5 -DEFINE_IMM5_INSN(IMM5_ASR,10) - -// 3-argument ADD/SUB ///////////////////////////////////////////////////// - -#define DEFINE_REG3_INSN(OP,BASE) \ - static INSN_REGPARM void thumb##BASE##_0(u32 opcode) { THREEARG_INSN(OP,0); } \ - static INSN_REGPARM void thumb##BASE##_1(u32 opcode) { THREEARG_INSN(OP,1); } \ - static INSN_REGPARM void thumb##BASE##_2(u32 opcode) { THREEARG_INSN(OP,2); } \ - static INSN_REGPARM void thumb##BASE##_3(u32 opcode) { THREEARG_INSN(OP,3); } \ - static INSN_REGPARM void thumb##BASE##_4(u32 opcode) { THREEARG_INSN(OP,4); } \ - static INSN_REGPARM void thumb##BASE##_5(u32 opcode) { THREEARG_INSN(OP,5); } \ - static INSN_REGPARM void thumb##BASE##_6(u32 opcode) { THREEARG_INSN(OP,6); } \ - static INSN_REGPARM void thumb##BASE##_7(u32 opcode) { THREEARG_INSN(OP,7); } - -#define DEFINE_IMM3_INSN(OP,BASE) \ - static INSN_REGPARM void thumb##BASE##_0(u32 opcode) { THREEARG_INSN(OP##_0,0); } \ - static INSN_REGPARM void thumb##BASE##_1(u32 opcode) { THREEARG_INSN(OP,1); } \ - static INSN_REGPARM void thumb##BASE##_2(u32 opcode) { THREEARG_INSN(OP,2); } \ - static INSN_REGPARM void thumb##BASE##_3(u32 opcode) { THREEARG_INSN(OP,3); } \ - static INSN_REGPARM void thumb##BASE##_4(u32 opcode) { THREEARG_INSN(OP,4); } \ - static INSN_REGPARM void thumb##BASE##_5(u32 opcode) { THREEARG_INSN(OP,5); } \ - static INSN_REGPARM void thumb##BASE##_6(u32 opcode) { THREEARG_INSN(OP,6); } \ - static INSN_REGPARM void thumb##BASE##_7(u32 opcode) { THREEARG_INSN(OP,7); } - -// ADD Rd, Rs, Rn -DEFINE_REG3_INSN(ADD_RD_RS_RN,18) -// SUB Rd, Rs, Rn -DEFINE_REG3_INSN(SUB_RD_RS_RN,1A) -// ADD Rd, Rs, #Offset3 -DEFINE_IMM3_INSN(ADD_RD_RS_O3,1C) -// SUB Rd, Rs, #Offset3 -DEFINE_IMM3_INSN(SUB_RD_RS_O3,1E) - -// MOV/CMP/ADD/SUB immediate ////////////////////////////////////////////// - -// MOV R0, #Offset8 -static INSN_REGPARM void thumb20(u32 opcode) { MOV_RN_O8(0); } -// MOV R1, #Offset8 -static INSN_REGPARM void thumb21(u32 opcode) { MOV_RN_O8(1); } -// MOV R2, #Offset8 -static INSN_REGPARM void thumb22(u32 opcode) { MOV_RN_O8(2); } -// MOV R3, #Offset8 -static INSN_REGPARM void thumb23(u32 opcode) { MOV_RN_O8(3); } -// MOV R4, #Offset8 -static INSN_REGPARM void thumb24(u32 opcode) { MOV_RN_O8(4); } -// MOV R5, #Offset8 -static INSN_REGPARM void thumb25(u32 opcode) { MOV_RN_O8(5); } -// MOV R6, #Offset8 -static INSN_REGPARM void thumb26(u32 opcode) { MOV_RN_O8(6); } -// MOV R7, #Offset8 -static INSN_REGPARM void thumb27(u32 opcode) { MOV_RN_O8(7); } - -// CMP R0, #Offset8 -static INSN_REGPARM void thumb28(u32 opcode) { CMP_RN_O8(0); } -// CMP R1, #Offset8 -static INSN_REGPARM void thumb29(u32 opcode) { CMP_RN_O8(1); } -// CMP R2, #Offset8 -static INSN_REGPARM void thumb2A(u32 opcode) { CMP_RN_O8(2); } -// CMP R3, #Offset8 -static INSN_REGPARM void thumb2B(u32 opcode) { CMP_RN_O8(3); } -// CMP R4, #Offset8 -static INSN_REGPARM void thumb2C(u32 opcode) { CMP_RN_O8(4); } -// CMP R5, #Offset8 -static INSN_REGPARM void thumb2D(u32 opcode) { CMP_RN_O8(5); } -// CMP R6, #Offset8 -static INSN_REGPARM void thumb2E(u32 opcode) { CMP_RN_O8(6); } -// CMP R7, #Offset8 -static INSN_REGPARM void thumb2F(u32 opcode) { CMP_RN_O8(7); } - -// ADD R0,#Offset8 -static INSN_REGPARM void thumb30(u32 opcode) { ADD_RN_O8(0); } -// ADD R1,#Offset8 -static INSN_REGPARM void thumb31(u32 opcode) { ADD_RN_O8(1); } -// ADD R2,#Offset8 -static INSN_REGPARM void thumb32(u32 opcode) { ADD_RN_O8(2); } -// ADD R3,#Offset8 -static INSN_REGPARM void thumb33(u32 opcode) { ADD_RN_O8(3); } -// ADD R4,#Offset8 -static INSN_REGPARM void thumb34(u32 opcode) { ADD_RN_O8(4); } -// ADD R5,#Offset8 -static INSN_REGPARM void thumb35(u32 opcode) { ADD_RN_O8(5); } -// ADD R6,#Offset8 -static INSN_REGPARM void thumb36(u32 opcode) { ADD_RN_O8(6); } -// ADD R7,#Offset8 -static INSN_REGPARM void thumb37(u32 opcode) { ADD_RN_O8(7); } - -// SUB R0,#Offset8 -static INSN_REGPARM void thumb38(u32 opcode) { SUB_RN_O8(0); } -// SUB R1,#Offset8 -static INSN_REGPARM void thumb39(u32 opcode) { SUB_RN_O8(1); } -// SUB R2,#Offset8 -static INSN_REGPARM void thumb3A(u32 opcode) { SUB_RN_O8(2); } -// SUB R3,#Offset8 -static INSN_REGPARM void thumb3B(u32 opcode) { SUB_RN_O8(3); } -// SUB R4,#Offset8 -static INSN_REGPARM void thumb3C(u32 opcode) { SUB_RN_O8(4); } -// SUB R5,#Offset8 -static INSN_REGPARM void thumb3D(u32 opcode) { SUB_RN_O8(5); } -// SUB R6,#Offset8 -static INSN_REGPARM void thumb3E(u32 opcode) { SUB_RN_O8(6); } -// SUB R7,#Offset8 -static INSN_REGPARM void thumb3F(u32 opcode) { SUB_RN_O8(7); } - -// ALU operations ///////////////////////////////////////////////////////// - -// AND Rd, Rs -static INSN_REGPARM void thumb40_0(u32 opcode) -{ - int dest = opcode & 7; - reg[dest].I &= reg[(opcode >> 3)&7].I; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = reg[dest].I ? false : true; - THUMB_CONSOLE_OUTPUT(NULL, reg[2].I); -} - -// EOR Rd, Rs -static INSN_REGPARM void thumb40_1(u32 opcode) -{ - int dest = opcode & 7; - reg[dest].I ^= reg[(opcode >> 3)&7].I; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = reg[dest].I ? false : true; -} - -// LSL Rd, Rs -static INSN_REGPARM void thumb40_2(u32 opcode) -{ - int dest = opcode & 7; - u32 value = reg[(opcode >> 3)&7].B.B0; - if(value) { - if(value == 32) { - value = 0; - C_FLAG = (reg[dest].I & 1 ? true : false); - } else if(value < 32) { - LSL_RD_RS; - } else { - value = 0; - C_FLAG = false; - } - reg[dest].I = value; - } - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = reg[dest].I ? false : true; - clockTicks = codeTicksAccess16(armNextPC)+2; -} - -// LSR Rd, Rs -static INSN_REGPARM void thumb40_3(u32 opcode) -{ - int dest = opcode & 7; - u32 value = reg[(opcode >> 3)&7].B.B0; - if(value) { - if(value == 32) { - value = 0; - C_FLAG = (reg[dest].I & 0x80000000 ? true : false); - } else if(value < 32) { - LSR_RD_RS; - } else { - value = 0; - C_FLAG = false; - } - reg[dest].I = value; - } - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = reg[dest].I ? false : true; - clockTicks = codeTicksAccess16(armNextPC)+2; -} - -// ASR Rd, Rs -static INSN_REGPARM void thumb41_0(u32 opcode) -{ - int dest = opcode & 7; - u32 value = reg[(opcode >> 3)&7].B.B0; - if(value) { - if(value < 32) { - ASR_RD_RS; - reg[dest].I = value; - } else { - if(reg[dest].I & 0x80000000){ - reg[dest].I = 0xFFFFFFFF; - C_FLAG = true; - } else { - reg[dest].I = 0x00000000; - C_FLAG = false; - } - } - } - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = reg[dest].I ? false : true; - clockTicks = codeTicksAccess16(armNextPC)+2; -} - -// ADC Rd, Rs -static INSN_REGPARM void thumb41_1(u32 opcode) -{ - int dest = opcode & 0x07; - u32 value = reg[(opcode >> 3)&7].I; - ADC_RD_RS; -} - -// SBC Rd, Rs -static INSN_REGPARM void thumb41_2(u32 opcode) -{ - int dest = opcode & 0x07; - u32 value = reg[(opcode >> 3)&7].I; - SBC_RD_RS; -} - -// ROR Rd, Rs -static INSN_REGPARM void thumb41_3(u32 opcode) -{ - int dest = opcode & 7; - u32 value = reg[(opcode >> 3)&7].B.B0; - - if(value) { - value = value & 0x1f; - if(value == 0) { - C_FLAG = (reg[dest].I & 0x80000000 ? true : false); - } else { - ROR_RD_RS; - reg[dest].I = value; - } - } - clockTicks = codeTicksAccess16(armNextPC)+2; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = reg[dest].I ? false : true; -} - -// TST Rd, Rs -static INSN_REGPARM void thumb42_0(u32 opcode) -{ - u32 value = reg[opcode & 7].I & reg[(opcode >> 3) & 7].I; - N_FLAG = value & 0x80000000 ? true : false; - Z_FLAG = value ? false : true; -} - -// NEG Rd, Rs -static INSN_REGPARM void thumb42_1(u32 opcode) -{ - int dest = opcode & 7; - int source = (opcode >> 3) & 7; - NEG_RD_RS; -} - -// CMP Rd, Rs -static INSN_REGPARM void thumb42_2(u32 opcode) -{ - int dest = opcode & 7; - u32 value = reg[(opcode >> 3)&7].I; - CMP_RD_RS; -} - -// CMN Rd, Rs -static INSN_REGPARM void thumb42_3(u32 opcode) -{ - int dest = opcode & 7; - u32 value = reg[(opcode >> 3)&7].I; - CMN_RD_RS; -} - -// ORR Rd, Rs -static INSN_REGPARM void thumb43_0(u32 opcode) -{ - int dest = opcode & 7; - reg[dest].I |= reg[(opcode >> 3) & 7].I; - Z_FLAG = reg[dest].I ? false : true; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; -} - -// MUL Rd, Rs -static INSN_REGPARM void thumb43_1(u32 opcode) -{ - clockTicks = 1; - int dest = opcode & 7; - u32 rm = reg[dest].I; - reg[dest].I = reg[(opcode >> 3) & 7].I * rm; - if (((s32)rm) < 0) - rm = ~rm; - if ((rm & 0xFFFFFF00) == 0) - clockTicks += 0; - else if ((rm & 0xFFFF0000) == 0) - clockTicks += 1; - else if ((rm & 0xFF000000) == 0) - clockTicks += 2; - else - clockTicks += 3; - busPrefetchCount = (busPrefetchCount<>(8-clockTicks)); - clockTicks += codeTicksAccess16(armNextPC) + 1; - Z_FLAG = reg[dest].I ? false : true; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; -} - -// BIC Rd, Rs -static INSN_REGPARM void thumb43_2(u32 opcode) -{ - int dest = opcode & 7; - reg[dest].I &= (~reg[(opcode >> 3) & 7].I); - Z_FLAG = reg[dest].I ? false : true; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; -} - -// MVN Rd, Rs -static INSN_REGPARM void thumb43_3(u32 opcode) -{ - int dest = opcode & 7; - reg[dest].I = ~reg[(opcode >> 3) & 7].I; - Z_FLAG = reg[dest].I ? false : true; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; -} - -// High-register instructions and BX ////////////////////////////////////// - -// ADD Rd, Hs -static INSN_REGPARM void thumb44_1(u32 opcode) -{ - reg[opcode&7].I += reg[((opcode>>3)&7)+8].I; -} - -// ADD Hd, Rs -static INSN_REGPARM void thumb44_2(u32 opcode) -{ - reg[(opcode&7)+8].I += reg[(opcode>>3)&7].I; - if((opcode&7) == 7) { - reg[15].I &= 0xFFFFFFFE; - armNextPC = reg[15].I; - reg[15].I += 2; - THUMB_PREFETCH; - clockTicks = codeTicksAccessSeq16(armNextPC)*2 - + codeTicksAccess16(armNextPC) + 3; - } -} - -// ADD Hd, Hs -static INSN_REGPARM void thumb44_3(u32 opcode) -{ - reg[(opcode&7)+8].I += reg[((opcode>>3)&7)+8].I; - if((opcode&7) == 7) { - reg[15].I &= 0xFFFFFFFE; - armNextPC = reg[15].I; - reg[15].I += 2; - THUMB_PREFETCH; - clockTicks = codeTicksAccessSeq16(armNextPC)*2 - + codeTicksAccess16(armNextPC) + 3; - } -} - -// CMP Rd, Hs -static INSN_REGPARM void thumb45_1(u32 opcode) -{ - int dest = opcode & 7; - u32 value = reg[((opcode>>3)&7)+8].I; - CMP_RD_RS; -} - -// CMP Hd, Rs -static INSN_REGPARM void thumb45_2(u32 opcode) -{ - int dest = (opcode & 7) + 8; - u32 value = reg[(opcode>>3)&7].I; - CMP_RD_RS; -} - -// CMP Hd, Hs -static INSN_REGPARM void thumb45_3(u32 opcode) -{ - int dest = (opcode & 7) + 8; - u32 value = reg[((opcode>>3)&7)+8].I; - CMP_RD_RS; -} - -// MOV Rd, Hs -static INSN_REGPARM void thumb46_1(u32 opcode) -{ - reg[opcode&7].I = reg[((opcode>>3)&7)+8].I; -} - -// MOV Hd, Rs -static INSN_REGPARM void thumb46_2(u32 opcode) -{ - reg[(opcode&7)+8].I = reg[(opcode>>3)&7].I; - if((opcode&7) == 7) { - UPDATE_OLDREG; - reg[15].I &= 0xFFFFFFFE; - armNextPC = reg[15].I; - reg[15].I += 2; - THUMB_PREFETCH; - clockTicks = codeTicksAccessSeq16(armNextPC)*2 - + codeTicksAccess16(armNextPC) + 3; - } -} - -// MOV Hd, Hs -static INSN_REGPARM void thumb46_3(u32 opcode) -{ - reg[(opcode&7)+8].I = reg[((opcode>>3)&7)+8].I; - if((opcode&7) == 7) { - UPDATE_OLDREG; - reg[15].I &= 0xFFFFFFFE; - armNextPC = reg[15].I; - reg[15].I += 2; - THUMB_PREFETCH; - clockTicks = codeTicksAccessSeq16(armNextPC)*2 - + codeTicksAccess16(armNextPC) + 3; - } -} - - -// BX Rs -static INSN_REGPARM void thumb47(u32 opcode) -{ - int base = (opcode >> 3) & 15; - busPrefetchCount=0; - UPDATE_OLDREG; - reg[15].I = reg[base].I; - if(reg[base].I & 1) { - armState = false; - reg[15].I &= 0xFFFFFFFE; - armNextPC = reg[15].I; - reg[15].I += 2; - THUMB_PREFETCH; - clockTicks = codeTicksAccessSeq16(armNextPC) - + codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 3; - } else { - armState = true; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - ARM_PREFETCH; - clockTicks = codeTicksAccessSeq32(armNextPC) - + codeTicksAccessSeq32(armNextPC) + codeTicksAccess32(armNextPC) + 3; - } -} - -// Load/store instructions //////////////////////////////////////////////// - -// LDR R0~R7,[PC, #Imm] -static INSN_REGPARM void thumb48(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); - reg[regist].I = CPUReadMemoryQuick(address); - busPrefetchCount=0; - clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); -} - -// STR Rd, [Rs, Rn] -static INSN_REGPARM void thumb50(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - CPUWriteMemory(address, reg[opcode & 7].I); - clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2; -} - -// STRH Rd, [Rs, Rn] -static INSN_REGPARM void thumb52(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - CPUWriteHalfWord(address, reg[opcode&7].W.W0); - clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2; -} - -// STRB Rd, [Rs, Rn] -static INSN_REGPARM void thumb54(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + reg[(opcode >>6)&7].I; - CPUWriteByte(address, reg[opcode & 7].B.B0); - clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2; -} - -// LDSB Rd, [Rs, Rn] -static INSN_REGPARM void thumb56(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - reg[opcode&7].I = (s8)CPUReadByte(address); - clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); -} - -// LDR Rd, [Rs, Rn] -static INSN_REGPARM void thumb58(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - reg[opcode&7].I = CPUReadMemory(address); - clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); -} - -// LDRH Rd, [Rs, Rn] -static INSN_REGPARM void thumb5A(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - reg[opcode&7].I = CPUReadHalfWord(address); - clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); -} - -// LDRB Rd, [Rs, Rn] -static INSN_REGPARM void thumb5C(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - reg[opcode&7].I = CPUReadByte(address); - clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); -} - -// LDSH Rd, [Rs, Rn] -static INSN_REGPARM void thumb5E(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - reg[opcode&7].I = (s16)CPUReadHalfWordSigned(address); - clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); -} - -// STR Rd, [Rs, #Imm] -static INSN_REGPARM void thumb60(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2); - CPUWriteMemory(address, reg[opcode&7].I); - clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2; -} - -// LDR Rd, [Rs, #Imm] -static INSN_REGPARM void thumb68(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2); - reg[opcode&7].I = CPUReadMemory(address); - clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); -} - -// STRB Rd, [Rs, #Imm] -static INSN_REGPARM void thumb70(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)); - CPUWriteByte(address, reg[opcode&7].B.B0); - clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2; -} - -// LDRB Rd, [Rs, #Imm] -static INSN_REGPARM void thumb78(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)); - reg[opcode&7].I = CPUReadByte(address); - clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); -} - -// STRH Rd, [Rs, #Imm] -static INSN_REGPARM void thumb80(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1); - CPUWriteHalfWord(address, reg[opcode&7].W.W0); - clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2; -} - -// LDRH Rd, [Rs, #Imm] -static INSN_REGPARM void thumb88(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1); - reg[opcode&7].I = CPUReadHalfWord(address); - clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); -} - -// STR R0~R7, [SP, #Imm] -static INSN_REGPARM void thumb90(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[13].I + ((opcode&255)<<2); - CPUWriteMemory(address, reg[regist].I); - clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2; -} - -// LDR R0~R7, [SP, #Imm] -static INSN_REGPARM void thumb98(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[13].I + ((opcode&255)<<2); - reg[regist].I = CPUReadMemoryQuick(address); - clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); -} - -// PC/stack-related /////////////////////////////////////////////////////// - -// ADD R0~R7, PC, Imm -static INSN_REGPARM void thumbA0(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - reg[regist].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); -} - -// ADD R0~R7, SP, Imm -static INSN_REGPARM void thumbA8(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - reg[regist].I = reg[13].I + ((opcode&255)<<2); -} - -// ADD SP, Imm -static INSN_REGPARM void thumbB0(u32 opcode) -{ - int offset = (opcode & 127) << 2; - if(opcode & 0x80) - offset = -offset; - reg[13].I += offset; -} - -// Push and pop /////////////////////////////////////////////////////////// - -#define PUSH_REG(val, r) \ - if (opcode & (val)) { \ - CPUWriteMemory(address, reg[(r)].I); \ - if (!count) { \ - clockTicks += 1 + dataTicksAccess32(address); \ - } else { \ - clockTicks += 1 + dataTicksAccessSeq32(address); \ - } \ - count++; \ - address += 4; \ - } - -#define POP_REG(val, r) \ - if (opcode & (val)) { \ - reg[(r)].I = CPUReadMemory(address); \ - if (!count) { \ - clockTicks += 1 + dataTicksAccess32(address); \ - } else { \ - clockTicks += 1 + dataTicksAccessSeq32(address); \ - } \ - count++; \ - address += 4; \ - } - -// PUSH {Rlist} -static INSN_REGPARM void thumbB4(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int count = 0; - u32 temp = reg[13].I - 4 * cpuBitsSet[opcode & 0xff]; - u32 address = temp & 0xFFFFFFFC; - PUSH_REG(1, 0); - PUSH_REG(2, 1); - PUSH_REG(4, 2); - PUSH_REG(8, 3); - PUSH_REG(16, 4); - PUSH_REG(32, 5); - PUSH_REG(64, 6); - PUSH_REG(128, 7); - clockTicks += 1 + codeTicksAccess16(armNextPC); - reg[13].I = temp; -} - -// PUSH {Rlist, LR} -static INSN_REGPARM void thumbB5(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int count = 0; - u32 temp = reg[13].I - 4 - 4 * cpuBitsSet[opcode & 0xff]; - u32 address = temp & 0xFFFFFFFC; - PUSH_REG(1, 0); - PUSH_REG(2, 1); - PUSH_REG(4, 2); - PUSH_REG(8, 3); - PUSH_REG(16, 4); - PUSH_REG(32, 5); - PUSH_REG(64, 6); - PUSH_REG(128, 7); - PUSH_REG(256, 14); - clockTicks += 1 + codeTicksAccess16(armNextPC); - reg[13].I = temp; -} - -// POP {Rlist} -static INSN_REGPARM void thumbBC(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int count = 0; - u32 address = reg[13].I & 0xFFFFFFFC; - u32 temp = reg[13].I + 4*cpuBitsSet[opcode & 0xFF]; - POP_REG(1, 0); - POP_REG(2, 1); - POP_REG(4, 2); - POP_REG(8, 3); - POP_REG(16, 4); - POP_REG(32, 5); - POP_REG(64, 6); - POP_REG(128, 7); - reg[13].I = temp; - clockTicks = 2 + codeTicksAccess16(armNextPC); -} - -// POP {Rlist, PC} -static INSN_REGPARM void thumbBD(u32 opcode) -{ - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - int count = 0; - u32 address = reg[13].I & 0xFFFFFFFC; - u32 temp = reg[13].I + 4 + 4*cpuBitsSet[opcode & 0xFF]; - POP_REG(1, 0); - POP_REG(2, 1); - POP_REG(4, 2); - POP_REG(8, 3); - POP_REG(16, 4); - POP_REG(32, 5); - POP_REG(64, 6); - POP_REG(128, 7); - reg[15].I = (CPUReadMemory(address) & 0xFFFFFFFE); - if (!count) { - clockTicks += 1 + dataTicksAccess32(address); - } else { - clockTicks += 1 + dataTicksAccessSeq32(address); - } - count++; - armNextPC = reg[15].I; - reg[15].I += 2; - reg[13].I = temp; - THUMB_PREFETCH; - busPrefetchCount = 0; - clockTicks += 3 + codeTicksAccess16(armNextPC) + codeTicksAccess16(armNextPC); -} - -// Load/store multiple //////////////////////////////////////////////////// - -#define THUMB_STM_REG(val,r,b) \ - if(opcode & (val)) { \ - CPUWriteMemory(address, reg[(r)].I); \ - reg[(b)].I = temp; \ - if (!count) { \ - clockTicks += 1 + dataTicksAccess32(address); \ - } else { \ - clockTicks += 1 + dataTicksAccessSeq32(address); \ - } \ - count++; \ - address += 4; \ - } - -#define THUMB_LDM_REG(val,r) \ - if(opcode & (val)) { \ - reg[(r)].I = CPUReadMemory(address); \ - if (!count) { \ - clockTicks += 1 + dataTicksAccess32(address); \ - } else { \ - clockTicks += 1 + dataTicksAccessSeq32(address); \ - } \ - count++; \ - address += 4; \ - } - -// STM R0~7!, {Rlist} -static INSN_REGPARM void thumbC0(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[regist].I & 0xFFFFFFFC; - u32 temp = reg[regist].I + 4*cpuBitsSet[opcode & 0xff]; - int count = 0; - // store - THUMB_STM_REG(1, 0, regist); - THUMB_STM_REG(2, 1, regist); - THUMB_STM_REG(4, 2, regist); - THUMB_STM_REG(8, 3, regist); - THUMB_STM_REG(16, 4, regist); - THUMB_STM_REG(32, 5, regist); - THUMB_STM_REG(64, 6, regist); - THUMB_STM_REG(128, 7, regist); - clockTicks = 1 + codeTicksAccess16(armNextPC); -} - -// LDM R0~R7!, {Rlist} -static INSN_REGPARM void thumbC8(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - if (busPrefetchCount == 0) - busPrefetch = busPrefetchEnable; - u32 address = reg[regist].I & 0xFFFFFFFC; - u32 temp = reg[regist].I + 4*cpuBitsSet[opcode & 0xFF]; - int count = 0; - // load - THUMB_LDM_REG(1, 0); - THUMB_LDM_REG(2, 1); - THUMB_LDM_REG(4, 2); - THUMB_LDM_REG(8, 3); - THUMB_LDM_REG(16, 4); - THUMB_LDM_REG(32, 5); - THUMB_LDM_REG(64, 6); - THUMB_LDM_REG(128, 7); - clockTicks = 2 + codeTicksAccess16(armNextPC); - if(!(opcode & (1<>6])(opcode); - - if (clockTicks < 0) - return 0; - if (clockTicks==0) - clockTicks = codeTicksAccessSeq16(oldArmNextPC) + 1; - cpuTotalTicks += clockTicks; - - } while (cpuTotalTicks < cpuNextEvent && !armState && !holdState && !SWITicks); - return 1; -} +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include +#include +#include +#include + +#include "GBA.h" +#include "GBAcpu.h" +#include "GBAinline.h" +#include "../Globals.h" +#include "../EEprom.h" +#include "../Flash.h" +#include "../Sound.h" +#include "../Sram.h" +#include "../bios.h" +#include "../Cheats.h" +#include "../NLS.h" +#include "../elf.h" +#include "../Util.h" +#include "../Port.h" +#include "../System.h" +#include "agbprint.h" +#ifdef PROFILING +#include "prof/prof.h" +#endif + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + +/////////////////////////////////////////////////////////////////////////// + +static int clockTicks; + +static INSN_REGPARM void thumbUnknownInsn(u32 opcode) +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_UNDEFINED) + log("Undefined THUMB instruction %04x at %08x\n", opcode, armNextPC-2); +#endif + CPUUndefinedException(); +} + +#ifdef BKPT_SUPPORT +static INSN_REGPARM void thumbBreakpoint(u32 opcode) +{ + reg[15].I -= 2; + armNextPC -= 2; + dbgSignal(5, opcode & 255); + clockTicks = -1; +} +#endif + +// Common macros ////////////////////////////////////////////////////////// + +#ifdef BKPT_SUPPORT +# define THUMB_CONSOLE_OUTPUT(a,b) do { \ + if ((opcode == 0x4000) && (reg[0].I == 0xC0DED00D)) { \ + dbgOutput((a), (b)); \ + } \ +} while (0) +# define UPDATE_OLDREG do { \ + if (debugger_last) { \ + snprintf(oldbuffer, sizeof(oldbuffer), "%08X", \ + armState ? reg[15].I - 4 : reg[15].I - 2); \ + int i; \ + for (i = 0; i < 18; i++) { \ + oldreg[i] = reg[i].I; \ + } \ + } \ +} while (0) +#else +# define THUMB_CONSOLE_OUTPUT(a,b) +# define UPDATE_OLDREG +#endif + +#define NEG(i) ((i) >> 31) +#define POS(i) ((~(i)) >> 31) + +#ifndef C_CORE +#ifdef __GNUC__ +#ifdef __POWERPC__ + #define ADD_RD_RS_RN(N) \ + { \ + register int Flags; \ + register int Result; \ + asm volatile("addco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[source].I), \ + "r" (reg[N].I) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define ADD_RD_RS_O3(N) \ + { \ + register int Flags; \ + register int Result; \ + asm volatile("addco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[source].I), \ + "r" (N) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define ADD_RD_RS_O3_0 ADD_RD_RS_O3 + #define ADD_RN_O8(d) \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("addco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[(d)].I), \ + "r" (opcode & 255) \ + ); \ + reg[(d)].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define CMN_RD_RS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("addco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[dest].I), \ + "r" (value) \ + ); \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define ADC_RD_RS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("mtspr xer, %4\n" \ + "addeo. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[dest].I), \ + "r" (value), \ + "r" (C_FLAG << 29) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define SUB_RD_RS_RN(N) \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[source].I), \ + "r" (reg[N].I) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define SUB_RD_RS_O3(N) \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[source].I), \ + "r" (N) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define SUB_RD_RS_O3_0 SUB_RD_RS_O3 + #define SUB_RN_O8(d) \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[(d)].I), \ + "r" (opcode & 255) \ + ); \ + reg[(d)].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define CMP_RN_O8(d) \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[(d)].I), \ + "r" (opcode & 255) \ + ); \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define SBC_RD_RS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("mtspr xer, %4\n" \ + "subfeo. %0, %3, %2\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[dest].I), \ + "r" (value), \ + "r" (C_FLAG << 29) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define NEG_RD_RS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subfco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[source].I), \ + "r" (0) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define CMP_RD_RS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[dest].I), \ + "r" (value) \ + ); \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } +#else + #define ADD_RN_O8(d) \ + asm ("andl $0xFF, %%eax;"\ + "addl %%eax, %0;"\ + "setsb _N_FLAG;"\ + "setzb _Z_FLAG;"\ + "setcb _C_FLAG;"\ + "setob _V_FLAG;"\ + : "=m" (reg[(d)].I)); + #define CMN_RD_RS \ + asm ("add %0, %1;"\ + "setsb _N_FLAG;"\ + "setzb _Z_FLAG;"\ + "setcb _C_FLAG;"\ + "setob _V_FLAG;"\ + : \ + : "r" (value), "r" (reg[dest].I):"1"); + #define ADC_RD_RS \ + asm ("bt $0, _C_FLAG;"\ + "adc %1, %%ebx;"\ + "setsb _N_FLAG;"\ + "setzb _Z_FLAG;"\ + "setcb _C_FLAG;"\ + "setob _V_FLAG;"\ + : "=b" (reg[dest].I)\ + : "r" (value), "b" (reg[dest].I)); + #define SUB_RN_O8(d) \ + asm ("andl $0xFF, %%eax;"\ + "subl %%eax, %0;"\ + "setsb _N_FLAG;"\ + "setzb _Z_FLAG;"\ + "setncb _C_FLAG;"\ + "setob _V_FLAG;"\ + : "=m" (reg[(d)].I)); + #define MOV_RN_O8(d) \ + asm ("andl $0xFF, %%eax;"\ + "movb $0, _N_FLAG;"\ + "movl %%eax, %0;"\ + "setzb _Z_FLAG;"\ + : "=m" (reg[(d)].I)); + #define CMP_RN_O8(d) \ + asm ("andl $0xFF, %%eax;"\ + "cmpl %%eax, %0;"\ + "setsb _N_FLAG;"\ + "setzb _Z_FLAG;"\ + "setncb _C_FLAG;"\ + "setob _V_FLAG;"\ + : \ + : "m" (reg[(d)].I)); + #define SBC_RD_RS \ + asm volatile ("bt $0, _C_FLAG;"\ + "cmc;"\ + "sbb %1, %%ebx;"\ + "setsb _N_FLAG;"\ + "setzb _Z_FLAG;"\ + "setncb _C_FLAG;"\ + "setob _V_FLAG;"\ + : "=b" (reg[dest].I)\ + : "r" (value), "b" (reg[dest].I) : "cc", "memory"); + #define LSL_RD_RS \ + asm ("shl %%cl, %%eax;"\ + "setcb _C_FLAG;"\ + : "=a" (value)\ + : "a" (reg[dest].I), "c" (value)); + #define LSR_RD_RS \ + asm ("shr %%cl, %%eax;"\ + "setcb _C_FLAG;"\ + : "=a" (value)\ + : "a" (reg[dest].I), "c" (value)); + #define ASR_RD_RS \ + asm ("sar %%cl, %%eax;"\ + "setcb _C_FLAG;"\ + : "=a" (value)\ + : "a" (reg[dest].I), "c" (value)); + #define ROR_RD_RS \ + asm ("ror %%cl, %%eax;"\ + "setcb _C_FLAG;"\ + : "=a" (value)\ + : "a" (reg[dest].I), "c" (value)); + #define NEG_RD_RS \ + asm ("neg %%ebx;"\ + "setsb _N_FLAG;"\ + "setzb _Z_FLAG;"\ + "setncb _C_FLAG;"\ + "setob _V_FLAG;"\ + : "=b" (reg[dest].I)\ + : "b" (reg[source].I)); + #define CMP_RD_RS \ + asm ("sub %0, %1;"\ + "setsb _N_FLAG;"\ + "setzb _Z_FLAG;"\ + "setncb _C_FLAG;"\ + "setob _V_FLAG;"\ + : \ + : "r" (value), "r" (reg[dest].I):"1"); + #define IMM5_INSN(OP,N) \ + asm("movl %%eax,%%ecx;" \ + "shrl $1,%%eax;" \ + "andl $7,%%ecx;" \ + "andl $0x1C,%%eax;" \ + "movl _reg(%%eax),%%edx;" \ + OP \ + "setsb _N_FLAG;" \ + "setzb _Z_FLAG;" \ + "movl %%edx,_reg(,%%ecx,4);" \ + : : "i" (N)) + #define IMM5_INSN_0(OP) \ + asm("movl %%eax,%%ecx;" \ + "shrl $1,%%eax;" \ + "andl $7,%%ecx;" \ + "andl $0x1C,%%eax;" \ + "movl _reg(%%eax),%%edx;" \ + OP \ + "setsb _N_FLAG;" \ + "setzb _Z_FLAG;" \ + "movl %%edx,_reg(,%%ecx,4);" \ + : : ) + #define IMM5_LSL \ + "shll %0,%%edx;"\ + "setcb _C_FLAG;" + #define IMM5_LSL_0 \ + "testl %%edx,%%edx;" + #define IMM5_LSR \ + "shrl %0,%%edx;"\ + "setcb _C_FLAG;" + #define IMM5_LSR_0 \ + "testl %%edx,%%edx;"\ + "setsb _C_FLAG;"\ + "xorl %%edx,%%edx;" + #define IMM5_ASR \ + "sarl %0,%%edx;"\ + "setcb _C_FLAG;" + #define IMM5_ASR_0 \ + "sarl $31,%%edx;"\ + "setsb _C_FLAG;" + #define THREEARG_INSN(OP,N) \ + asm("movl %%eax,%%edx;" \ + "shrl $1,%%edx;" \ + "andl $0x1C,%%edx;" \ + "andl $7,%%eax;" \ + "movl _reg(%%edx),%%ecx;" \ + OP(N) \ + "setsb _N_FLAG;" \ + "setzb _Z_FLAG;" \ + "movl %%ecx,_reg(,%%eax,4)"::) + #define ADD_RD_RS_RN(N) \ + "add (_reg+"#N"*4),%%ecx;" \ + "setcb _C_FLAG;" \ + "setob _V_FLAG;" + #define ADD_RD_RS_O3(N) \ + "add $"#N",%%ecx;" \ + "setcb _C_FLAG;" \ + "setob _V_FLAG;" + #define ADD_RD_RS_O3_0(N) \ + "movb $0,_C_FLAG;" \ + "add $0,%%ecx;" \ + "movb $0,_V_FLAG;" + #define SUB_RD_RS_RN(N) \ + "sub (_reg+"#N"*4),%%ecx;" \ + "setncb _C_FLAG;" \ + "setob _V_FLAG;" + #define SUB_RD_RS_O3(N) \ + "sub $"#N",%%ecx;" \ + "setncb _C_FLAG;" \ + "setob _V_FLAG;" + #define SUB_RD_RS_O3_0(N) \ + "movb $1,_C_FLAG;" \ + "sub $0,%%ecx;" \ + "movb $0,_V_FLAG;" +#endif +#else // !__GNUC__ + #define ADD_RD_RS_RN(N) \ + {\ + __asm mov eax, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm add ebx, dword ptr [OFFSET reg+4*N]\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define ADD_RD_RS_O3(N) \ + {\ + __asm mov eax, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm add ebx, N\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define ADD_RD_RS_O3_0 \ + {\ + __asm mov eax, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm add ebx, 0\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm mov byte ptr C_FLAG, 0\ + __asm mov byte ptr V_FLAG, 0\ + } + #define ADD_RN_O8(d) \ + {\ + __asm mov ebx, opcode\ + __asm and ebx, 255\ + __asm add dword ptr [OFFSET reg+4*(d)], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define CMN_RD_RS \ + {\ + __asm mov eax, dest\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm add ebx, value\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define ADC_RD_RS \ + {\ + __asm mov ebx, dest\ + __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ + __asm bt word ptr C_FLAG, 0\ + __asm adc ebx, value\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define SUB_RD_RS_RN(N) \ + {\ + __asm mov eax, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm sub ebx, dword ptr [OFFSET reg+4*N]\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define SUB_RD_RS_O3(N) \ + {\ + __asm mov eax, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm sub ebx, N\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define SUB_RD_RS_O3_0 \ + {\ + __asm mov eax, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm sub ebx, 0\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm mov byte ptr C_FLAG, 1\ + __asm mov byte ptr V_FLAG, 0\ + } + #define SUB_RN_O8(d) \ + {\ + __asm mov ebx, opcode\ + __asm and ebx, 255\ + __asm sub dword ptr [OFFSET reg + 4*(d)], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define MOV_RN_O8(d) \ + {\ + __asm mov eax, opcode\ + __asm and eax, 255\ + __asm mov dword ptr [OFFSET reg+4*(d)], eax\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + } + #define CMP_RN_O8(d) \ + {\ + __asm mov eax, dword ptr [OFFSET reg+4*(d)]\ + __asm mov ebx, opcode\ + __asm and ebx, 255\ + __asm sub eax, ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define SBC_RD_RS \ + {\ + __asm mov ebx, dest\ + __asm mov ebx, dword ptr [OFFSET reg + 4*ebx]\ + __asm mov eax, value\ + __asm bt word ptr C_FLAG, 0\ + __asm cmc\ + __asm sbb ebx, eax\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg + 4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define LSL_RD_RM_I5 \ + {\ + __asm mov eax, source\ + __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ + __asm mov cl, byte ptr shift\ + __asm shl eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define LSL_RD_RS \ + {\ + __asm mov eax, dest\ + __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ + __asm mov cl, byte ptr value\ + __asm shl eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define LSR_RD_RM_I5 \ + {\ + __asm mov eax, source\ + __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ + __asm mov cl, byte ptr shift\ + __asm shr eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define LSR_RD_RS \ + {\ + __asm mov eax, dest\ + __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ + __asm mov cl, byte ptr value\ + __asm shr eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define ASR_RD_RM_I5 \ + {\ + __asm mov eax, source\ + __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ + __asm mov cl, byte ptr shift\ + __asm sar eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define ASR_RD_RS \ + {\ + __asm mov eax, dest\ + __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ + __asm mov cl, byte ptr value\ + __asm sar eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define ROR_RD_RS \ + {\ + __asm mov eax, dest\ + __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ + __asm mov cl, byte ptr value\ + __asm ror eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define NEG_RD_RS \ + {\ + __asm mov ebx, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ + __asm neg ebx\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax],ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define CMP_RD_RS \ + {\ + __asm mov eax, dest\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm sub ebx, value\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } +#endif +#endif + +// C core +#ifndef ADDCARRY + #define ADDCARRY(a, b, c) \ + C_FLAG = ((NEG(a) & NEG(b)) |\ + (NEG(a) & POS(c)) |\ + (NEG(b) & POS(c))) ? true : false; +#endif +#ifndef ADDOVERFLOW + #define ADDOVERFLOW(a, b, c) \ + V_FLAG = ((NEG(a) & NEG(b) & POS(c)) |\ + (POS(a) & POS(b) & NEG(c))) ? true : false; +#endif +#ifndef SUBCARRY + #define SUBCARRY(a, b, c) \ + C_FLAG = ((NEG(a) & POS(b)) |\ + (NEG(a) & POS(c)) |\ + (POS(b) & POS(c))) ? true : false; +#endif +#ifndef SUBOVERFLOW + #define SUBOVERFLOW(a, b, c)\ + V_FLAG = ((NEG(a) & POS(b) & POS(c)) |\ + (POS(a) & NEG(b) & NEG(c))) ? true : false; +#endif +#ifndef ADD_RD_RS_RN + #define ADD_RD_RS_RN(N) \ + {\ + u32 lhs = reg[source].I;\ + u32 rhs = reg[N].I;\ + u32 res = lhs + rhs;\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + ADDCARRY(lhs, rhs, res);\ + ADDOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef ADD_RD_RS_O3 + #define ADD_RD_RS_O3(N) \ + {\ + u32 lhs = reg[source].I;\ + u32 rhs = N;\ + u32 res = lhs + rhs;\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + ADDCARRY(lhs, rhs, res);\ + ADDOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef ADD_RD_RS_O3_0 +# define ADD_RD_RS_O3_0 ADD_RD_RS_O3 +#endif +#ifndef ADD_RN_O8 + #define ADD_RN_O8(d) \ + {\ + u32 lhs = reg[(d)].I;\ + u32 rhs = (opcode & 255);\ + u32 res = lhs + rhs;\ + reg[(d)].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + ADDCARRY(lhs, rhs, res);\ + ADDOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef CMN_RD_RS + #define CMN_RD_RS \ + {\ + u32 lhs = reg[dest].I;\ + u32 rhs = value;\ + u32 res = lhs + rhs;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + ADDCARRY(lhs, rhs, res);\ + ADDOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef ADC_RD_RS + #define ADC_RD_RS \ + {\ + u32 lhs = reg[dest].I;\ + u32 rhs = value;\ + u32 res = lhs + rhs + (u32)C_FLAG;\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + ADDCARRY(lhs, rhs, res);\ + ADDOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef SUB_RD_RS_RN + #define SUB_RD_RS_RN(N) \ + {\ + u32 lhs = reg[source].I;\ + u32 rhs = reg[N].I;\ + u32 res = lhs - rhs;\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(lhs, rhs, res);\ + SUBOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef SUB_RD_RS_O3 + #define SUB_RD_RS_O3(N) \ + {\ + u32 lhs = reg[source].I;\ + u32 rhs = N;\ + u32 res = lhs - rhs;\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(lhs, rhs, res);\ + SUBOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef SUB_RD_RS_O3_0 +# define SUB_RD_RS_O3_0 SUB_RD_RS_O3 +#endif +#ifndef SUB_RN_O8 + #define SUB_RN_O8(d) \ + {\ + u32 lhs = reg[(d)].I;\ + u32 rhs = (opcode & 255);\ + u32 res = lhs - rhs;\ + reg[(d)].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(lhs, rhs, res);\ + SUBOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef MOV_RN_O8 + #define MOV_RN_O8(d) \ + {\ + reg[d].I = opcode & 255;\ + N_FLAG = false;\ + Z_FLAG = (reg[d].I ? false : true);\ + } +#endif +#ifndef CMP_RN_O8 + #define CMP_RN_O8(d) \ + {\ + u32 lhs = reg[(d)].I;\ + u32 rhs = (opcode & 255);\ + u32 res = lhs - rhs;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(lhs, rhs, res);\ + SUBOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef SBC_RD_RS + #define SBC_RD_RS \ + {\ + u32 lhs = reg[dest].I;\ + u32 rhs = value;\ + u32 res = lhs - rhs - !((u32)C_FLAG);\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(lhs, rhs, res);\ + SUBOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef LSL_RD_RM_I5 + #define LSL_RD_RM_I5 \ + {\ + C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false;\ + value = reg[source].I << shift;\ + } +#endif +#ifndef LSL_RD_RS + #define LSL_RD_RS \ + {\ + C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false;\ + value = reg[dest].I << value;\ + } +#endif +#ifndef LSR_RD_RM_I5 + #define LSR_RD_RM_I5 \ + {\ + C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false;\ + value = reg[source].I >> shift;\ + } +#endif +#ifndef LSR_RD_RS + #define LSR_RD_RS \ + {\ + C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\ + value = reg[dest].I >> value;\ + } +#endif +#ifndef ASR_RD_RM_I5 + #define ASR_RD_RM_I5 \ + {\ + C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false;\ + value = (s32)reg[source].I >> (int)shift;\ + } +#endif +#ifndef ASR_RD_RS + #define ASR_RD_RS \ + {\ + C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false;\ + value = (s32)reg[dest].I >> (int)value;\ + } +#endif +#ifndef ROR_RD_RS + #define ROR_RD_RS \ + {\ + C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\ + value = ((reg[dest].I << (32 - value)) |\ + (reg[dest].I >> value));\ + } +#endif +#ifndef NEG_RD_RS + #define NEG_RD_RS \ + {\ + u32 lhs = reg[source].I;\ + u32 rhs = 0;\ + u32 res = rhs - lhs;\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(rhs, lhs, res);\ + SUBOVERFLOW(rhs, lhs, res);\ + } +#endif +#ifndef CMP_RD_RS + #define CMP_RD_RS \ + {\ + u32 lhs = reg[dest].I;\ + u32 rhs = value;\ + u32 res = lhs - rhs;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(lhs, rhs, res);\ + SUBOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef IMM5_INSN + #define IMM5_INSN(OP,N) \ + int dest = opcode & 0x07;\ + int source = (opcode >> 3) & 0x07;\ + u32 value;\ + OP(N);\ + reg[dest].I = value;\ + N_FLAG = (value & 0x80000000 ? true : false);\ + Z_FLAG = (value ? false : true); + #define IMM5_INSN_0(OP) \ + int dest = opcode & 0x07;\ + int source = (opcode >> 3) & 0x07;\ + u32 value;\ + OP;\ + reg[dest].I = value;\ + N_FLAG = (value & 0x80000000 ? true : false);\ + Z_FLAG = (value ? false : true); + #define IMM5_LSL(N) \ + int shift = N;\ + LSL_RD_RM_I5; + #define IMM5_LSL_0 \ + value = reg[source].I; + #define IMM5_LSR(N) \ + int shift = N;\ + LSR_RD_RM_I5; + #define IMM5_LSR_0 \ + C_FLAG = reg[source].I & 0x80000000 ? true : false;\ + value = 0; + #define IMM5_ASR(N) \ + int shift = N;\ + ASR_RD_RM_I5; + #define IMM5_ASR_0 \ + if(reg[source].I & 0x80000000) {\ + value = 0xFFFFFFFF;\ + C_FLAG = true;\ + } else {\ + value = 0;\ + C_FLAG = false;\ + } +#endif +#ifndef THREEARG_INSN + #define THREEARG_INSN(OP,N) \ + int dest = opcode & 0x07; \ + int source = (opcode >> 3) & 0x07; \ + OP(N); +#endif + +// Shift instructions ///////////////////////////////////////////////////// + +#define DEFINE_IMM5_INSN(OP,BASE) \ + static INSN_REGPARM void thumb##BASE##_00(u32 opcode) { IMM5_INSN_0(OP##_0); } \ + static INSN_REGPARM void thumb##BASE##_01(u32 opcode) { IMM5_INSN(OP, 1); } \ + static INSN_REGPARM void thumb##BASE##_02(u32 opcode) { IMM5_INSN(OP, 2); } \ + static INSN_REGPARM void thumb##BASE##_03(u32 opcode) { IMM5_INSN(OP, 3); } \ + static INSN_REGPARM void thumb##BASE##_04(u32 opcode) { IMM5_INSN(OP, 4); } \ + static INSN_REGPARM void thumb##BASE##_05(u32 opcode) { IMM5_INSN(OP, 5); } \ + static INSN_REGPARM void thumb##BASE##_06(u32 opcode) { IMM5_INSN(OP, 6); } \ + static INSN_REGPARM void thumb##BASE##_07(u32 opcode) { IMM5_INSN(OP, 7); } \ + static INSN_REGPARM void thumb##BASE##_08(u32 opcode) { IMM5_INSN(OP, 8); } \ + static INSN_REGPARM void thumb##BASE##_09(u32 opcode) { IMM5_INSN(OP, 9); } \ + static INSN_REGPARM void thumb##BASE##_0A(u32 opcode) { IMM5_INSN(OP,10); } \ + static INSN_REGPARM void thumb##BASE##_0B(u32 opcode) { IMM5_INSN(OP,11); } \ + static INSN_REGPARM void thumb##BASE##_0C(u32 opcode) { IMM5_INSN(OP,12); } \ + static INSN_REGPARM void thumb##BASE##_0D(u32 opcode) { IMM5_INSN(OP,13); } \ + static INSN_REGPARM void thumb##BASE##_0E(u32 opcode) { IMM5_INSN(OP,14); } \ + static INSN_REGPARM void thumb##BASE##_0F(u32 opcode) { IMM5_INSN(OP,15); } \ + static INSN_REGPARM void thumb##BASE##_10(u32 opcode) { IMM5_INSN(OP,16); } \ + static INSN_REGPARM void thumb##BASE##_11(u32 opcode) { IMM5_INSN(OP,17); } \ + static INSN_REGPARM void thumb##BASE##_12(u32 opcode) { IMM5_INSN(OP,18); } \ + static INSN_REGPARM void thumb##BASE##_13(u32 opcode) { IMM5_INSN(OP,19); } \ + static INSN_REGPARM void thumb##BASE##_14(u32 opcode) { IMM5_INSN(OP,20); } \ + static INSN_REGPARM void thumb##BASE##_15(u32 opcode) { IMM5_INSN(OP,21); } \ + static INSN_REGPARM void thumb##BASE##_16(u32 opcode) { IMM5_INSN(OP,22); } \ + static INSN_REGPARM void thumb##BASE##_17(u32 opcode) { IMM5_INSN(OP,23); } \ + static INSN_REGPARM void thumb##BASE##_18(u32 opcode) { IMM5_INSN(OP,24); } \ + static INSN_REGPARM void thumb##BASE##_19(u32 opcode) { IMM5_INSN(OP,25); } \ + static INSN_REGPARM void thumb##BASE##_1A(u32 opcode) { IMM5_INSN(OP,26); } \ + static INSN_REGPARM void thumb##BASE##_1B(u32 opcode) { IMM5_INSN(OP,27); } \ + static INSN_REGPARM void thumb##BASE##_1C(u32 opcode) { IMM5_INSN(OP,28); } \ + static INSN_REGPARM void thumb##BASE##_1D(u32 opcode) { IMM5_INSN(OP,29); } \ + static INSN_REGPARM void thumb##BASE##_1E(u32 opcode) { IMM5_INSN(OP,30); } \ + static INSN_REGPARM void thumb##BASE##_1F(u32 opcode) { IMM5_INSN(OP,31); } + +// LSL Rd, Rm, #Imm 5 +DEFINE_IMM5_INSN(IMM5_LSL,00) +// LSR Rd, Rm, #Imm 5 +DEFINE_IMM5_INSN(IMM5_LSR,08) +// ASR Rd, Rm, #Imm 5 +DEFINE_IMM5_INSN(IMM5_ASR,10) + +// 3-argument ADD/SUB ///////////////////////////////////////////////////// + +#define DEFINE_REG3_INSN(OP,BASE) \ + static INSN_REGPARM void thumb##BASE##_0(u32 opcode) { THREEARG_INSN(OP,0); } \ + static INSN_REGPARM void thumb##BASE##_1(u32 opcode) { THREEARG_INSN(OP,1); } \ + static INSN_REGPARM void thumb##BASE##_2(u32 opcode) { THREEARG_INSN(OP,2); } \ + static INSN_REGPARM void thumb##BASE##_3(u32 opcode) { THREEARG_INSN(OP,3); } \ + static INSN_REGPARM void thumb##BASE##_4(u32 opcode) { THREEARG_INSN(OP,4); } \ + static INSN_REGPARM void thumb##BASE##_5(u32 opcode) { THREEARG_INSN(OP,5); } \ + static INSN_REGPARM void thumb##BASE##_6(u32 opcode) { THREEARG_INSN(OP,6); } \ + static INSN_REGPARM void thumb##BASE##_7(u32 opcode) { THREEARG_INSN(OP,7); } + +#define DEFINE_IMM3_INSN(OP,BASE) \ + static INSN_REGPARM void thumb##BASE##_0(u32 opcode) { THREEARG_INSN(OP##_0,0); } \ + static INSN_REGPARM void thumb##BASE##_1(u32 opcode) { THREEARG_INSN(OP,1); } \ + static INSN_REGPARM void thumb##BASE##_2(u32 opcode) { THREEARG_INSN(OP,2); } \ + static INSN_REGPARM void thumb##BASE##_3(u32 opcode) { THREEARG_INSN(OP,3); } \ + static INSN_REGPARM void thumb##BASE##_4(u32 opcode) { THREEARG_INSN(OP,4); } \ + static INSN_REGPARM void thumb##BASE##_5(u32 opcode) { THREEARG_INSN(OP,5); } \ + static INSN_REGPARM void thumb##BASE##_6(u32 opcode) { THREEARG_INSN(OP,6); } \ + static INSN_REGPARM void thumb##BASE##_7(u32 opcode) { THREEARG_INSN(OP,7); } + +// ADD Rd, Rs, Rn +DEFINE_REG3_INSN(ADD_RD_RS_RN,18) +// SUB Rd, Rs, Rn +DEFINE_REG3_INSN(SUB_RD_RS_RN,1A) +// ADD Rd, Rs, #Offset3 +DEFINE_IMM3_INSN(ADD_RD_RS_O3,1C) +// SUB Rd, Rs, #Offset3 +DEFINE_IMM3_INSN(SUB_RD_RS_O3,1E) + +// MOV/CMP/ADD/SUB immediate ////////////////////////////////////////////// + +// MOV R0, #Offset8 +static INSN_REGPARM void thumb20(u32 opcode) { MOV_RN_O8(0); } +// MOV R1, #Offset8 +static INSN_REGPARM void thumb21(u32 opcode) { MOV_RN_O8(1); } +// MOV R2, #Offset8 +static INSN_REGPARM void thumb22(u32 opcode) { MOV_RN_O8(2); } +// MOV R3, #Offset8 +static INSN_REGPARM void thumb23(u32 opcode) { MOV_RN_O8(3); } +// MOV R4, #Offset8 +static INSN_REGPARM void thumb24(u32 opcode) { MOV_RN_O8(4); } +// MOV R5, #Offset8 +static INSN_REGPARM void thumb25(u32 opcode) { MOV_RN_O8(5); } +// MOV R6, #Offset8 +static INSN_REGPARM void thumb26(u32 opcode) { MOV_RN_O8(6); } +// MOV R7, #Offset8 +static INSN_REGPARM void thumb27(u32 opcode) { MOV_RN_O8(7); } + +// CMP R0, #Offset8 +static INSN_REGPARM void thumb28(u32 opcode) { CMP_RN_O8(0); } +// CMP R1, #Offset8 +static INSN_REGPARM void thumb29(u32 opcode) { CMP_RN_O8(1); } +// CMP R2, #Offset8 +static INSN_REGPARM void thumb2A(u32 opcode) { CMP_RN_O8(2); } +// CMP R3, #Offset8 +static INSN_REGPARM void thumb2B(u32 opcode) { CMP_RN_O8(3); } +// CMP R4, #Offset8 +static INSN_REGPARM void thumb2C(u32 opcode) { CMP_RN_O8(4); } +// CMP R5, #Offset8 +static INSN_REGPARM void thumb2D(u32 opcode) { CMP_RN_O8(5); } +// CMP R6, #Offset8 +static INSN_REGPARM void thumb2E(u32 opcode) { CMP_RN_O8(6); } +// CMP R7, #Offset8 +static INSN_REGPARM void thumb2F(u32 opcode) { CMP_RN_O8(7); } + +// ADD R0,#Offset8 +static INSN_REGPARM void thumb30(u32 opcode) { ADD_RN_O8(0); } +// ADD R1,#Offset8 +static INSN_REGPARM void thumb31(u32 opcode) { ADD_RN_O8(1); } +// ADD R2,#Offset8 +static INSN_REGPARM void thumb32(u32 opcode) { ADD_RN_O8(2); } +// ADD R3,#Offset8 +static INSN_REGPARM void thumb33(u32 opcode) { ADD_RN_O8(3); } +// ADD R4,#Offset8 +static INSN_REGPARM void thumb34(u32 opcode) { ADD_RN_O8(4); } +// ADD R5,#Offset8 +static INSN_REGPARM void thumb35(u32 opcode) { ADD_RN_O8(5); } +// ADD R6,#Offset8 +static INSN_REGPARM void thumb36(u32 opcode) { ADD_RN_O8(6); } +// ADD R7,#Offset8 +static INSN_REGPARM void thumb37(u32 opcode) { ADD_RN_O8(7); } + +// SUB R0,#Offset8 +static INSN_REGPARM void thumb38(u32 opcode) { SUB_RN_O8(0); } +// SUB R1,#Offset8 +static INSN_REGPARM void thumb39(u32 opcode) { SUB_RN_O8(1); } +// SUB R2,#Offset8 +static INSN_REGPARM void thumb3A(u32 opcode) { SUB_RN_O8(2); } +// SUB R3,#Offset8 +static INSN_REGPARM void thumb3B(u32 opcode) { SUB_RN_O8(3); } +// SUB R4,#Offset8 +static INSN_REGPARM void thumb3C(u32 opcode) { SUB_RN_O8(4); } +// SUB R5,#Offset8 +static INSN_REGPARM void thumb3D(u32 opcode) { SUB_RN_O8(5); } +// SUB R6,#Offset8 +static INSN_REGPARM void thumb3E(u32 opcode) { SUB_RN_O8(6); } +// SUB R7,#Offset8 +static INSN_REGPARM void thumb3F(u32 opcode) { SUB_RN_O8(7); } + +// ALU operations ///////////////////////////////////////////////////////// + +// AND Rd, Rs +static INSN_REGPARM void thumb40_0(u32 opcode) +{ + int dest = opcode & 7; + reg[dest].I &= reg[(opcode >> 3)&7].I; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; + Z_FLAG = reg[dest].I ? false : true; + THUMB_CONSOLE_OUTPUT(NULL, reg[2].I); +} + +// EOR Rd, Rs +static INSN_REGPARM void thumb40_1(u32 opcode) +{ + int dest = opcode & 7; + reg[dest].I ^= reg[(opcode >> 3)&7].I; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; + Z_FLAG = reg[dest].I ? false : true; +} + +// LSL Rd, Rs +static INSN_REGPARM void thumb40_2(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[(opcode >> 3)&7].B.B0; + if(value) { + if(value == 32) { + value = 0; + C_FLAG = (reg[dest].I & 1 ? true : false); + } else if(value < 32) { + LSL_RD_RS; + } else { + value = 0; + C_FLAG = false; + } + reg[dest].I = value; + } + N_FLAG = reg[dest].I & 0x80000000 ? true : false; + Z_FLAG = reg[dest].I ? false : true; + clockTicks = codeTicksAccess16(armNextPC)+2; +} + +// LSR Rd, Rs +static INSN_REGPARM void thumb40_3(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[(opcode >> 3)&7].B.B0; + if(value) { + if(value == 32) { + value = 0; + C_FLAG = (reg[dest].I & 0x80000000 ? true : false); + } else if(value < 32) { + LSR_RD_RS; + } else { + value = 0; + C_FLAG = false; + } + reg[dest].I = value; + } + N_FLAG = reg[dest].I & 0x80000000 ? true : false; + Z_FLAG = reg[dest].I ? false : true; + clockTicks = codeTicksAccess16(armNextPC)+2; +} + +// ASR Rd, Rs +static INSN_REGPARM void thumb41_0(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[(opcode >> 3)&7].B.B0; + if(value) { + if(value < 32) { + ASR_RD_RS; + reg[dest].I = value; + } else { + if(reg[dest].I & 0x80000000){ + reg[dest].I = 0xFFFFFFFF; + C_FLAG = true; + } else { + reg[dest].I = 0x00000000; + C_FLAG = false; + } + } + } + N_FLAG = reg[dest].I & 0x80000000 ? true : false; + Z_FLAG = reg[dest].I ? false : true; + clockTicks = codeTicksAccess16(armNextPC)+2; +} + +// ADC Rd, Rs +static INSN_REGPARM void thumb41_1(u32 opcode) +{ + int dest = opcode & 0x07; + u32 value = reg[(opcode >> 3)&7].I; + ADC_RD_RS; +} + +// SBC Rd, Rs +static INSN_REGPARM void thumb41_2(u32 opcode) +{ + int dest = opcode & 0x07; + u32 value = reg[(opcode >> 3)&7].I; + SBC_RD_RS; +} + +// ROR Rd, Rs +static INSN_REGPARM void thumb41_3(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[(opcode >> 3)&7].B.B0; + + if(value) { + value = value & 0x1f; + if(value == 0) { + C_FLAG = (reg[dest].I & 0x80000000 ? true : false); + } else { + ROR_RD_RS; + reg[dest].I = value; + } + } + clockTicks = codeTicksAccess16(armNextPC)+2; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; + Z_FLAG = reg[dest].I ? false : true; +} + +// TST Rd, Rs +static INSN_REGPARM void thumb42_0(u32 opcode) +{ + u32 value = reg[opcode & 7].I & reg[(opcode >> 3) & 7].I; + N_FLAG = value & 0x80000000 ? true : false; + Z_FLAG = value ? false : true; +} + +// NEG Rd, Rs +static INSN_REGPARM void thumb42_1(u32 opcode) +{ + int dest = opcode & 7; + int source = (opcode >> 3) & 7; + NEG_RD_RS; +} + +// CMP Rd, Rs +static INSN_REGPARM void thumb42_2(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[(opcode >> 3)&7].I; + CMP_RD_RS; +} + +// CMN Rd, Rs +static INSN_REGPARM void thumb42_3(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[(opcode >> 3)&7].I; + CMN_RD_RS; +} + +// ORR Rd, Rs +static INSN_REGPARM void thumb43_0(u32 opcode) +{ + int dest = opcode & 7; + reg[dest].I |= reg[(opcode >> 3) & 7].I; + Z_FLAG = reg[dest].I ? false : true; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; +} + +// MUL Rd, Rs +static INSN_REGPARM void thumb43_1(u32 opcode) +{ + clockTicks = 1; + int dest = opcode & 7; + u32 rm = reg[dest].I; + reg[dest].I = reg[(opcode >> 3) & 7].I * rm; + if (((s32)rm) < 0) + rm = ~rm; + if ((rm & 0xFFFFFF00) == 0) + clockTicks += 0; + else if ((rm & 0xFFFF0000) == 0) + clockTicks += 1; + else if ((rm & 0xFF000000) == 0) + clockTicks += 2; + else + clockTicks += 3; + busPrefetchCount = (busPrefetchCount<>(8-clockTicks)); + clockTicks += codeTicksAccess16(armNextPC) + 1; + Z_FLAG = reg[dest].I ? false : true; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; +} + +// BIC Rd, Rs +static INSN_REGPARM void thumb43_2(u32 opcode) +{ + int dest = opcode & 7; + reg[dest].I &= (~reg[(opcode >> 3) & 7].I); + Z_FLAG = reg[dest].I ? false : true; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; +} + +// MVN Rd, Rs +static INSN_REGPARM void thumb43_3(u32 opcode) +{ + int dest = opcode & 7; + reg[dest].I = ~reg[(opcode >> 3) & 7].I; + Z_FLAG = reg[dest].I ? false : true; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; +} + +// High-register instructions and BX ////////////////////////////////////// + +// ADD Rd, Hs +static INSN_REGPARM void thumb44_1(u32 opcode) +{ + reg[opcode&7].I += reg[((opcode>>3)&7)+8].I; +} + +// ADD Hd, Rs +static INSN_REGPARM void thumb44_2(u32 opcode) +{ + reg[(opcode&7)+8].I += reg[(opcode>>3)&7].I; + if((opcode&7) == 7) { + reg[15].I &= 0xFFFFFFFE; + armNextPC = reg[15].I; + reg[15].I += 2; + THUMB_PREFETCH; + clockTicks = codeTicksAccessSeq16(armNextPC)*2 + + codeTicksAccess16(armNextPC) + 3; + } +} + +// ADD Hd, Hs +static INSN_REGPARM void thumb44_3(u32 opcode) +{ + reg[(opcode&7)+8].I += reg[((opcode>>3)&7)+8].I; + if((opcode&7) == 7) { + reg[15].I &= 0xFFFFFFFE; + armNextPC = reg[15].I; + reg[15].I += 2; + THUMB_PREFETCH; + clockTicks = codeTicksAccessSeq16(armNextPC)*2 + + codeTicksAccess16(armNextPC) + 3; + } +} + +// CMP Rd, Hs +static INSN_REGPARM void thumb45_1(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[((opcode>>3)&7)+8].I; + CMP_RD_RS; +} + +// CMP Hd, Rs +static INSN_REGPARM void thumb45_2(u32 opcode) +{ + int dest = (opcode & 7) + 8; + u32 value = reg[(opcode>>3)&7].I; + CMP_RD_RS; +} + +// CMP Hd, Hs +static INSN_REGPARM void thumb45_3(u32 opcode) +{ + int dest = (opcode & 7) + 8; + u32 value = reg[((opcode>>3)&7)+8].I; + CMP_RD_RS; +} + +// MOV Rd, Hs +static INSN_REGPARM void thumb46_1(u32 opcode) +{ + reg[opcode&7].I = reg[((opcode>>3)&7)+8].I; +} + +// MOV Hd, Rs +static INSN_REGPARM void thumb46_2(u32 opcode) +{ + reg[(opcode&7)+8].I = reg[(opcode>>3)&7].I; + if((opcode&7) == 7) { + UPDATE_OLDREG; + reg[15].I &= 0xFFFFFFFE; + armNextPC = reg[15].I; + reg[15].I += 2; + THUMB_PREFETCH; + clockTicks = codeTicksAccessSeq16(armNextPC)*2 + + codeTicksAccess16(armNextPC) + 3; + } +} + +// MOV Hd, Hs +static INSN_REGPARM void thumb46_3(u32 opcode) +{ + reg[(opcode&7)+8].I = reg[((opcode>>3)&7)+8].I; + if((opcode&7) == 7) { + UPDATE_OLDREG; + reg[15].I &= 0xFFFFFFFE; + armNextPC = reg[15].I; + reg[15].I += 2; + THUMB_PREFETCH; + clockTicks = codeTicksAccessSeq16(armNextPC)*2 + + codeTicksAccess16(armNextPC) + 3; + } +} + + +// BX Rs +static INSN_REGPARM void thumb47(u32 opcode) +{ + int base = (opcode >> 3) & 15; + busPrefetchCount=0; + UPDATE_OLDREG; + reg[15].I = reg[base].I; + if(reg[base].I & 1) { + armState = false; + reg[15].I &= 0xFFFFFFFE; + armNextPC = reg[15].I; + reg[15].I += 2; + THUMB_PREFETCH; + clockTicks = codeTicksAccessSeq16(armNextPC) + + codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 3; + } else { + armState = true; + reg[15].I &= 0xFFFFFFFC; + armNextPC = reg[15].I; + reg[15].I += 4; + ARM_PREFETCH; + clockTicks = codeTicksAccessSeq32(armNextPC) + + codeTicksAccessSeq32(armNextPC) + codeTicksAccess32(armNextPC) + 3; + } +} + +// Load/store instructions //////////////////////////////////////////////// + +// LDR R0~R7,[PC, #Imm] +static INSN_REGPARM void thumb48(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); + reg[regist].I = CPUReadMemoryQuick(address); + busPrefetchCount=0; + clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); +} + +// STR Rd, [Rs, Rn] +static INSN_REGPARM void thumb50(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + CPUWriteMemory(address, reg[opcode & 7].I); + clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2; +} + +// STRH Rd, [Rs, Rn] +static INSN_REGPARM void thumb52(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + CPUWriteHalfWord(address, reg[opcode&7].W.W0); + clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2; +} + +// STRB Rd, [Rs, Rn] +static INSN_REGPARM void thumb54(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode >>6)&7].I; + CPUWriteByte(address, reg[opcode & 7].B.B0); + clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2; +} + +// LDSB Rd, [Rs, Rn] +static INSN_REGPARM void thumb56(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + reg[opcode&7].I = (s8)CPUReadByte(address); + clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); +} + +// LDR Rd, [Rs, Rn] +static INSN_REGPARM void thumb58(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + reg[opcode&7].I = CPUReadMemory(address); + clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); +} + +// LDRH Rd, [Rs, Rn] +static INSN_REGPARM void thumb5A(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + reg[opcode&7].I = CPUReadHalfWord(address); + clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); +} + +// LDRB Rd, [Rs, Rn] +static INSN_REGPARM void thumb5C(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + reg[opcode&7].I = CPUReadByte(address); + clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); +} + +// LDSH Rd, [Rs, Rn] +static INSN_REGPARM void thumb5E(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + reg[opcode&7].I = (s16)CPUReadHalfWordSigned(address); + clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); +} + +// STR Rd, [Rs, #Imm] +static INSN_REGPARM void thumb60(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2); + CPUWriteMemory(address, reg[opcode&7].I); + clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2; +} + +// LDR Rd, [Rs, #Imm] +static INSN_REGPARM void thumb68(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2); + reg[opcode&7].I = CPUReadMemory(address); + clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); +} + +// STRB Rd, [Rs, #Imm] +static INSN_REGPARM void thumb70(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)); + CPUWriteByte(address, reg[opcode&7].B.B0); + clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2; +} + +// LDRB Rd, [Rs, #Imm] +static INSN_REGPARM void thumb78(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)); + reg[opcode&7].I = CPUReadByte(address); + clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); +} + +// STRH Rd, [Rs, #Imm] +static INSN_REGPARM void thumb80(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1); + CPUWriteHalfWord(address, reg[opcode&7].W.W0); + clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2; +} + +// LDRH Rd, [Rs, #Imm] +static INSN_REGPARM void thumb88(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1); + reg[opcode&7].I = CPUReadHalfWord(address); + clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); +} + +// STR R0~R7, [SP, #Imm] +static INSN_REGPARM void thumb90(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[13].I + ((opcode&255)<<2); + CPUWriteMemory(address, reg[regist].I); + clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2; +} + +// LDR R0~R7, [SP, #Imm] +static INSN_REGPARM void thumb98(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[13].I + ((opcode&255)<<2); + reg[regist].I = CPUReadMemoryQuick(address); + clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); +} + +// PC/stack-related /////////////////////////////////////////////////////// + +// ADD R0~R7, PC, Imm +static INSN_REGPARM void thumbA0(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + reg[regist].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); +} + +// ADD R0~R7, SP, Imm +static INSN_REGPARM void thumbA8(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + reg[regist].I = reg[13].I + ((opcode&255)<<2); +} + +// ADD SP, Imm +static INSN_REGPARM void thumbB0(u32 opcode) +{ + int offset = (opcode & 127) << 2; + if(opcode & 0x80) + offset = -offset; + reg[13].I += offset; +} + +// Push and pop /////////////////////////////////////////////////////////// + +#define PUSH_REG(val, r) \ + if (opcode & (val)) { \ + CPUWriteMemory(address, reg[(r)].I); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address); \ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address); \ + } \ + count++; \ + address += 4; \ + } + +#define POP_REG(val, r) \ + if (opcode & (val)) { \ + reg[(r)].I = CPUReadMemory(address); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address); \ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address); \ + } \ + count++; \ + address += 4; \ + } + +// PUSH {Rlist} +static INSN_REGPARM void thumbB4(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int count = 0; + u32 temp = reg[13].I - 4 * cpuBitsSet[opcode & 0xff]; + u32 address = temp & 0xFFFFFFFC; + PUSH_REG(1, 0); + PUSH_REG(2, 1); + PUSH_REG(4, 2); + PUSH_REG(8, 3); + PUSH_REG(16, 4); + PUSH_REG(32, 5); + PUSH_REG(64, 6); + PUSH_REG(128, 7); + clockTicks += 1 + codeTicksAccess16(armNextPC); + reg[13].I = temp; +} + +// PUSH {Rlist, LR} +static INSN_REGPARM void thumbB5(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int count = 0; + u32 temp = reg[13].I - 4 - 4 * cpuBitsSet[opcode & 0xff]; + u32 address = temp & 0xFFFFFFFC; + PUSH_REG(1, 0); + PUSH_REG(2, 1); + PUSH_REG(4, 2); + PUSH_REG(8, 3); + PUSH_REG(16, 4); + PUSH_REG(32, 5); + PUSH_REG(64, 6); + PUSH_REG(128, 7); + PUSH_REG(256, 14); + clockTicks += 1 + codeTicksAccess16(armNextPC); + reg[13].I = temp; +} + +// POP {Rlist} +static INSN_REGPARM void thumbBC(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int count = 0; + u32 address = reg[13].I & 0xFFFFFFFC; + u32 temp = reg[13].I + 4*cpuBitsSet[opcode & 0xFF]; + POP_REG(1, 0); + POP_REG(2, 1); + POP_REG(4, 2); + POP_REG(8, 3); + POP_REG(16, 4); + POP_REG(32, 5); + POP_REG(64, 6); + POP_REG(128, 7); + reg[13].I = temp; + clockTicks = 2 + codeTicksAccess16(armNextPC); +} + +// POP {Rlist, PC} +static INSN_REGPARM void thumbBD(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int count = 0; + u32 address = reg[13].I & 0xFFFFFFFC; + u32 temp = reg[13].I + 4 + 4*cpuBitsSet[opcode & 0xFF]; + POP_REG(1, 0); + POP_REG(2, 1); + POP_REG(4, 2); + POP_REG(8, 3); + POP_REG(16, 4); + POP_REG(32, 5); + POP_REG(64, 6); + POP_REG(128, 7); + reg[15].I = (CPUReadMemory(address) & 0xFFFFFFFE); + if (!count) { + clockTicks += 1 + dataTicksAccess32(address); + } else { + clockTicks += 1 + dataTicksAccessSeq32(address); + } + count++; + armNextPC = reg[15].I; + reg[15].I += 2; + reg[13].I = temp; + THUMB_PREFETCH; + busPrefetchCount = 0; + clockTicks += 3 + codeTicksAccess16(armNextPC) + codeTicksAccess16(armNextPC); +} + +// Load/store multiple //////////////////////////////////////////////////// + +#define THUMB_STM_REG(val,r,b) \ + if(opcode & (val)) { \ + CPUWriteMemory(address, reg[(r)].I); \ + reg[(b)].I = temp; \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address); \ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address); \ + } \ + count++; \ + address += 4; \ + } + +#define THUMB_LDM_REG(val,r) \ + if(opcode & (val)) { \ + reg[(r)].I = CPUReadMemory(address); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address); \ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address); \ + } \ + count++; \ + address += 4; \ + } + +// STM R0~7!, {Rlist} +static INSN_REGPARM void thumbC0(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[regist].I & 0xFFFFFFFC; + u32 temp = reg[regist].I + 4*cpuBitsSet[opcode & 0xff]; + int count = 0; + // store + THUMB_STM_REG(1, 0, regist); + THUMB_STM_REG(2, 1, regist); + THUMB_STM_REG(4, 2, regist); + THUMB_STM_REG(8, 3, regist); + THUMB_STM_REG(16, 4, regist); + THUMB_STM_REG(32, 5, regist); + THUMB_STM_REG(64, 6, regist); + THUMB_STM_REG(128, 7, regist); + clockTicks = 1 + codeTicksAccess16(armNextPC); +} + +// LDM R0~R7!, {Rlist} +static INSN_REGPARM void thumbC8(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[regist].I & 0xFFFFFFFC; + u32 temp = reg[regist].I + 4*cpuBitsSet[opcode & 0xFF]; + int count = 0; + // load + THUMB_LDM_REG(1, 0); + THUMB_LDM_REG(2, 1); + THUMB_LDM_REG(4, 2); + THUMB_LDM_REG(8, 3); + THUMB_LDM_REG(16, 4); + THUMB_LDM_REG(32, 5); + THUMB_LDM_REG(64, 6); + THUMB_LDM_REG(128, 7); + clockTicks = 2 + codeTicksAccess16(armNextPC); + if(!(opcode & (1<>6])(opcode); + + if (clockTicks < 0) + return 0; + if (clockTicks==0) + clockTicks = codeTicksAccessSeq16(oldArmNextPC) + 1; + cpuTotalTicks += clockTicks; + + } while (cpuTotalTicks < cpuNextEvent && !armState && !holdState && !SWITicks); + return 1; +} diff --git a/src/agb/GBA.cpp b/src/agb/GBA.cpp index 44d4877f..8ea7a614 100644 --- a/src/agb/GBA.cpp +++ b/src/agb/GBA.cpp @@ -1,3983 +1,3983 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005-2006 Forgotten and the VBA development team -// Copyright (C) VBA-M development team -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include -#include -#include -#include -#include -#include "GBA.h" -#include "GBAcpu.h" -#include "GBAinline.h" -#include "../Globals.h" -#include "GBAGfx.h" -#include "../EEprom.h" -#include "../Flash.h" -#include "../Sound.h" -#include "../Sram.h" -#include "../bios.h" -#include "../Cheats.h" -#include "../NLS.h" -#include "../elf.h" -#include "../Util.h" -#include "../Port.h" -#include "../System.h" -#include "agbprint.h" -#ifdef PROFILING -#include "prof/prof.h" -#endif - -#ifdef __GNUC__ -#define _stricmp strcasecmp -#endif - - -extern int emulating; -#ifdef LINK_EMULATION -extern int linktime; -extern void StartLink(u16); -extern void StartJOYLink(u16); -extern void StartGPLink(u16); -extern void LinkSSend(u16); -extern void LinkUpdate(int); -extern int linktime2; -#endif -int SWITicks = 0; -int IRQTicks = 0; - -u32 mastercode = 0; -int layerEnableDelay = 0; -bool busPrefetch = false; -bool busPrefetchEnable = false; -u32 busPrefetchCount = 0; -int cpuDmaTicksToUpdate = 0; -int cpuDmaCount = 0; -bool cpuDmaHack = false; -u32 cpuDmaLast = 0; -int dummyAddress = 0; - -bool cpuBreakLoop = false; -int cpuNextEvent = 0; - -int gbaSaveType = 0; // used to remember the save type on reset -bool intState = false; -bool stopState = false; -bool holdState = false; -int holdType = 0; -bool cpuSramEnabled = true; -bool cpuFlashEnabled = true; -bool cpuEEPROMEnabled = true; -bool cpuEEPROMSensorEnabled = false; - -u32 cpuPrefetch[2]; - -int cpuTotalTicks = 0; -#ifdef PROFILING -int profilingTicks = 0; -int profilingTicksReload = 0; -static profile_segment *profilSegment = NULL; -#endif - -#ifdef BKPT_SUPPORT -u8 freezeWorkRAM[0x40000]; -u8 freezeInternalRAM[0x8000]; -u8 freezeVRAM[0x18000]; -u8 freezePRAM[0x400]; -u8 freezeOAM[0x400]; -bool debugger_last; -#endif - -int lcdTicks = (useBios && !skipBios) ? 1008 : 208; -u8 timerOnOffDelay = 0; -u16 timer0Value = 0; -bool timer0On = false; -int timer0Ticks = 0; -int timer0Reload = 0; -int timer0ClockReload = 0; -u16 timer1Value = 0; -bool timer1On = false; -int timer1Ticks = 0; -int timer1Reload = 0; -int timer1ClockReload = 0; -u16 timer2Value = 0; -bool timer2On = false; -int timer2Ticks = 0; -int timer2Reload = 0; -int timer2ClockReload = 0; -u16 timer3Value = 0; -bool timer3On = false; -int timer3Ticks = 0; -int timer3Reload = 0; -int timer3ClockReload = 0; -u32 dma0Source = 0; -u32 dma0Dest = 0; -u32 dma1Source = 0; -u32 dma1Dest = 0; -u32 dma2Source = 0; -u32 dma2Dest = 0; -u32 dma3Source = 0; -u32 dma3Dest = 0; -void (*cpuSaveGameFunc)(u32,u8) = flashSaveDecide; -void (*renderLine)() = mode0RenderLine; -bool fxOn = false; -bool windowOn = false; -int frameCount = 0; -char buffer[1024]; -FILE *out = NULL; -u32 lastTime = 0; -int count = 0; - -int capture = 0; -int capturePrevious = 0; -int captureNumber = 0; - -const int TIMER_TICKS[4] = { - 0, - 6, - 8, - 10 -}; - -const u32 objTilesAddress [3] = {0x010000, 0x014000, 0x014000}; -const u8 gamepakRamWaitState[4] = { 4, 3, 2, 8 }; -const u8 gamepakWaitState[4] = { 4, 3, 2, 8 }; -const u8 gamepakWaitState0[2] = { 2, 1 }; -const u8 gamepakWaitState1[2] = { 4, 1 }; -const u8 gamepakWaitState2[2] = { 8, 1 }; -const bool isInRom [16]= - { false, false, false, false, false, false, false, false, - true, true, true, true, true, true, false, false }; - -u8 memoryWait[16] = - { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 }; -u8 memoryWait32[16] = - { 0, 0, 5, 0, 0, 1, 1, 0, 7, 7, 9, 9, 13, 13, 4, 0 }; -u8 memoryWaitSeq[16] = - { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 }; -u8 memoryWaitSeq32[16] = - { 0, 0, 5, 0, 0, 1, 1, 0, 5, 5, 9, 9, 17, 17, 4, 0 }; - -// The videoMemoryWait constants are used to add some waitstates -// if the opcode access video memory data outside of vblank/hblank -// It seems to happen on only one ticks for each pixel. -// Not used for now (too problematic with current code). -//const u8 videoMemoryWait[16] = -// {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - - -u8 biosProtected[4]; - -#ifdef WORDS_BIGENDIAN -bool cpuBiosSwapped = false; -#endif - -u32 myROM[] = { -0xEA000006, -0xEA000093, -0xEA000006, -0x00000000, -0x00000000, -0x00000000, -0xEA000088, -0x00000000, -0xE3A00302, -0xE1A0F000, -0xE92D5800, -0xE55EC002, -0xE28FB03C, -0xE79BC10C, -0xE14FB000, -0xE92D0800, -0xE20BB080, -0xE38BB01F, -0xE129F00B, -0xE92D4004, -0xE1A0E00F, -0xE12FFF1C, -0xE8BD4004, -0xE3A0C0D3, -0xE129F00C, -0xE8BD0800, -0xE169F00B, -0xE8BD5800, -0xE1B0F00E, -0x0000009C, -0x0000009C, -0x0000009C, -0x0000009C, -0x000001F8, -0x000001F0, -0x000000AC, -0x000000A0, -0x000000FC, -0x00000168, -0xE12FFF1E, -0xE1A03000, -0xE1A00001, -0xE1A01003, -0xE2113102, -0x42611000, -0xE033C040, -0x22600000, -0xE1B02001, -0xE15200A0, -0x91A02082, -0x3AFFFFFC, -0xE1500002, -0xE0A33003, -0x20400002, -0xE1320001, -0x11A020A2, -0x1AFFFFF9, -0xE1A01000, -0xE1A00003, -0xE1B0C08C, -0x22600000, -0x42611000, -0xE12FFF1E, -0xE92D0010, -0xE1A0C000, -0xE3A01001, -0xE1500001, -0x81A000A0, -0x81A01081, -0x8AFFFFFB, -0xE1A0000C, -0xE1A04001, -0xE3A03000, -0xE1A02001, -0xE15200A0, -0x91A02082, -0x3AFFFFFC, -0xE1500002, -0xE0A33003, -0x20400002, -0xE1320001, -0x11A020A2, -0x1AFFFFF9, -0xE0811003, -0xE1B010A1, -0xE1510004, -0x3AFFFFEE, -0xE1A00004, -0xE8BD0010, -0xE12FFF1E, -0xE0010090, -0xE1A01741, -0xE2611000, -0xE3A030A9, -0xE0030391, -0xE1A03743, -0xE2833E39, -0xE0030391, -0xE1A03743, -0xE2833C09, -0xE283301C, -0xE0030391, -0xE1A03743, -0xE2833C0F, -0xE28330B6, -0xE0030391, -0xE1A03743, -0xE2833C16, -0xE28330AA, -0xE0030391, -0xE1A03743, -0xE2833A02, -0xE2833081, -0xE0030391, -0xE1A03743, -0xE2833C36, -0xE2833051, -0xE0030391, -0xE1A03743, -0xE2833CA2, -0xE28330F9, -0xE0000093, -0xE1A00840, -0xE12FFF1E, -0xE3A00001, -0xE3A01001, -0xE92D4010, -0xE3A03000, -0xE3A04001, -0xE3500000, -0x1B000004, -0xE5CC3301, -0xEB000002, -0x0AFFFFFC, -0xE8BD4010, -0xE12FFF1E, -0xE3A0C301, -0xE5CC3208, -0xE15C20B8, -0xE0110002, -0x10222000, -0x114C20B8, -0xE5CC4208, -0xE12FFF1E, -0xE92D500F, -0xE3A00301, -0xE1A0E00F, -0xE510F004, -0xE8BD500F, -0xE25EF004, -0xE59FD044, -0xE92D5000, -0xE14FC000, -0xE10FE000, -0xE92D5000, -0xE3A0C302, -0xE5DCE09C, -0xE35E00A5, -0x1A000004, -0x05DCE0B4, -0x021EE080, -0xE28FE004, -0x159FF018, -0x059FF018, -0xE59FD018, -0xE8BD5000, -0xE169F00C, -0xE8BD5000, -0xE25EF004, -0x03007FF0, -0x09FE2000, -0x09FFC000, -0x03007FE0 -}; - -variable_desc saveGameStruct[] = { - { &DISPCNT , sizeof(u16) }, - { &DISPSTAT , sizeof(u16) }, - { &VCOUNT , sizeof(u16) }, - { &BG0CNT , sizeof(u16) }, - { &BG1CNT , sizeof(u16) }, - { &BG2CNT , sizeof(u16) }, - { &BG3CNT , sizeof(u16) }, - { &BG0HOFS , sizeof(u16) }, - { &BG0VOFS , sizeof(u16) }, - { &BG1HOFS , sizeof(u16) }, - { &BG1VOFS , sizeof(u16) }, - { &BG2HOFS , sizeof(u16) }, - { &BG2VOFS , sizeof(u16) }, - { &BG3HOFS , sizeof(u16) }, - { &BG3VOFS , sizeof(u16) }, - { &BG2PA , sizeof(u16) }, - { &BG2PB , sizeof(u16) }, - { &BG2PC , sizeof(u16) }, - { &BG2PD , sizeof(u16) }, - { &BG2X_L , sizeof(u16) }, - { &BG2X_H , sizeof(u16) }, - { &BG2Y_L , sizeof(u16) }, - { &BG2Y_H , sizeof(u16) }, - { &BG3PA , sizeof(u16) }, - { &BG3PB , sizeof(u16) }, - { &BG3PC , sizeof(u16) }, - { &BG3PD , sizeof(u16) }, - { &BG3X_L , sizeof(u16) }, - { &BG3X_H , sizeof(u16) }, - { &BG3Y_L , sizeof(u16) }, - { &BG3Y_H , sizeof(u16) }, - { &WIN0H , sizeof(u16) }, - { &WIN1H , sizeof(u16) }, - { &WIN0V , sizeof(u16) }, - { &WIN1V , sizeof(u16) }, - { &WININ , sizeof(u16) }, - { &WINOUT , sizeof(u16) }, - { &MOSAIC , sizeof(u16) }, - { &BLDMOD , sizeof(u16) }, - { &COLEV , sizeof(u16) }, - { &COLY , sizeof(u16) }, - { &DM0SAD_L , sizeof(u16) }, - { &DM0SAD_H , sizeof(u16) }, - { &DM0DAD_L , sizeof(u16) }, - { &DM0DAD_H , sizeof(u16) }, - { &DM0CNT_L , sizeof(u16) }, - { &DM0CNT_H , sizeof(u16) }, - { &DM1SAD_L , sizeof(u16) }, - { &DM1SAD_H , sizeof(u16) }, - { &DM1DAD_L , sizeof(u16) }, - { &DM1DAD_H , sizeof(u16) }, - { &DM1CNT_L , sizeof(u16) }, - { &DM1CNT_H , sizeof(u16) }, - { &DM2SAD_L , sizeof(u16) }, - { &DM2SAD_H , sizeof(u16) }, - { &DM2DAD_L , sizeof(u16) }, - { &DM2DAD_H , sizeof(u16) }, - { &DM2CNT_L , sizeof(u16) }, - { &DM2CNT_H , sizeof(u16) }, - { &DM3SAD_L , sizeof(u16) }, - { &DM3SAD_H , sizeof(u16) }, - { &DM3DAD_L , sizeof(u16) }, - { &DM3DAD_H , sizeof(u16) }, - { &DM3CNT_L , sizeof(u16) }, - { &DM3CNT_H , sizeof(u16) }, - { &TM0D , sizeof(u16) }, - { &TM0CNT , sizeof(u16) }, - { &TM1D , sizeof(u16) }, - { &TM1CNT , sizeof(u16) }, - { &TM2D , sizeof(u16) }, - { &TM2CNT , sizeof(u16) }, - { &TM3D , sizeof(u16) }, - { &TM3CNT , sizeof(u16) }, - { &P1 , sizeof(u16) }, - { &IE , sizeof(u16) }, - { &IF , sizeof(u16) }, - { &IME , sizeof(u16) }, - { &holdState, sizeof(bool) }, - { &holdType, sizeof(int) }, - { &lcdTicks, sizeof(int) }, - { &timer0On , sizeof(bool) }, - { &timer0Ticks , sizeof(int) }, - { &timer0Reload , sizeof(int) }, - { &timer0ClockReload , sizeof(int) }, - { &timer1On , sizeof(bool) }, - { &timer1Ticks , sizeof(int) }, - { &timer1Reload , sizeof(int) }, - { &timer1ClockReload , sizeof(int) }, - { &timer2On , sizeof(bool) }, - { &timer2Ticks , sizeof(int) }, - { &timer2Reload , sizeof(int) }, - { &timer2ClockReload , sizeof(int) }, - { &timer3On , sizeof(bool) }, - { &timer3Ticks , sizeof(int) }, - { &timer3Reload , sizeof(int) }, - { &timer3ClockReload , sizeof(int) }, - { &dma0Source , sizeof(u32) }, - { &dma0Dest , sizeof(u32) }, - { &dma1Source , sizeof(u32) }, - { &dma1Dest , sizeof(u32) }, - { &dma2Source , sizeof(u32) }, - { &dma2Dest , sizeof(u32) }, - { &dma3Source , sizeof(u32) }, - { &dma3Dest , sizeof(u32) }, - { &fxOn, sizeof(bool) }, - { &windowOn, sizeof(bool) }, - { &N_FLAG , sizeof(bool) }, - { &C_FLAG , sizeof(bool) }, - { &Z_FLAG , sizeof(bool) }, - { &V_FLAG , sizeof(bool) }, - { &armState , sizeof(bool) }, - { &armIrqEnable , sizeof(bool) }, - { &armNextPC , sizeof(u32) }, - { &armMode , sizeof(int) }, - { &saveType , sizeof(int) }, - { NULL, 0 } -}; - -static int romSize = 0x2000000; - -#ifdef PROFILING -void cpuProfil(profile_segment *seg) -{ - profilSegment = seg; -} - -void cpuEnableProfiling(int hz) -{ - if(hz == 0) - hz = 100; - profilingTicks = profilingTicksReload = 16777216 / hz; - profSetHertz(hz); -} -#endif - - -inline int CPUUpdateTicks() -{ - int cpuLoopTicks = lcdTicks; - - if(soundTicks < cpuLoopTicks) - cpuLoopTicks = soundTicks; - - if(timer0On && (timer0Ticks < cpuLoopTicks)) { - cpuLoopTicks = timer0Ticks; - } - if(timer1On && !(TM1CNT & 4) && (timer1Ticks < cpuLoopTicks)) { - cpuLoopTicks = timer1Ticks; - } - if(timer2On && !(TM2CNT & 4) && (timer2Ticks < cpuLoopTicks)) { - cpuLoopTicks = timer2Ticks; - } - if(timer3On && !(TM3CNT & 4) && (timer3Ticks < cpuLoopTicks)) { - cpuLoopTicks = timer3Ticks; - } -#ifdef PROFILING - if(profilingTicksReload != 0) { - if(profilingTicks < cpuLoopTicks) { - cpuLoopTicks = profilingTicks; - } - } -#endif - - if (SWITicks) { - if (SWITicks < cpuLoopTicks) - cpuLoopTicks = SWITicks; - } - - if (IRQTicks) { - if (IRQTicks < cpuLoopTicks) - cpuLoopTicks = IRQTicks; - } - - return cpuLoopTicks; -} - -void CPUUpdateWindow0() -{ - int x00 = WIN0H>>8; - int x01 = WIN0H & 255; - - if(x00 <= x01) { - for(int i = 0; i < 240; i++) { - gfxInWin0[i] = (i >= x00 && i < x01); - } - } else { - for(int i = 0; i < 240; i++) { - gfxInWin0[i] = (i >= x00 || i < x01); - } - } -} - -void CPUUpdateWindow1() -{ - int x00 = WIN1H>>8; - int x01 = WIN1H & 255; - - if(x00 <= x01) { - for(int i = 0; i < 240; i++) { - gfxInWin1[i] = (i >= x00 && i < x01); - } - } else { - for(int i = 0; i < 240; i++) { - gfxInWin1[i] = (i >= x00 || i < x01); - } - } -} - -extern u32 line0[240]; -extern u32 line1[240]; -extern u32 line2[240]; -extern u32 line3[240]; - -#define CLEAR_ARRAY(a) \ - {\ - u32 *array = (a);\ - for(int i = 0; i < 240; i++) {\ - *array++ = 0x80000000;\ - }\ - }\ - -void CPUUpdateRenderBuffers(bool force) -{ - if(!(layerEnable & 0x0100) || force) { - CLEAR_ARRAY(line0); - } - if(!(layerEnable & 0x0200) || force) { - CLEAR_ARRAY(line1); - } - if(!(layerEnable & 0x0400) || force) { - CLEAR_ARRAY(line2); - } - if(!(layerEnable & 0x0800) || force) { - CLEAR_ARRAY(line3); - } -} - -static bool CPUWriteState(gzFile gzFile) -{ - utilWriteInt(gzFile, SAVE_GAME_VERSION); - - utilGzWrite(gzFile, &rom[0xa0], 16); - - utilWriteInt(gzFile, useBios); - - utilGzWrite(gzFile, ®[0], sizeof(reg)); - - utilWriteData(gzFile, saveGameStruct); - - // new to version 0.7.1 - utilWriteInt(gzFile, stopState); - // new to version 0.8 - utilWriteInt(gzFile, IRQTicks); - - utilGzWrite(gzFile, internalRAM, 0x8000); - utilGzWrite(gzFile, paletteRAM, 0x400); - utilGzWrite(gzFile, workRAM, 0x40000); - utilGzWrite(gzFile, vram, 0x20000); - utilGzWrite(gzFile, oam, 0x400); - utilGzWrite(gzFile, pix, 4*241*162); - utilGzWrite(gzFile, ioMem, 0x400); - - eepromSaveGame(gzFile); - flashSaveGame(gzFile); - soundSaveGame(gzFile); - - cheatsSaveGame(gzFile); - - // version 1.5 - rtcSaveGame(gzFile); - - return true; -} - -bool CPUWriteState(const char *file) -{ - gzFile gzFile = utilGzOpen(file, "wb"); - - if(gzFile == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), file); - return false; - } - - bool res = CPUWriteState(gzFile); - - utilGzClose(gzFile); - - return res; -} - -bool CPUWriteMemState(char *memory, int available) -{ - gzFile gzFile = utilMemGzOpen(memory, available, "w"); - - if(gzFile == NULL) { - return false; - } - - bool res = CPUWriteState(gzFile); - - long pos = utilGzMemTell(gzFile)+8; - - if(pos >= (available)) - res = false; - - utilGzClose(gzFile); - - return res; -} - -static bool CPUReadState(gzFile gzFile) -{ - int version = utilReadInt(gzFile); - - if(version > SAVE_GAME_VERSION || version < SAVE_GAME_VERSION_1) { - systemMessage(MSG_UNSUPPORTED_VBA_SGM, - N_("Unsupported VisualBoyAdvance save game version %d"), - version); - return false; - } - - u8 romname[17]; - - utilGzRead(gzFile, romname, 16); - - if(memcmp(&rom[0xa0], romname, 16) != 0) { - romname[16]=0; - for(int i = 0; i < 16; i++) - if(romname[i] < 32) - romname[i] = 32; - systemMessage(MSG_CANNOT_LOAD_SGM, N_("Cannot load save game for %s"), romname); - return false; - } - - bool ub = utilReadInt(gzFile) ? true : false; - - if(ub != useBios) { - if(useBios) - systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS, - N_("Save game is not using the BIOS files")); - else - systemMessage(MSG_SAVE_GAME_USING_BIOS, - N_("Save game is using the BIOS file")); - return false; - } - - utilGzRead(gzFile, ®[0], sizeof(reg)); - - utilReadData(gzFile, saveGameStruct); - - if(version < SAVE_GAME_VERSION_3) - stopState = false; - else - stopState = utilReadInt(gzFile) ? true : false; - - if(version < SAVE_GAME_VERSION_4) - { - IRQTicks = 0; - intState = false; - } - else - { - IRQTicks = utilReadInt(gzFile); - if (IRQTicks>0) - intState = true; - else - { - intState = false; - IRQTicks = 0; - } - } - - utilGzRead(gzFile, internalRAM, 0x8000); - utilGzRead(gzFile, paletteRAM, 0x400); - utilGzRead(gzFile, workRAM, 0x40000); - utilGzRead(gzFile, vram, 0x20000); - utilGzRead(gzFile, oam, 0x400); - if(version < SAVE_GAME_VERSION_6) - utilGzRead(gzFile, pix, 4*240*160); - else - utilGzRead(gzFile, pix, 4*241*162); - utilGzRead(gzFile, ioMem, 0x400); - - eepromReadGame(gzFile, version); - flashReadGame(gzFile, version); - soundReadGame(gzFile, version); - - if(version > SAVE_GAME_VERSION_1) { - cheatsReadGame(gzFile, version); - } - if(version > SAVE_GAME_VERSION_6) { - rtcReadGame(gzFile); - } - - if(version <= SAVE_GAME_VERSION_7) { - u32 temp; -#define SWAP(a,b,c) \ - temp = (a);\ - (a) = (b)<<16|(c);\ - (b) = (temp) >> 16;\ - (c) = (temp) & 0xFFFF; - - SWAP(dma0Source, DM0SAD_H, DM0SAD_L); - SWAP(dma0Dest, DM0DAD_H, DM0DAD_L); - SWAP(dma1Source, DM1SAD_H, DM1SAD_L); - SWAP(dma1Dest, DM1DAD_H, DM1DAD_L); - SWAP(dma2Source, DM2SAD_H, DM2SAD_L); - SWAP(dma2Dest, DM2DAD_H, DM2DAD_L); - SWAP(dma3Source, DM3SAD_H, DM3SAD_L); - SWAP(dma3Dest, DM3DAD_H, DM3DAD_L); - } - - if(version <= SAVE_GAME_VERSION_8) { - timer0ClockReload = TIMER_TICKS[TM0CNT & 3]; - timer1ClockReload = TIMER_TICKS[TM1CNT & 3]; - timer2ClockReload = TIMER_TICKS[TM2CNT & 3]; - timer3ClockReload = TIMER_TICKS[TM3CNT & 3]; - - timer0Ticks = ((0x10000 - TM0D) << timer0ClockReload) - timer0Ticks; - timer1Ticks = ((0x10000 - TM1D) << timer1ClockReload) - timer1Ticks; - timer2Ticks = ((0x10000 - TM2D) << timer2ClockReload) - timer2Ticks; - timer3Ticks = ((0x10000 - TM3D) << timer3ClockReload) - timer3Ticks; - interp_rate(); - } - - // set pointers! - layerEnable = layerSettings & DISPCNT; - - CPUUpdateRender(); - CPUUpdateRenderBuffers(true); - CPUUpdateWindow0(); - CPUUpdateWindow1(); - gbaSaveType = 0; - switch(saveType) { - case 0: - cpuSaveGameFunc = flashSaveDecide; - break; - case 1: - cpuSaveGameFunc = sramWrite; - gbaSaveType = 1; - break; - case 2: - cpuSaveGameFunc = flashWrite; - gbaSaveType = 2; - break; - case 3: - break; - case 5: - gbaSaveType = 5; - break; - default: - systemMessage(MSG_UNSUPPORTED_SAVE_TYPE, - N_("Unsupported save type %d"), saveType); - break; - } - if(eepromInUse) - gbaSaveType = 3; - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - if(armState) { - ARM_PREFETCH; - } else { - THUMB_PREFETCH; - } - - CPUUpdateRegister(0x204, CPUReadHalfWordQuick(0x4000204)); - - return true; -} - -bool CPUReadMemState(char *memory, int available) -{ - gzFile gzFile = utilMemGzOpen(memory, available, "r"); - - bool res = CPUReadState(gzFile); - - utilGzClose(gzFile); - - return res; -} - -bool CPUReadState(const char * file) -{ - gzFile gzFile = utilGzOpen(file, "rb"); - - if(gzFile == NULL) - return false; - - bool res = CPUReadState(gzFile); - - utilGzClose(gzFile); - - return res; -} - -bool CPUExportEepromFile(const char *fileName) -{ - if(eepromInUse) { - FILE *file = fopen(fileName, "wb"); - - if(!file) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), - fileName); - return false; - } - - for(int i = 0; i < eepromSize;) { - for(int j = 0; j < 8; j++) { - if(fwrite(&eepromData[i+7-j], 1, 1, file) != 1) { - fclose(file); - return false; - } - } - i += 8; - } - fclose(file); - } - return true; -} - -bool CPUWriteBatteryFile(const char *fileName) -{ - if(gbaSaveType == 0) { - if(eepromInUse) - gbaSaveType = 3; - else switch(saveType) { - case 1: - gbaSaveType = 1; - break; - case 2: - gbaSaveType = 2; - break; - } - } - - if((gbaSaveType) && (gbaSaveType!=5)) { - FILE *file = fopen(fileName, "wb"); - - if(!file) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), - fileName); - return false; - } - - // only save if Flash/Sram in use or EEprom in use - if(gbaSaveType != 3) { - if(gbaSaveType == 2) { - if(fwrite(flashSaveMemory, 1, flashSize, file) != (size_t)flashSize) { - fclose(file); - return false; - } - } else { - if(fwrite(flashSaveMemory, 1, 0x10000, file) != 0x10000) { - fclose(file); - return false; - } - } - } else { - if(fwrite(eepromData, 1, eepromSize, file) != (size_t)eepromSize) { - fclose(file); - return false; - } - } - fclose(file); - } - return true; -} - -bool CPUReadGSASnapshot(const char *fileName) -{ - int i; - FILE *file = fopen(fileName, "rb"); - - if(!file) { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); - return false; - } - - // check file size to know what we should read - fseek(file, 0, SEEK_END); - - // long size = ftell(file); - fseek(file, 0x0, SEEK_SET); - fread(&i, 1, 4, file); - fseek(file, i, SEEK_CUR); // Skip SharkPortSave - fseek(file, 4, SEEK_CUR); // skip some sort of flag - fread(&i, 1, 4, file); // name length - fseek(file, i, SEEK_CUR); // skip name - fread(&i, 1, 4, file); // desc length - fseek(file, i, SEEK_CUR); // skip desc - fread(&i, 1, 4, file); // notes length - fseek(file, i, SEEK_CUR); // skip notes - int saveSize; - fread(&saveSize, 1, 4, file); // read length - saveSize -= 0x1c; // remove header size - char buffer[17]; - char buffer2[17]; - fread(buffer, 1, 16, file); - buffer[16] = 0; - for(i = 0; i < 16; i++) - if(buffer[i] < 32) - buffer[i] = 32; - memcpy(buffer2, &rom[0xa0], 16); - buffer2[16] = 0; - for(i = 0; i < 16; i++) - if(buffer2[i] < 32) - buffer2[i] = 32; - if(memcmp(buffer, buffer2, 16)) { - systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, - N_("Cannot import snapshot for %s. Current game is %s"), - buffer, - buffer2); - fclose(file); - return false; - } - fseek(file, 12, SEEK_CUR); // skip some flags - if(saveSize >= 65536) { - if(fread(flashSaveMemory, 1, saveSize, file) != (size_t)saveSize) { - fclose(file); - return false; - } - } else { - systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, - N_("Unsupported snapshot file %s"), - fileName); - fclose(file); - return false; - } - fclose(file); - CPUReset(); - return true; -} - -bool CPUWriteGSASnapshot(const char *fileName, - const char *title, - const char *desc, - const char *notes) -{ - FILE *file = fopen(fileName, "wb"); - - if(!file) { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); - return false; - } - - u8 buffer[17]; - - utilPutDword(buffer, 0x0d); // SharkPortSave length - fwrite(buffer, 1, 4, file); - fwrite("SharkPortSave", 1, 0x0d, file); - utilPutDword(buffer, 0x000f0000); - fwrite(buffer, 1, 4, file); // save type 0x000f0000 = GBA save - utilPutDword(buffer, (u32)strlen(title)); - fwrite(buffer, 1, 4, file); // title length - fwrite(title, 1, strlen(title), file); - utilPutDword(buffer, (u32)strlen(desc)); - fwrite(buffer, 1, 4, file); // desc length - fwrite(desc, 1, strlen(desc), file); - utilPutDword(buffer, (u32)strlen(notes)); - fwrite(buffer, 1, 4, file); // notes length - fwrite(notes, 1, strlen(notes), file); - int saveSize = 0x10000; - if(gbaSaveType == 2) - saveSize = flashSize; - int totalSize = saveSize + 0x1c; - - utilPutDword(buffer, totalSize); // length of remainder of save - CRC - fwrite(buffer, 1, 4, file); - - char temp[0x2001c]; - memset(temp, 0, 28); - memcpy(temp, &rom[0xa0], 16); // copy internal name - temp[0x10] = rom[0xbe]; // reserved area (old checksum) - temp[0x11] = rom[0xbf]; // reserved area (old checksum) - temp[0x12] = rom[0xbd]; // complement check - temp[0x13] = rom[0xb0]; // maker - temp[0x14] = 1; // 1 save ? - memcpy(&temp[0x1c], flashSaveMemory, saveSize); // copy save - fwrite(temp, 1, totalSize, file); // write save + header - u32 crc = 0; - - for(int i = 0; i < totalSize; i++) { - crc += ((u32)temp[i] << (crc % 0x18)); - } - - utilPutDword(buffer, crc); - fwrite(buffer, 1, 4, file); // CRC? - - fclose(file); - return true; -} - -bool CPUImportEepromFile(const char *fileName) -{ - FILE *file = fopen(fileName, "rb"); - - if(!file) - return false; - - // check file size to know what we should read - fseek(file, 0, SEEK_END); - - long size = ftell(file); - fseek(file, 0, SEEK_SET); - if(size == 512 || size == 0x2000) { - if(fread(eepromData, 1, size, file) != (size_t)size) { - fclose(file); - return false; - } - for(int i = 0; i < size;) { - u8 tmp = eepromData[i]; - eepromData[i] = eepromData[7-i]; - eepromData[7-i] = tmp; - i++; - tmp = eepromData[i]; - eepromData[i] = eepromData[7-i]; - eepromData[7-i] = tmp; - i++; - tmp = eepromData[i]; - eepromData[i] = eepromData[7-i]; - eepromData[7-i] = tmp; - i++; - tmp = eepromData[i]; - eepromData[i] = eepromData[7-i]; - eepromData[7-i] = tmp; - i++; - i += 4; - } - } else - return false; - fclose(file); - return true; -} - -bool CPUReadBatteryFile(const char *fileName) -{ - FILE *file = fopen(fileName, "rb"); - - if(!file) - return false; - - // check file size to know what we should read - fseek(file, 0, SEEK_END); - - long size = ftell(file); - fseek(file, 0, SEEK_SET); - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - if(size == 512 || size == 0x2000) { - if(fread(eepromData, 1, size, file) != (size_t)size) { - fclose(file); - return false; - } - } else { - if(size == 0x20000) { - if(fread(flashSaveMemory, 1, 0x20000, file) != 0x20000) { - fclose(file); - return false; - } - flashSetSize(0x20000); - } else { - if(fread(flashSaveMemory, 1, 0x10000, file) != 0x10000) { - fclose(file); - return false; - } - flashSetSize(0x10000); - } - } - fclose(file); - return true; -} - -bool CPUWritePNGFile(const char *fileName) -{ - return utilWritePNGFile(fileName, 240, 160, pix); -} - -bool CPUWriteBMPFile(const char *fileName) -{ - return utilWriteBMPFile(fileName, 240, 160, pix); -} - -bool CPUIsZipFile(const char * file) -{ - if(strlen(file) > 4) { - const char * p = strrchr(file,'.'); - - if(p != NULL) { - if(_stricmp(p, ".zip") == 0) - return true; - } - } - - return false; -} - -bool CPUIsGBAImage(const char * file) -{ - cpuIsMultiBoot = false; - if(strlen(file) > 4) { - const char * p = strrchr(file,'.'); - - if(p != NULL) { - if(_stricmp(p, ".gba") == 0) - return true; - if(_stricmp(p, ".agb") == 0) - return true; - if(_stricmp(p, ".bin") == 0) - return true; - if(_stricmp(p, ".elf") == 0) - return true; - if(_stricmp(p, ".mb") == 0) { - cpuIsMultiBoot = true; - return true; - } - } - } - - return false; -} - -bool CPUIsGBABios(const char * file) -{ - if(strlen(file) > 4) { - const char * p = strrchr(file,'.'); - - if(p != NULL) { - if(_stricmp(p, ".gba") == 0) - return true; - if(_stricmp(p, ".agb") == 0) - return true; - if(_stricmp(p, ".bin") == 0) - return true; - if(_stricmp(p, ".bios") == 0) - return true; - if(_stricmp(p, ".rom") == 0) - return true; - } - } - - return false; -} - -bool CPUIsELF(const char *file) -{ - if(strlen(file) > 4) { - const char * p = strrchr(file,'.'); - - if(p != NULL) { - if(_stricmp(p, ".elf") == 0) - return true; - } - } - return false; -} - -void CPUCleanUp() -{ -#ifdef PROFILING - if(profilingTicksReload) { - profCleanup(); - } -#endif - - if(rom != NULL) { - free(rom); - rom = NULL; - } - - if(vram != NULL) { - free(vram); - vram = NULL; - } - - if(paletteRAM != NULL) { - free(paletteRAM); - paletteRAM = NULL; - } - - if(internalRAM != NULL) { - free(internalRAM); - internalRAM = NULL; - } - - if(workRAM != NULL) { - free(workRAM); - workRAM = NULL; - } - - if(bios != NULL) { - free(bios); - bios = NULL; - } - - if(pix != NULL) { - free(pix); - pix = NULL; - } - - if(oam != NULL) { - free(oam); - oam = NULL; - } - - if(ioMem != NULL) { - free(ioMem); - ioMem = NULL; - } - - elfCleanUp(); - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - emulating = 0; -} - -int CPULoadRom(const char *szFile) -{ - romSize = 0x2000000; - if(rom != NULL) { - CPUCleanUp(); - } - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - rom = (u8 *)malloc(0x2000000); - if(rom == NULL) { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "ROM"); - return 0; - } - workRAM = (u8 *)calloc(1, 0x40000); - if(workRAM == NULL) { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "WRAM"); - return 0; - } - - u8 *whereToLoad = cpuIsMultiBoot ? workRAM : rom; - - if(CPUIsELF(szFile)) { - FILE *f = fopen(szFile, "rb"); - if(!f) { - systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), - szFile); - free(rom); - rom = NULL; - free(workRAM); - workRAM = NULL; - return 0; - } - bool res = elfRead(szFile, romSize, f); - if(!res || romSize == 0) { - free(rom); - rom = NULL; - free(workRAM); - workRAM = NULL; - elfCleanUp(); - return 0; - } - } else if(!utilLoad(szFile, - utilIsGBAImage, - whereToLoad, - romSize)) { - free(rom); - rom = NULL; - free(workRAM); - workRAM = NULL; - return 0; - } - - u16 *temp = (u16 *)(rom+((romSize+1)&~1)); - int i; - for(i = (romSize+1)&~1; i < 0x2000000; i+=2) { - WRITE16LE(temp, (i >> 1) & 0xFFFF); - temp++; - } - - bios = (u8 *)calloc(1,0x4000); - if(bios == NULL) { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "BIOS"); - CPUCleanUp(); - return 0; - } - internalRAM = (u8 *)calloc(1,0x8000); - if(internalRAM == NULL) { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "IRAM"); - CPUCleanUp(); - return 0; - } - paletteRAM = (u8 *)calloc(1,0x400); - if(paletteRAM == NULL) { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "PRAM"); - CPUCleanUp(); - return 0; - } - vram = (u8 *)calloc(1, 0x20000); - if(vram == NULL) { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "VRAM"); - CPUCleanUp(); - return 0; - } - oam = (u8 *)calloc(1, 0x400); - if(oam == NULL) { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "OAM"); - CPUCleanUp(); - return 0; - } - pix = (u8 *)calloc(1, 4 * 241 * 162); - if(pix == NULL) { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "PIX"); - CPUCleanUp(); - return 0; - } - ioMem = (u8 *)calloc(1, 0x400); - if(ioMem == NULL) { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "IO"); - CPUCleanUp(); - return 0; - } - - flashInit(); - eepromInit(); - - CPUUpdateRenderBuffers(true); - - return romSize; -} - -void doMirroring (bool b) -{ - u32 mirroredRomSize = (((romSize)>>20) & 0x3F)<<20; - u32 mirroredRomAddress = romSize; - if ((mirroredRomSize <=0x800000) && (b)) - { - mirroredRomAddress = mirroredRomSize; - if (mirroredRomSize==0) - mirroredRomSize=0x100000; - while (mirroredRomAddress<0x01000000) - { - memcpy ((u16 *)(rom+mirroredRomAddress), (u16 *)(rom), mirroredRomSize); - mirroredRomAddress+=mirroredRomSize; - } - } -} - -void CPUUpdateRender() -{ - switch(DISPCNT & 7) { - case 0: - if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || - cpuDisableSfx) - renderLine = mode0RenderLine; - else if(fxOn && !windowOn && !(layerEnable & 0x8000)) - renderLine = mode0RenderLineNoWindow; - else - renderLine = mode0RenderLineAll; - break; - case 1: - if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || - cpuDisableSfx) - renderLine = mode1RenderLine; - else if(fxOn && !windowOn && !(layerEnable & 0x8000)) - renderLine = mode1RenderLineNoWindow; - else - renderLine = mode1RenderLineAll; - break; - case 2: - if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || - cpuDisableSfx) - renderLine = mode2RenderLine; - else if(fxOn && !windowOn && !(layerEnable & 0x8000)) - renderLine = mode2RenderLineNoWindow; - else - renderLine = mode2RenderLineAll; - break; - case 3: - if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || - cpuDisableSfx) - renderLine = mode3RenderLine; - else if(fxOn && !windowOn && !(layerEnable & 0x8000)) - renderLine = mode3RenderLineNoWindow; - else - renderLine = mode3RenderLineAll; - break; - case 4: - if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || - cpuDisableSfx) - renderLine = mode4RenderLine; - else if(fxOn && !windowOn && !(layerEnable & 0x8000)) - renderLine = mode4RenderLineNoWindow; - else - renderLine = mode4RenderLineAll; - break; - case 5: - if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || - cpuDisableSfx) - renderLine = mode5RenderLine; - else if(fxOn && !windowOn && !(layerEnable & 0x8000)) - renderLine = mode5RenderLineNoWindow; - else - renderLine = mode5RenderLineAll; - default: - break; - } -} - -void CPUUpdateCPSR() -{ - u32 CPSR = reg[16].I & 0x40; - if(N_FLAG) - CPSR |= 0x80000000; - if(Z_FLAG) - CPSR |= 0x40000000; - if(C_FLAG) - CPSR |= 0x20000000; - if(V_FLAG) - CPSR |= 0x10000000; - if(!armState) - CPSR |= 0x00000020; - if(!armIrqEnable) - CPSR |= 0x80; - CPSR |= (armMode & 0x1F); - reg[16].I = CPSR; -} - -void CPUUpdateFlags(bool breakLoop) -{ - u32 CPSR = reg[16].I; - - N_FLAG = (CPSR & 0x80000000) ? true: false; - Z_FLAG = (CPSR & 0x40000000) ? true: false; - C_FLAG = (CPSR & 0x20000000) ? true: false; - V_FLAG = (CPSR & 0x10000000) ? true: false; - armState = (CPSR & 0x20) ? false : true; - armIrqEnable = (CPSR & 0x80) ? false : true; - if(breakLoop) { - if (armIrqEnable && (IF & IE) && (IME & 1)) - cpuNextEvent = cpuTotalTicks; - } -} - -void CPUUpdateFlags() -{ - CPUUpdateFlags(true); -} - -#ifdef WORDS_BIGENDIAN -static void CPUSwap(volatile u32 *a, volatile u32 *b) -{ - volatile u32 c = *b; - *b = *a; - *a = c; -} -#else -static void CPUSwap(u32 *a, u32 *b) -{ - u32 c = *b; - *b = *a; - *a = c; -} -#endif - -void CPUSwitchMode(int mode, bool saveState, bool breakLoop) -{ - // if(armMode == mode) - // return; - - CPUUpdateCPSR(); - - switch(armMode) { - case 0x10: - case 0x1F: - reg[R13_USR].I = reg[13].I; - reg[R14_USR].I = reg[14].I; - reg[17].I = reg[16].I; - break; - case 0x11: - CPUSwap(®[R8_FIQ].I, ®[8].I); - CPUSwap(®[R9_FIQ].I, ®[9].I); - CPUSwap(®[R10_FIQ].I, ®[10].I); - CPUSwap(®[R11_FIQ].I, ®[11].I); - CPUSwap(®[R12_FIQ].I, ®[12].I); - reg[R13_FIQ].I = reg[13].I; - reg[R14_FIQ].I = reg[14].I; - reg[SPSR_FIQ].I = reg[17].I; - break; - case 0x12: - reg[R13_IRQ].I = reg[13].I; - reg[R14_IRQ].I = reg[14].I; - reg[SPSR_IRQ].I = reg[17].I; - break; - case 0x13: - reg[R13_SVC].I = reg[13].I; - reg[R14_SVC].I = reg[14].I; - reg[SPSR_SVC].I = reg[17].I; - break; - case 0x17: - reg[R13_ABT].I = reg[13].I; - reg[R14_ABT].I = reg[14].I; - reg[SPSR_ABT].I = reg[17].I; - break; - case 0x1b: - reg[R13_UND].I = reg[13].I; - reg[R14_UND].I = reg[14].I; - reg[SPSR_UND].I = reg[17].I; - break; - } - - u32 CPSR = reg[16].I; - u32 SPSR = reg[17].I; - - switch(mode) { - case 0x10: - case 0x1F: - reg[13].I = reg[R13_USR].I; - reg[14].I = reg[R14_USR].I; - reg[16].I = SPSR; - break; - case 0x11: - CPUSwap(®[8].I, ®[R8_FIQ].I); - CPUSwap(®[9].I, ®[R9_FIQ].I); - CPUSwap(®[10].I, ®[R10_FIQ].I); - CPUSwap(®[11].I, ®[R11_FIQ].I); - CPUSwap(®[12].I, ®[R12_FIQ].I); - reg[13].I = reg[R13_FIQ].I; - reg[14].I = reg[R14_FIQ].I; - if(saveState) - reg[17].I = CPSR; - else - reg[17].I = reg[SPSR_FIQ].I; - break; - case 0x12: - reg[13].I = reg[R13_IRQ].I; - reg[14].I = reg[R14_IRQ].I; - reg[16].I = SPSR; - if(saveState) - reg[17].I = CPSR; - else - reg[17].I = reg[SPSR_IRQ].I; - break; - case 0x13: - reg[13].I = reg[R13_SVC].I; - reg[14].I = reg[R14_SVC].I; - reg[16].I = SPSR; - if(saveState) - reg[17].I = CPSR; - else - reg[17].I = reg[SPSR_SVC].I; - break; - case 0x17: - reg[13].I = reg[R13_ABT].I; - reg[14].I = reg[R14_ABT].I; - reg[16].I = SPSR; - if(saveState) - reg[17].I = CPSR; - else - reg[17].I = reg[SPSR_ABT].I; - break; - case 0x1b: - reg[13].I = reg[R13_UND].I; - reg[14].I = reg[R14_UND].I; - reg[16].I = SPSR; - if(saveState) - reg[17].I = CPSR; - else - reg[17].I = reg[SPSR_UND].I; - break; - default: - systemMessage(MSG_UNSUPPORTED_ARM_MODE, N_("Unsupported ARM mode %02x"), mode); - break; - } - armMode = mode; - CPUUpdateFlags(breakLoop); - CPUUpdateCPSR(); -} - -void CPUSwitchMode(int mode, bool saveState) -{ - CPUSwitchMode(mode, saveState, true); -} - -void CPUUndefinedException() -{ - u32 PC = reg[15].I; - bool savedArmState = armState; - CPUSwitchMode(0x1b, true, false); - reg[14].I = PC - (savedArmState ? 4 : 2); - reg[15].I = 0x04; - armState = true; - armIrqEnable = false; - armNextPC = 0x04; - ARM_PREFETCH; - reg[15].I += 4; -} - -void CPUSoftwareInterrupt() -{ - u32 PC = reg[15].I; - bool savedArmState = armState; - CPUSwitchMode(0x13, true, false); - reg[14].I = PC - (savedArmState ? 4 : 2); - reg[15].I = 0x08; - armState = true; - armIrqEnable = false; - armNextPC = 0x08; - ARM_PREFETCH; - reg[15].I += 4; -} - -void CPUSoftwareInterrupt(int comment) -{ - static bool disableMessage = false; - if(armState) comment >>= 16; -#ifdef BKPT_SUPPORT - if(comment == 0xff) { - dbgOutput(NULL, reg[0].I); - return; - } -#endif -#ifdef PROFILING - if(comment == 0xfe) { - profStartup(reg[0].I, reg[1].I); - return; - } - if(comment == 0xfd) { - profControl(reg[0].I); - return; - } - if(comment == 0xfc) { - profCleanup(); - return; - } - if(comment == 0xfb) { - profCount(); - return; - } -#endif - if(comment == 0xfa) { - agbPrintFlush(); - return; - } -#ifdef SDL - if(comment == 0xf9) { - emulating = 0; - cpuNextEvent = cpuTotalTicks; - cpuBreakLoop = true; - return; - } -#endif - if(useBios) { -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_SWI) { - log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, - armState ? armNextPC - 4: armNextPC -2, - reg[0].I, - reg[1].I, - reg[2].I, - VCOUNT); - } -#endif - CPUSoftwareInterrupt(); - return; - } - // This would be correct, but it causes problems if uncommented - // else { - // biosProtected = 0xe3a02004; - // } - - switch(comment) { - case 0x00: - BIOS_SoftReset(); - ARM_PREFETCH; - break; - case 0x01: - BIOS_RegisterRamReset(); - break; - case 0x02: -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_SWI) { - log("Halt: (VCOUNT = %2d)\n", - VCOUNT); - } -#endif - holdState = true; - holdType = -1; - cpuNextEvent = cpuTotalTicks; - break; - case 0x03: -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_SWI) { - log("Stop: (VCOUNT = %2d)\n", - VCOUNT); - } -#endif - holdState = true; - holdType = -1; - stopState = true; - cpuNextEvent = cpuTotalTicks; - break; - case 0x04: -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_SWI) { - log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n", - reg[0].I, - reg[1].I, - VCOUNT); - } -#endif - CPUSoftwareInterrupt(); - break; - case 0x05: -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_SWI) { - log("VBlankIntrWait: (VCOUNT = %2d)\n", - VCOUNT); - } -#endif - CPUSoftwareInterrupt(); - break; - case 0x06: - CPUSoftwareInterrupt(); - break; - case 0x07: - CPUSoftwareInterrupt(); - break; - case 0x08: - BIOS_Sqrt(); - break; - case 0x09: - BIOS_ArcTan(); - break; - case 0x0A: - BIOS_ArcTan2(); - break; - case 0x0B: - { - int len = (reg[2].I & 0x1FFFFF) >>1; - if (!(((reg[0].I & 0xe000000) == 0) || - ((reg[0].I + len) & 0xe000000) == 0)) - { - if ((reg[2].I >> 24) & 1) - { - if ((reg[2].I >> 26) & 1) - SWITicks = (7 + memoryWait32[(reg[1].I>>24) & 0xF]) * (len>>1); - else - SWITicks = (8 + memoryWait[(reg[1].I>>24) & 0xF]) * (len); - } - else - { - if ((reg[2].I >> 26) & 1) - SWITicks = (10 + memoryWait32[(reg[0].I>>24) & 0xF] + - memoryWait32[(reg[1].I>>24) & 0xF]) * (len>>1); - else - SWITicks = (11 + memoryWait[(reg[0].I>>24) & 0xF] + - memoryWait[(reg[1].I>>24) & 0xF]) * len; - } - } - } - BIOS_CpuSet(); - break; - case 0x0C: - { - int len = (reg[2].I & 0x1FFFFF) >>5; - if (!(((reg[0].I & 0xe000000) == 0) || - ((reg[0].I + len) & 0xe000000) == 0)) - { - if ((reg[2].I >> 24) & 1) - SWITicks = (6 + memoryWait32[(reg[1].I>>24) & 0xF] + - 7 * (memoryWaitSeq32[(reg[1].I>>24) & 0xF] + 1)) * len; - else - SWITicks = (9 + memoryWait32[(reg[0].I>>24) & 0xF] + - memoryWait32[(reg[1].I>>24) & 0xF] + - 7 * (memoryWaitSeq32[(reg[0].I>>24) & 0xF] + - memoryWaitSeq32[(reg[1].I>>24) & 0xF] + 2)) * len; - } - } - BIOS_CpuFastSet(); - break; - case 0x0D: - BIOS_GetBiosChecksum(); - break; - case 0x0E: - BIOS_BgAffineSet(); - break; - case 0x0F: - BIOS_ObjAffineSet(); - break; - case 0x10: - { - int len = CPUReadHalfWord(reg[2].I); - if (!(((reg[0].I & 0xe000000) == 0) || - ((reg[0].I + len) & 0xe000000) == 0)) - SWITicks = (32 + memoryWait[(reg[0].I>>24) & 0xF]) * len; - } - BIOS_BitUnPack(); - break; - case 0x11: - { - u32 len = CPUReadMemory(reg[0].I) >> 8; - if(!(((reg[0].I & 0xe000000) == 0) || - ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) - SWITicks = (9 + memoryWait[(reg[1].I>>24) & 0xF]) * len; - } - BIOS_LZ77UnCompWram(); - break; - case 0x12: - { - u32 len = CPUReadMemory(reg[0].I) >> 8; - if(!(((reg[0].I & 0xe000000) == 0) || - ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) - SWITicks = (19 + memoryWait[(reg[1].I>>24) & 0xF]) * len; - } - BIOS_LZ77UnCompVram(); - break; - case 0x13: - { - u32 len = CPUReadMemory(reg[0].I) >> 8; - if(!(((reg[0].I & 0xe000000) == 0) || - ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) - SWITicks = (29 + (memoryWait[(reg[0].I>>24) & 0xF]<<1)) * len; - } - BIOS_HuffUnComp(); - break; - case 0x14: - { - u32 len = CPUReadMemory(reg[0].I) >> 8; - if(!(((reg[0].I & 0xe000000) == 0) || - ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) - SWITicks = (11 + memoryWait[(reg[0].I>>24) & 0xF] + - memoryWait[(reg[1].I>>24) & 0xF]) * len; - } - BIOS_RLUnCompWram(); - break; - case 0x15: - { - u32 len = CPUReadMemory(reg[0].I) >> 9; - if(!(((reg[0].I & 0xe000000) == 0) || - ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) - SWITicks = (34 + (memoryWait[(reg[0].I>>24) & 0xF] << 1) + - memoryWait[(reg[1].I>>24) & 0xF]) * len; - } - BIOS_RLUnCompVram(); - break; - case 0x16: - { - u32 len = CPUReadMemory(reg[0].I) >> 8; - if(!(((reg[0].I & 0xe000000) == 0) || - ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) - SWITicks = (13 + memoryWait[(reg[0].I>>24) & 0xF] + - memoryWait[(reg[1].I>>24) & 0xF]) * len; - } - BIOS_Diff8bitUnFilterWram(); - break; - case 0x17: - { - u32 len = CPUReadMemory(reg[0].I) >> 9; - if(!(((reg[0].I & 0xe000000) == 0) || - ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) - SWITicks = (39 + (memoryWait[(reg[0].I>>24) & 0xF]<<1) + - memoryWait[(reg[1].I>>24) & 0xF]) * len; - } - BIOS_Diff8bitUnFilterVram(); - break; - case 0x18: - { - u32 len = CPUReadMemory(reg[0].I) >> 9; - if(!(((reg[0].I & 0xe000000) == 0) || - ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) - SWITicks = (13 + memoryWait[(reg[0].I>>24) & 0xF] + - memoryWait[(reg[1].I>>24) & 0xF]) * len; - } - BIOS_Diff16bitUnFilter(); - break; - case 0x19: -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_SWI) { - log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n", - reg[0].I, - VCOUNT); - } -#endif - if(reg[0].I) - systemSoundPause(); - else - systemSoundResume(); - break; - case 0x1F: - BIOS_MidiKey2Freq(); - break; - case 0x2A: - BIOS_SndDriverJmpTableCopy(); - // let it go, because we don't really emulate this function - default: -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_SWI) { - log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, - armState ? armNextPC - 4: armNextPC -2, - reg[0].I, - reg[1].I, - reg[2].I, - VCOUNT); - } -#endif - - if(!disableMessage) { - systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION, - N_("Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."), - comment, - armMode ? armNextPC - 4: armNextPC - 2); - disableMessage = true; - } - break; - } -} - -void CPUCompareVCOUNT() -{ - if(VCOUNT == (DISPSTAT >> 8)) { - DISPSTAT |= 4; - UPDATE_REG(0x04, DISPSTAT); - - if(DISPSTAT & 0x20) { - IF |= 4; - UPDATE_REG(0x202, IF); - } - } else { - DISPSTAT &= 0xFFFB; - UPDATE_REG(0x4, DISPSTAT); - } - if (layerEnableDelay>0) - { - layerEnableDelay--; - if (layerEnableDelay==1) - layerEnable = layerSettings & DISPCNT; - } - -} - -void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32) -{ - int sm = s >> 24; - int dm = d >> 24; - int sw = 0; - int dw = 0; - int sc = c; - - cpuDmaCount = c; - // This is done to get the correct waitstates. - if (sm>15) - sm=15; - if (dm>15) - dm=15; - - //if ((sm>=0x05) && (sm<=0x07) || (dm>=0x05) && (dm <=0x07)) - // blank = (((DISPSTAT | ((DISPSTAT>>1)&1))==1) ? true : false); - - if(transfer32) { - s &= 0xFFFFFFFC; - if(s < 0x02000000 && (reg[15].I >> 24)) { - while(c != 0) { - CPUWriteMemory(d, 0); - d += di; - c--; - } - } else { - while(c != 0) { - cpuDmaLast = CPUReadMemory(s); - CPUWriteMemory(d, cpuDmaLast); - d += di; - s += si; - c--; - } - } - } else { - s &= 0xFFFFFFFE; - si = (int)si >> 1; - di = (int)di >> 1; - if(s < 0x02000000 && (reg[15].I >> 24)) { - while(c != 0) { - CPUWriteHalfWord(d, 0); - d += di; - c--; - } - } else { - while(c != 0) { - cpuDmaLast = CPUReadHalfWord(s); - CPUWriteHalfWord(d, cpuDmaLast); - cpuDmaLast |= (cpuDmaLast<<16); - d += di; - s += si; - c--; - } - } - } - - cpuDmaCount = 0; - - int totalTicks = 0; - - if(transfer32) { - sw =1+memoryWaitSeq32[sm & 15]; - dw =1+memoryWaitSeq32[dm & 15]; - totalTicks = (sw+dw)*(sc-1) + 6 + memoryWait32[sm & 15] + - memoryWaitSeq32[dm & 15]; - } - else - { - sw = 1+memoryWaitSeq[sm & 15]; - dw = 1+memoryWaitSeq[dm & 15]; - totalTicks = (sw+dw)*(sc-1) + 6 + memoryWait[sm & 15] + - memoryWaitSeq[dm & 15]; - } - - cpuDmaTicksToUpdate += totalTicks; - -} - -void CPUCheckDMA(int reason, int dmamask) -{ - // DMA 0 - if((DM0CNT_H & 0x8000) && (dmamask & 1)) { - if(((DM0CNT_H >> 12) & 3) == reason) { - u32 sourceIncrement = 4; - u32 destIncrement = 4; - switch((DM0CNT_H >> 7) & 3) { - case 0: - break; - case 1: - sourceIncrement = (u32)-4; - break; - case 2: - sourceIncrement = 0; - break; - } - switch((DM0CNT_H >> 5) & 3) { - case 0: - break; - case 1: - destIncrement = (u32)-4; - break; - case 2: - destIncrement = 0; - break; - } -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_DMA0) { - int count = (DM0CNT_L ? DM0CNT_L : 0x4000) << 1; - if(DM0CNT_H & 0x0400) - count <<= 1; - log("DMA0: s=%08x d=%08x c=%04x count=%08x\n", dma0Source, dma0Dest, - DM0CNT_H, - count); - } -#endif - doDMA(dma0Source, dma0Dest, sourceIncrement, destIncrement, - DM0CNT_L ? DM0CNT_L : 0x4000, - DM0CNT_H & 0x0400); - cpuDmaHack = true; - - if(DM0CNT_H & 0x4000) { - IF |= 0x0100; - UPDATE_REG(0x202, IF); - cpuNextEvent = cpuTotalTicks; - } - - if(((DM0CNT_H >> 5) & 3) == 3) { - dma0Dest = DM0DAD_L | (DM0DAD_H << 16); - } - - if(!(DM0CNT_H & 0x0200) || (reason == 0)) { - DM0CNT_H &= 0x7FFF; - UPDATE_REG(0xBA, DM0CNT_H); - } - } - } - - // DMA 1 - if((DM1CNT_H & 0x8000) && (dmamask & 2)) { - if(((DM1CNT_H >> 12) & 3) == reason) { - u32 sourceIncrement = 4; - u32 destIncrement = 4; - switch((DM1CNT_H >> 7) & 3) { - case 0: - break; - case 1: - sourceIncrement = (u32)-4; - break; - case 2: - sourceIncrement = 0; - break; - } - switch((DM1CNT_H >> 5) & 3) { - case 0: - break; - case 1: - destIncrement = (u32)-4; - break; - case 2: - destIncrement = 0; - break; - } - if(reason == 3) { -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_DMA1) { - log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest, - DM1CNT_H, - 16); - } -#endif - doDMA(dma1Source, dma1Dest, sourceIncrement, 0, 4, - 0x0400); - } else { -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_DMA1) { - int count = (DM1CNT_L ? DM1CNT_L : 0x4000) << 1; - if(DM1CNT_H & 0x0400) - count <<= 1; - log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest, - DM1CNT_H, - count); - } -#endif - doDMA(dma1Source, dma1Dest, sourceIncrement, destIncrement, - DM1CNT_L ? DM1CNT_L : 0x4000, - DM1CNT_H & 0x0400); - } - cpuDmaHack = true; - - if(DM1CNT_H & 0x4000) { - IF |= 0x0200; - UPDATE_REG(0x202, IF); - cpuNextEvent = cpuTotalTicks; - } - - if(((DM1CNT_H >> 5) & 3) == 3) { - dma1Dest = DM1DAD_L | (DM1DAD_H << 16); - } - - if(!(DM1CNT_H & 0x0200) || (reason == 0)) { - DM1CNT_H &= 0x7FFF; - UPDATE_REG(0xC6, DM1CNT_H); - } - } - } - - // DMA 2 - if((DM2CNT_H & 0x8000) && (dmamask & 4)) { - if(((DM2CNT_H >> 12) & 3) == reason) { - u32 sourceIncrement = 4; - u32 destIncrement = 4; - switch((DM2CNT_H >> 7) & 3) { - case 0: - break; - case 1: - sourceIncrement = (u32)-4; - break; - case 2: - sourceIncrement = 0; - break; - } - switch((DM2CNT_H >> 5) & 3) { - case 0: - break; - case 1: - destIncrement = (u32)-4; - break; - case 2: - destIncrement = 0; - break; - } - if(reason == 3) { -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_DMA2) { - int count = (4) << 2; - log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest, - DM2CNT_H, - count); - } -#endif - doDMA(dma2Source, dma2Dest, sourceIncrement, 0, 4, - 0x0400); - } else { -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_DMA2) { - int count = (DM2CNT_L ? DM2CNT_L : 0x4000) << 1; - if(DM2CNT_H & 0x0400) - count <<= 1; - log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest, - DM2CNT_H, - count); - } -#endif - doDMA(dma2Source, dma2Dest, sourceIncrement, destIncrement, - DM2CNT_L ? DM2CNT_L : 0x4000, - DM2CNT_H & 0x0400); - } - cpuDmaHack = true; - - if(DM2CNT_H & 0x4000) { - IF |= 0x0400; - UPDATE_REG(0x202, IF); - cpuNextEvent = cpuTotalTicks; - } - - if(((DM2CNT_H >> 5) & 3) == 3) { - dma2Dest = DM2DAD_L | (DM2DAD_H << 16); - } - - if(!(DM2CNT_H & 0x0200) || (reason == 0)) { - DM2CNT_H &= 0x7FFF; - UPDATE_REG(0xD2, DM2CNT_H); - } - } - } - - // DMA 3 - if((DM3CNT_H & 0x8000) && (dmamask & 8)) { - if(((DM3CNT_H >> 12) & 3) == reason) { - u32 sourceIncrement = 4; - u32 destIncrement = 4; - switch((DM3CNT_H >> 7) & 3) { - case 0: - break; - case 1: - sourceIncrement = (u32)-4; - break; - case 2: - sourceIncrement = 0; - break; - } - switch((DM3CNT_H >> 5) & 3) { - case 0: - break; - case 1: - destIncrement = (u32)-4; - break; - case 2: - destIncrement = 0; - break; - } -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_DMA3) { - int count = (DM3CNT_L ? DM3CNT_L : 0x10000) << 1; - if(DM3CNT_H & 0x0400) - count <<= 1; - log("DMA3: s=%08x d=%08x c=%04x count=%08x\n", dma3Source, dma3Dest, - DM3CNT_H, - count); - } -#endif - doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement, - DM3CNT_L ? DM3CNT_L : 0x10000, - DM3CNT_H & 0x0400); - if(DM3CNT_H & 0x4000) { - IF |= 0x0800; - UPDATE_REG(0x202, IF); - cpuNextEvent = cpuTotalTicks; - } - - if(((DM3CNT_H >> 5) & 3) == 3) { - dma3Dest = DM3DAD_L | (DM3DAD_H << 16); - } - - if(!(DM3CNT_H & 0x0200) || (reason == 0)) { - DM3CNT_H &= 0x7FFF; - UPDATE_REG(0xDE, DM3CNT_H); - } - } - } -} - -void CPUUpdateRegister(u32 address, u16 value) -{ - switch(address) { - case 0x00: - { - if ((value & 7) >5) - DISPCNT = (value &7); - bool change = ((DISPCNT ^ value) & 0x80) ? true : false; - bool changeBG = ((DISPCNT ^ value) & 0x0F00) ? true : false; - u16 changeBGon = (((~DISPCNT) & value) & 0x0F00); - DISPCNT = (value & 0xFFF7); - UPDATE_REG(0x00, DISPCNT); - - if (changeBGon) - { - layerEnableDelay=4; - layerEnable = layerSettings & value & (~changeBGon); - } - else - layerEnable = layerSettings & value; - // CPUUpdateTicks(); - - windowOn = (layerEnable & 0x6000) ? true : false; - if(change && !((value & 0x80))) { - if(!(DISPSTAT & 1)) { - lcdTicks = 1008; - // VCOUNT = 0; - // UPDATE_REG(0x06, VCOUNT); - DISPSTAT &= 0xFFFC; - UPDATE_REG(0x04, DISPSTAT); - CPUCompareVCOUNT(); - } - // (*renderLine)(); - } - CPUUpdateRender(); - // we only care about changes in BG0-BG3 - if(changeBG) - CPUUpdateRenderBuffers(false); - } - break; - case 0x04: - DISPSTAT = (value & 0xFF38) | (DISPSTAT & 7); - UPDATE_REG(0x04, DISPSTAT); - break; - case 0x06: - // not writable - break; - case 0x08: - BG0CNT = (value & 0xDFCF); - UPDATE_REG(0x08, BG0CNT); - break; - case 0x0A: - BG1CNT = (value & 0xDFCF); - UPDATE_REG(0x0A, BG1CNT); - break; - case 0x0C: - BG2CNT = (value & 0xFFCF); - UPDATE_REG(0x0C, BG2CNT); - break; - case 0x0E: - BG3CNT = (value & 0xFFCF); - UPDATE_REG(0x0E, BG3CNT); - break; - case 0x10: - BG0HOFS = value & 511; - UPDATE_REG(0x10, BG0HOFS); - break; - case 0x12: - BG0VOFS = value & 511; - UPDATE_REG(0x12, BG0VOFS); - break; - case 0x14: - BG1HOFS = value & 511; - UPDATE_REG(0x14, BG1HOFS); - break; - case 0x16: - BG1VOFS = value & 511; - UPDATE_REG(0x16, BG1VOFS); - break; - case 0x18: - BG2HOFS = value & 511; - UPDATE_REG(0x18, BG2HOFS); - break; - case 0x1A: - BG2VOFS = value & 511; - UPDATE_REG(0x1A, BG2VOFS); - break; - case 0x1C: - BG3HOFS = value & 511; - UPDATE_REG(0x1C, BG3HOFS); - break; - case 0x1E: - BG3VOFS = value & 511; - UPDATE_REG(0x1E, BG3VOFS); - break; - case 0x20: - BG2PA = value; - UPDATE_REG(0x20, BG2PA); - break; - case 0x22: - BG2PB = value; - UPDATE_REG(0x22, BG2PB); - break; - case 0x24: - BG2PC = value; - UPDATE_REG(0x24, BG2PC); - break; - case 0x26: - BG2PD = value; - UPDATE_REG(0x26, BG2PD); - break; - case 0x28: - BG2X_L = value; - UPDATE_REG(0x28, BG2X_L); - gfxBG2Changed |= 1; - break; - case 0x2A: - BG2X_H = (value & 0xFFF); - UPDATE_REG(0x2A, BG2X_H); - gfxBG2Changed |= 1; - break; - case 0x2C: - BG2Y_L = value; - UPDATE_REG(0x2C, BG2Y_L); - gfxBG2Changed |= 2; - break; - case 0x2E: - BG2Y_H = value & 0xFFF; - UPDATE_REG(0x2E, BG2Y_H); - gfxBG2Changed |= 2; - break; - case 0x30: - BG3PA = value; - UPDATE_REG(0x30, BG3PA); - break; - case 0x32: - BG3PB = value; - UPDATE_REG(0x32, BG3PB); - break; - case 0x34: - BG3PC = value; - UPDATE_REG(0x34, BG3PC); - break; - case 0x36: - BG3PD = value; - UPDATE_REG(0x36, BG3PD); - break; - case 0x38: - BG3X_L = value; - UPDATE_REG(0x38, BG3X_L); - gfxBG3Changed |= 1; - break; - case 0x3A: - BG3X_H = value & 0xFFF; - UPDATE_REG(0x3A, BG3X_H); - gfxBG3Changed |= 1; - break; - case 0x3C: - BG3Y_L = value; - UPDATE_REG(0x3C, BG3Y_L); - gfxBG3Changed |= 2; - break; - case 0x3E: - BG3Y_H = value & 0xFFF; - UPDATE_REG(0x3E, BG3Y_H); - gfxBG3Changed |= 2; - break; - case 0x40: - WIN0H = value; - UPDATE_REG(0x40, WIN0H); - CPUUpdateWindow0(); - break; - case 0x42: - WIN1H = value; - UPDATE_REG(0x42, WIN1H); - CPUUpdateWindow1(); - break; - case 0x44: - WIN0V = value; - UPDATE_REG(0x44, WIN0V); - break; - case 0x46: - WIN1V = value; - UPDATE_REG(0x46, WIN1V); - break; - case 0x48: - WININ = value & 0x3F3F; - UPDATE_REG(0x48, WININ); - break; - case 0x4A: - WINOUT = value & 0x3F3F; - UPDATE_REG(0x4A, WINOUT); - break; - case 0x4C: - MOSAIC = value; - UPDATE_REG(0x4C, MOSAIC); - break; - case 0x50: - BLDMOD = value & 0x3FFF; - UPDATE_REG(0x50, BLDMOD); - fxOn = ((BLDMOD>>6)&3) != 0; - CPUUpdateRender(); - break; - case 0x52: - COLEV = value & 0x1F1F; - UPDATE_REG(0x52, COLEV); - break; - case 0x54: - COLY = value & 0x1F; - UPDATE_REG(0x54, COLY); - break; - case 0x60: - case 0x62: - case 0x64: - case 0x68: - case 0x6c: - case 0x70: - case 0x72: - case 0x74: - case 0x78: - case 0x7c: - case 0x80: - case 0x84: - soundEvent(address&0xFF, (u8)(value & 0xFF)); - soundEvent((address&0xFF)+1, (u8)(value>>8)); - break; - case 0x82: - case 0x88: - case 0xa0: - case 0xa2: - case 0xa4: - case 0xa6: - case 0x90: - case 0x92: - case 0x94: - case 0x96: - case 0x98: - case 0x9a: - case 0x9c: - case 0x9e: - soundEvent(address&0xFF, value); - break; - case 0xB0: - DM0SAD_L = value; - UPDATE_REG(0xB0, DM0SAD_L); - break; - case 0xB2: - DM0SAD_H = value & 0x07FF; - UPDATE_REG(0xB2, DM0SAD_H); - break; - case 0xB4: - DM0DAD_L = value; - UPDATE_REG(0xB4, DM0DAD_L); - break; - case 0xB6: - DM0DAD_H = value & 0x07FF; - UPDATE_REG(0xB6, DM0DAD_H); - break; - case 0xB8: - DM0CNT_L = value & 0x3FFF; - UPDATE_REG(0xB8, 0); - break; - case 0xBA: - { - bool start = ((DM0CNT_H ^ value) & 0x8000) ? true : false; - value &= 0xF7E0; - - DM0CNT_H = value; - UPDATE_REG(0xBA, DM0CNT_H); - - if(start && (value & 0x8000)) { - dma0Source = DM0SAD_L | (DM0SAD_H << 16); - dma0Dest = DM0DAD_L | (DM0DAD_H << 16); - CPUCheckDMA(0, 1); - } - } - break; - case 0xBC: - DM1SAD_L = value; - UPDATE_REG(0xBC, DM1SAD_L); - break; - case 0xBE: - DM1SAD_H = value & 0x0FFF; - UPDATE_REG(0xBE, DM1SAD_H); - break; - case 0xC0: - DM1DAD_L = value; - UPDATE_REG(0xC0, DM1DAD_L); - break; - case 0xC2: - DM1DAD_H = value & 0x07FF; - UPDATE_REG(0xC2, DM1DAD_H); - break; - case 0xC4: - DM1CNT_L = value & 0x3FFF; - UPDATE_REG(0xC4, 0); - break; - case 0xC6: - { - bool start = ((DM1CNT_H ^ value) & 0x8000) ? true : false; - value &= 0xF7E0; - - DM1CNT_H = value; - UPDATE_REG(0xC6, DM1CNT_H); - - if(start && (value & 0x8000)) { - dma1Source = DM1SAD_L | (DM1SAD_H << 16); - dma1Dest = DM1DAD_L | (DM1DAD_H << 16); - CPUCheckDMA(0, 2); - } - } - break; - case 0xC8: - DM2SAD_L = value; - UPDATE_REG(0xC8, DM2SAD_L); - break; - case 0xCA: - DM2SAD_H = value & 0x0FFF; - UPDATE_REG(0xCA, DM2SAD_H); - break; - case 0xCC: - DM2DAD_L = value; - UPDATE_REG(0xCC, DM2DAD_L); - break; - case 0xCE: - DM2DAD_H = value & 0x07FF; - UPDATE_REG(0xCE, DM2DAD_H); - break; - case 0xD0: - DM2CNT_L = value & 0x3FFF; - UPDATE_REG(0xD0, 0); - break; - case 0xD2: - { - bool start = ((DM2CNT_H ^ value) & 0x8000) ? true : false; - - value &= 0xF7E0; - - DM2CNT_H = value; - UPDATE_REG(0xD2, DM2CNT_H); - - if(start && (value & 0x8000)) { - dma2Source = DM2SAD_L | (DM2SAD_H << 16); - dma2Dest = DM2DAD_L | (DM2DAD_H << 16); - - CPUCheckDMA(0, 4); - } - } - break; - case 0xD4: - DM3SAD_L = value; - UPDATE_REG(0xD4, DM3SAD_L); - break; - case 0xD6: - DM3SAD_H = value & 0x0FFF; - UPDATE_REG(0xD6, DM3SAD_H); - break; - case 0xD8: - DM3DAD_L = value; - UPDATE_REG(0xD8, DM3DAD_L); - break; - case 0xDA: - DM3DAD_H = value & 0x0FFF; - UPDATE_REG(0xDA, DM3DAD_H); - break; - case 0xDC: - DM3CNT_L = value; - UPDATE_REG(0xDC, 0); - break; - case 0xDE: - { - bool start = ((DM3CNT_H ^ value) & 0x8000) ? true : false; - - value &= 0xFFE0; - - DM3CNT_H = value; - UPDATE_REG(0xDE, DM3CNT_H); - - if(start && (value & 0x8000)) { - dma3Source = DM3SAD_L | (DM3SAD_H << 16); - dma3Dest = DM3DAD_L | (DM3DAD_H << 16); - CPUCheckDMA(0,8); - } - } - break; - case 0x100: - timer0Reload = value; - interp_rate(); - break; - case 0x102: - timer0Value = value; - timerOnOffDelay|=1; - cpuNextEvent = cpuTotalTicks; - break; - case 0x104: - timer1Reload = value; - interp_rate(); - break; - case 0x106: - timer1Value = value; - timerOnOffDelay|=2; - cpuNextEvent = cpuTotalTicks; - break; - case 0x108: - timer2Reload = value; - break; - case 0x10A: - timer2Value = value; - timerOnOffDelay|=4; - cpuNextEvent = cpuTotalTicks; - break; - case 0x10C: - timer3Reload = value; - break; - case 0x10E: - timer3Value = value; - timerOnOffDelay|=8; - cpuNextEvent = cpuTotalTicks; - break; - case 0x128: - #ifdef LINK_EMULATION - if (linkenable) - { - StartLink(value); - } - else -#endif - { - if(value & 0x80) { - value &= 0xff7f; - if(value & 1 && (value & 0x4000)) { - UPDATE_REG(0x12a, 0xFF); - IF |= 0x80; - UPDATE_REG(0x202, IF); - value &= 0x7f7f; - } - } - UPDATE_REG(0x128, value); - } - break; - case 0x12a: - #ifdef LINK_EMULATION - if(linkenable && lspeed) - LinkSSend(value); - #endif - { - UPDATE_REG(0x134, value); - } - break; - case 0x130: - P1 |= (value & 0x3FF); - UPDATE_REG(0x130, P1); - break; - case 0x132: - UPDATE_REG(0x132, value & 0xC3FF); - break; - case 0x134: -#ifdef LINK_EMULATION - if (linkenable) - StartGPLink(value); - else -#endif - UPDATE_REG(0x134, value); - - break; - case 0x140: -#ifdef LINK_EMULATION - if (linkenable) - StartJOYLink(value); - else -#endif - UPDATE_REG(0x140, value); - - break; - case 0x200: - IE = value & 0x3FFF; - UPDATE_REG(0x200, IE); - if ((IME & 1) && (IF & IE) && armIrqEnable) - cpuNextEvent = cpuTotalTicks; - break; - case 0x202: - IF ^= (value & IF); - UPDATE_REG(0x202, IF); - break; - case 0x204: - { - memoryWait[0x0e] = memoryWaitSeq[0x0e] = gamepakRamWaitState[value & 3]; - - if(!speedHack) { - memoryWait[0x08] = memoryWait[0x09] = gamepakWaitState[(value >> 2) & 3]; - memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = - gamepakWaitState0[(value >> 4) & 1]; - - memoryWait[0x0a] = memoryWait[0x0b] = gamepakWaitState[(value >> 5) & 3]; - memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = - gamepakWaitState1[(value >> 7) & 1]; - - memoryWait[0x0c] = memoryWait[0x0d] = gamepakWaitState[(value >> 8) & 3]; - memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = - gamepakWaitState2[(value >> 10) & 1]; - } else { - memoryWait[0x08] = memoryWait[0x09] = 3; - memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = 1; - - memoryWait[0x0a] = memoryWait[0x0b] = 3; - memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = 1; - - memoryWait[0x0c] = memoryWait[0x0d] = 3; - memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = 1; - } - - for(int i = 8; i < 15; i++) { - memoryWait32[i] = memoryWait[i] + memoryWaitSeq[i] + 1; - memoryWaitSeq32[i] = memoryWaitSeq[i]*2 + 1; - } - - if((value & 0x4000) == 0x4000) { - busPrefetchEnable = true; - busPrefetch = false; - busPrefetchCount = 0; - } else { - busPrefetchEnable = false; - busPrefetch = false; - busPrefetchCount = 0; - } - UPDATE_REG(0x204, value & 0x7FFF); - - } - break; - case 0x208: - IME = value & 1; - UPDATE_REG(0x208, IME); - if ((IME & 1) && (IF & IE) && armIrqEnable) - cpuNextEvent = cpuTotalTicks; - break; - case 0x300: - if(value != 0) - value &= 0xFFFE; - UPDATE_REG(0x300, value); - break; - default: - UPDATE_REG(address&0x3FE, value); - break; - } -} - -void applyTimer () -{ - if (timerOnOffDelay & 1) - { - timer0ClockReload = TIMER_TICKS[timer0Value & 3]; - if(!timer0On && (timer0Value & 0x80)) { - // reload the counter - TM0D = timer0Reload; - timer0Ticks = (0x10000 - TM0D) << timer0ClockReload; - UPDATE_REG(0x100, TM0D); - } - timer0On = timer0Value & 0x80 ? true : false; - TM0CNT = timer0Value & 0xC7; - interp_rate(); - UPDATE_REG(0x102, TM0CNT); - // CPUUpdateTicks(); - } - if (timerOnOffDelay & 2) - { - timer1ClockReload = TIMER_TICKS[timer1Value & 3]; - if(!timer1On && (timer1Value & 0x80)) { - // reload the counter - TM1D = timer1Reload; - timer1Ticks = (0x10000 - TM1D) << timer1ClockReload; - UPDATE_REG(0x104, TM1D); - } - timer1On = timer1Value & 0x80 ? true : false; - TM1CNT = timer1Value & 0xC7; - interp_rate(); - UPDATE_REG(0x106, TM1CNT); - } - if (timerOnOffDelay & 4) - { - timer2ClockReload = TIMER_TICKS[timer2Value & 3]; - if(!timer2On && (timer2Value & 0x80)) { - // reload the counter - TM2D = timer2Reload; - timer2Ticks = (0x10000 - TM2D) << timer2ClockReload; - UPDATE_REG(0x108, TM2D); - } - timer2On = timer2Value & 0x80 ? true : false; - TM2CNT = timer2Value & 0xC7; - UPDATE_REG(0x10A, TM2CNT); - } - if (timerOnOffDelay & 8) - { - timer3ClockReload = TIMER_TICKS[timer3Value & 3]; - if(!timer3On && (timer3Value & 0x80)) { - // reload the counter - TM3D = timer3Reload; - timer3Ticks = (0x10000 - TM3D) << timer3ClockReload; - UPDATE_REG(0x10C, TM3D); - } - timer3On = timer3Value & 0x80 ? true : false; - TM3CNT = timer3Value & 0xC7; - UPDATE_REG(0x10E, TM3CNT); - } - cpuNextEvent = CPUUpdateTicks(); - timerOnOffDelay = 0; -} - -u8 cpuBitsSet[256]; -u8 cpuLowestBitSet[256]; - -void CPUInit(const char *biosFileName, bool useBiosFile) -{ -#ifdef WORDS_BIGENDIAN - if(!cpuBiosSwapped) { - for(unsigned int i = 0; i < sizeof(myROM)/4; i++) { - WRITE32LE(&myROM[i], myROM[i]); - } - cpuBiosSwapped = true; - } -#endif - gbaSaveType = 0; - eepromInUse = 0; - saveType = 0; - useBios = false; - - if(useBiosFile) { - int size = 0x4000; - if(utilLoad(biosFileName, - CPUIsGBABios, - bios, - size)) { - if(size == 0x4000) - useBios = true; - else - systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BIOS file size")); - } - } - - if(!useBios) { - memcpy(bios, myROM, sizeof(myROM)); - } - - int i = 0; - - biosProtected[0] = 0x00; - biosProtected[1] = 0xf0; - biosProtected[2] = 0x29; - biosProtected[3] = 0xe1; - - for(i = 0; i < 256; i++) { - int count = 0; - int j; - for(j = 0; j < 8; j++) - if(i & (1 << j)) - count++; - cpuBitsSet[i] = count; - - for(j = 0; j < 8; j++) - if(i & (1 << j)) - break; - cpuLowestBitSet[i] = j; - } - - for(i = 0; i < 0x400; i++) - ioReadable[i] = true; - for(i = 0x10; i < 0x48; i++) - ioReadable[i] = false; - for(i = 0x4c; i < 0x50; i++) - ioReadable[i] = false; - for(i = 0x54; i < 0x60; i++) - ioReadable[i] = false; - for(i = 0x8c; i < 0x90; i++) - ioReadable[i] = false; - for(i = 0xa0; i < 0xb8; i++) - ioReadable[i] = false; - for(i = 0xbc; i < 0xc4; i++) - ioReadable[i] = false; - for(i = 0xc8; i < 0xd0; i++) - ioReadable[i] = false; - for(i = 0xd4; i < 0xdc; i++) - ioReadable[i] = false; - for(i = 0xe0; i < 0x100; i++) - ioReadable[i] = false; - for(i = 0x110; i < 0x120; i++) - ioReadable[i] = false; - for(i = 0x12c; i < 0x130; i++) - ioReadable[i] = false; - for(i = 0x138; i < 0x140; i++) - ioReadable[i] = false; - for(i = 0x144; i < 0x150; i++) - ioReadable[i] = false; - for(i = 0x15c; i < 0x200; i++) - ioReadable[i] = false; - for(i = 0x20c; i < 0x300; i++) - ioReadable[i] = false; - for(i = 0x304; i < 0x400; i++) - ioReadable[i] = false; - - if(romSize < 0x1fe2000) { - *((u16 *)&rom[0x1fe209c]) = 0xdffa; // SWI 0xFA - *((u16 *)&rom[0x1fe209e]) = 0x4770; // BX LR - } else { - agbPrintEnable(false); - } -} - -void CPUReset() -{ - if(gbaSaveType == 0) { - if(eepromInUse) - gbaSaveType = 3; - else - switch(saveType) { - case 1: - gbaSaveType = 1; - break; - case 2: - gbaSaveType = 2; - break; - } - } - rtcReset(); - // clean registers - memset(®[0], 0, sizeof(reg)); - // clean OAM - memset(oam, 0, 0x400); - // clean palette - memset(paletteRAM, 0, 0x400); - // clean picture - memset(pix, 0, 4*160*240); - // clean vram - memset(vram, 0, 0x20000); - // clean io memory - memset(ioMem, 0, 0x400); - - DISPCNT = 0x0080; - DISPSTAT = 0x0000; - VCOUNT = (useBios && !skipBios) ? 0 :0x007E; - BG0CNT = 0x0000; - BG1CNT = 0x0000; - BG2CNT = 0x0000; - BG3CNT = 0x0000; - BG0HOFS = 0x0000; - BG0VOFS = 0x0000; - BG1HOFS = 0x0000; - BG1VOFS = 0x0000; - BG2HOFS = 0x0000; - BG2VOFS = 0x0000; - BG3HOFS = 0x0000; - BG3VOFS = 0x0000; - BG2PA = 0x0100; - BG2PB = 0x0000; - BG2PC = 0x0000; - BG2PD = 0x0100; - BG2X_L = 0x0000; - BG2X_H = 0x0000; - BG2Y_L = 0x0000; - BG2Y_H = 0x0000; - BG3PA = 0x0100; - BG3PB = 0x0000; - BG3PC = 0x0000; - BG3PD = 0x0100; - BG3X_L = 0x0000; - BG3X_H = 0x0000; - BG3Y_L = 0x0000; - BG3Y_H = 0x0000; - WIN0H = 0x0000; - WIN1H = 0x0000; - WIN0V = 0x0000; - WIN1V = 0x0000; - WININ = 0x0000; - WINOUT = 0x0000; - MOSAIC = 0x0000; - BLDMOD = 0x0000; - COLEV = 0x0000; - COLY = 0x0000; - DM0SAD_L = 0x0000; - DM0SAD_H = 0x0000; - DM0DAD_L = 0x0000; - DM0DAD_H = 0x0000; - DM0CNT_L = 0x0000; - DM0CNT_H = 0x0000; - DM1SAD_L = 0x0000; - DM1SAD_H = 0x0000; - DM1DAD_L = 0x0000; - DM1DAD_H = 0x0000; - DM1CNT_L = 0x0000; - DM1CNT_H = 0x0000; - DM2SAD_L = 0x0000; - DM2SAD_H = 0x0000; - DM2DAD_L = 0x0000; - DM2DAD_H = 0x0000; - DM2CNT_L = 0x0000; - DM2CNT_H = 0x0000; - DM3SAD_L = 0x0000; - DM3SAD_H = 0x0000; - DM3DAD_L = 0x0000; - DM3DAD_H = 0x0000; - DM3CNT_L = 0x0000; - DM3CNT_H = 0x0000; - TM0D = 0x0000; - TM0CNT = 0x0000; - TM1D = 0x0000; - TM1CNT = 0x0000; - TM2D = 0x0000; - TM2CNT = 0x0000; - TM3D = 0x0000; - TM3CNT = 0x0000; - P1 = 0x03FF; - IE = 0x0000; - IF = 0x0000; - IME = 0x0000; - - armMode = 0x1F; - - if(cpuIsMultiBoot) { - reg[13].I = 0x03007F00; - reg[15].I = 0x02000000; - reg[16].I = 0x00000000; - reg[R13_IRQ].I = 0x03007FA0; - reg[R13_SVC].I = 0x03007FE0; - armIrqEnable = true; - } else { - if(useBios && !skipBios) { - reg[15].I = 0x00000000; - armMode = 0x13; - armIrqEnable = false; - } else { - reg[13].I = 0x03007F00; - reg[15].I = 0x08000000; - reg[16].I = 0x00000000; - reg[R13_IRQ].I = 0x03007FA0; - reg[R13_SVC].I = 0x03007FE0; - armIrqEnable = true; - } - } - armState = true; - C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false; - UPDATE_REG(0x00, DISPCNT); - UPDATE_REG(0x06, VCOUNT); - UPDATE_REG(0x20, BG2PA); - UPDATE_REG(0x26, BG2PD); - UPDATE_REG(0x30, BG3PA); - UPDATE_REG(0x36, BG3PD); - UPDATE_REG(0x130, P1); - UPDATE_REG(0x88, 0x200); - - // disable FIQ - reg[16].I |= 0x40; - - CPUUpdateCPSR(); - - armNextPC = reg[15].I; - reg[15].I += 4; - - // reset internal state - holdState = false; - holdType = 0; - - biosProtected[0] = 0x00; - biosProtected[1] = 0xf0; - biosProtected[2] = 0x29; - biosProtected[3] = 0xe1; - - lcdTicks = (useBios && !skipBios) ? 1008 : 208; - timer0On = false; - timer0Ticks = 0; - timer0Reload = 0; - timer0ClockReload = 0; - timer1On = false; - timer1Ticks = 0; - timer1Reload = 0; - timer1ClockReload = 0; - timer2On = false; - timer2Ticks = 0; - timer2Reload = 0; - timer2ClockReload = 0; - timer3On = false; - timer3Ticks = 0; - timer3Reload = 0; - timer3ClockReload = 0; - dma0Source = 0; - dma0Dest = 0; - dma1Source = 0; - dma1Dest = 0; - dma2Source = 0; - dma2Dest = 0; - dma3Source = 0; - dma3Dest = 0; - cpuSaveGameFunc = flashSaveDecide; - renderLine = mode0RenderLine; - fxOn = false; - windowOn = false; - frameCount = 0; - saveType = 0; - layerEnable = DISPCNT & layerSettings; - - CPUUpdateRenderBuffers(true); - - for(int i = 0; i < 256; i++) { - map[i].address = (u8 *)&dummyAddress; - map[i].mask = 0; - } - - map[0].address = bios; - map[0].mask = 0x3FFF; - map[2].address = workRAM; - map[2].mask = 0x3FFFF; - map[3].address = internalRAM; - map[3].mask = 0x7FFF; - map[4].address = ioMem; - map[4].mask = 0x3FF; - map[5].address = paletteRAM; - map[5].mask = 0x3FF; - map[6].address = vram; - map[6].mask = 0x1FFFF; - map[7].address = oam; - map[7].mask = 0x3FF; - map[8].address = rom; - map[8].mask = 0x1FFFFFF; - map[9].address = rom; - map[9].mask = 0x1FFFFFF; - map[10].address = rom; - map[10].mask = 0x1FFFFFF; - map[12].address = rom; - map[12].mask = 0x1FFFFFF; - map[14].address = flashSaveMemory; - map[14].mask = 0xFFFF; - - eepromReset(); - flashReset(); - - soundReset(); - - CPUUpdateWindow0(); - CPUUpdateWindow1(); - - // make sure registers are correctly initialized if not using BIOS - if(!useBios) { - if(cpuIsMultiBoot) - BIOS_RegisterRamReset(0xfe); - else - BIOS_RegisterRamReset(0xff); - } else { - if(cpuIsMultiBoot) - BIOS_RegisterRamReset(0xfe); - } - - switch(cpuSaveType) { - case 0: // automatic - cpuSramEnabled = true; - cpuFlashEnabled = true; - cpuEEPROMEnabled = true; - cpuEEPROMSensorEnabled = false; - saveType = gbaSaveType = 0; - break; - case 1: // EEPROM - cpuSramEnabled = false; - cpuFlashEnabled = false; - cpuEEPROMEnabled = true; - cpuEEPROMSensorEnabled = false; - saveType = gbaSaveType = 3; - // EEPROM usage is automatically detected - break; - case 2: // SRAM - cpuSramEnabled = true; - cpuFlashEnabled = false; - cpuEEPROMEnabled = false; - cpuEEPROMSensorEnabled = false; - cpuSaveGameFunc = sramDelayedWrite; // to insure we detect the write - saveType = gbaSaveType = 1; - break; - case 3: // FLASH - cpuSramEnabled = false; - cpuFlashEnabled = true; - cpuEEPROMEnabled = false; - cpuEEPROMSensorEnabled = false; - cpuSaveGameFunc = flashDelayedWrite; // to insure we detect the write - saveType = gbaSaveType = 2; - break; - case 4: // EEPROM+Sensor - cpuSramEnabled = false; - cpuFlashEnabled = false; - cpuEEPROMEnabled = true; - cpuEEPROMSensorEnabled = true; - // EEPROM usage is automatically detected - saveType = gbaSaveType = 3; - break; - case 5: // NONE - cpuSramEnabled = false; - cpuFlashEnabled = false; - cpuEEPROMEnabled = false; - cpuEEPROMSensorEnabled = false; - // no save at all - saveType = gbaSaveType = 5; - break; - } - - ARM_PREFETCH; - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - cpuDmaHack = false; - - lastTime = systemGetClock(); - - SWITicks = 0; -} - -void CPUInterrupt() -{ - u32 PC = reg[15].I; - bool savedState = armState; - CPUSwitchMode(0x12, true, false); - reg[14].I = PC; - if(!savedState) - reg[14].I += 2; - reg[15].I = 0x18; - armState = true; - armIrqEnable = false; - - armNextPC = reg[15].I; - reg[15].I += 4; - ARM_PREFETCH; - - // if(!holdState) - biosProtected[0] = 0x02; - biosProtected[1] = 0xc0; - biosProtected[2] = 0x5e; - biosProtected[3] = 0xe5; -} - -#ifdef SDL -void log(const char *defaultMsg, ...) -{ - char buffer[2048]; - va_list valist; - - va_start(valist, defaultMsg); - vsprintf(buffer, defaultMsg, valist); - - if(out == NULL) { - out = fopen("trace.log","w"); - } - - fputs(buffer, out); - - va_end(valist); -} -#else -extern void winlog(const char *, ...); -#endif - -void CPULoop(int ticks) -{ - int clockTicks; - int timerOverflow = 0; - // variable used by the CPU core - cpuTotalTicks = 0; -#ifdef LINK_EMULATION - if(linkenable) - cpuNextEvent = 1; -#endif - cpuBreakLoop = false; - cpuNextEvent = CPUUpdateTicks(); - if(cpuNextEvent > ticks) - cpuNextEvent = ticks; - - - for(;;) { -#ifndef FINAL_VERSION - if(systemDebug) { - if(systemDebug >= 10 && !holdState) { - CPUUpdateCPSR(); -#ifdef BKPT_SUPPORT - if (debugger_last) - { - sprintf(buffer, "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n", - oldreg[0], oldreg[1], oldreg[2], oldreg[3], oldreg[4], oldreg[5], - oldreg[6], oldreg[7], oldreg[8], oldreg[9], oldreg[10], oldreg[11], - oldreg[12], oldreg[13], oldreg[14], oldreg[15], oldreg[16], - oldreg[17]); - } -#endif - sprintf(buffer, "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n", - reg[0].I, reg[1].I, reg[2].I, reg[3].I, reg[4].I, reg[5].I, - reg[6].I, reg[7].I, reg[8].I, reg[9].I, reg[10].I, reg[11].I, - reg[12].I, reg[13].I, reg[14].I, reg[15].I, reg[16].I, - reg[17].I); -#ifdef SDL - log(buffer); -#else - winlog(buffer); -#endif - } else if(!holdState) { - sprintf(buffer, "PC=%08x\n", armNextPC); -#ifdef SDL - log(buffer); -#else - winlog(buffer); -#endif - } - } -#endif /* FINAL_VERSION */ - - if(!holdState && !SWITicks) { - if(armState) { - if (!armExecute()) - return; - } else { - if (!thumbExecute()) - return; - } - clockTicks = 0; - } else - clockTicks = CPUUpdateTicks(); - - cpuTotalTicks += clockTicks; - - - if(cpuTotalTicks >= cpuNextEvent) { - int remainingTicks = cpuTotalTicks - cpuNextEvent; - - if (SWITicks) - { - SWITicks-=clockTicks; - if (SWITicks<0) - SWITicks = 0; - } - - clockTicks = cpuNextEvent; - cpuTotalTicks = 0; - cpuDmaHack = false; - - updateLoop: - - if (IRQTicks) - { - IRQTicks -= clockTicks; - if (IRQTicks<0) - IRQTicks = 0; - } - - lcdTicks -= clockTicks; - - - if(lcdTicks <= 0) { - if(DISPSTAT & 1) { // V-BLANK - // if in V-Blank mode, keep computing... - if(DISPSTAT & 2) { - lcdTicks += 1008; - VCOUNT++; - UPDATE_REG(0x06, VCOUNT); - DISPSTAT &= 0xFFFD; - UPDATE_REG(0x04, DISPSTAT); - CPUCompareVCOUNT(); - } else { - lcdTicks += 224; - DISPSTAT |= 2; - UPDATE_REG(0x04, DISPSTAT); - if(DISPSTAT & 16) { - IF |= 2; - UPDATE_REG(0x202, IF); - } - } - - if(VCOUNT >= 228) { //Reaching last line - DISPSTAT &= 0xFFFC; - UPDATE_REG(0x04, DISPSTAT); - VCOUNT = 0; - UPDATE_REG(0x06, VCOUNT); - CPUCompareVCOUNT(); - } - } else { - int framesToSkip = systemFrameSkip; - if(speedup) - framesToSkip = 9; // try 6 FPS during speedup - - if(DISPSTAT & 2) { - // if in H-Blank, leave it and move to drawing mode - VCOUNT++; - UPDATE_REG(0x06, VCOUNT); - - lcdTicks += 1008; - DISPSTAT &= 0xFFFD; - if(VCOUNT == 160) { - count++; - systemFrame(); - - if((count % 10) == 0) { - system10Frames(60); - } - if(count == 60) { - u32 time = systemGetClock(); - if(time != lastTime) { - u32 t = 100000/(time - lastTime); - systemShowSpeed(t); - } else - systemShowSpeed(0); - lastTime = time; - count = 0; - } - u32 joy = 0; - // update joystick information - if(systemReadJoypads()) - // read default joystick - joy = systemReadJoypad(-1); - P1 = 0x03FF ^ (joy & 0x3FF); - if(cpuEEPROMSensorEnabled) - systemUpdateMotionSensor(); - UPDATE_REG(0x130, P1); - u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132])); - // this seems wrong, but there are cases where the game - // can enter the stop state without requesting an IRQ from - // the joypad. - if((P1CNT & 0x4000) || stopState) { - u16 p1 = (0x3FF ^ P1) & 0x3FF; - if(P1CNT & 0x8000) { - if(p1 == (P1CNT & 0x3FF)) { - IF |= 0x1000; - UPDATE_REG(0x202, IF); - } - } else { - if(p1 & P1CNT) { - IF |= 0x1000; - UPDATE_REG(0x202, IF); - } - } - } - - u32 ext = (joy >> 10); - // If no (m) code is enabled, apply the cheats at each LCDline - if((cheatsEnabled) && (mastercode==0)) - remainingTicks += cheatsCheckKeys(P1^0x3FF, ext); - speedup = (ext & 1) ? true : false; - capture = (ext & 2) ? true : false; - - if(capture && !capturePrevious) { - captureNumber++; - systemScreenCapture(captureNumber); - } - capturePrevious = capture; - - DISPSTAT |= 1; - DISPSTAT &= 0xFFFD; - UPDATE_REG(0x04, DISPSTAT); - if(DISPSTAT & 0x0008) { - IF |= 1; - UPDATE_REG(0x202, IF); - } - CPUCheckDMA(1, 0x0f); - if(frameCount >= framesToSkip) { - systemDrawScreen(); - frameCount = 0; - } else - frameCount++; - if(systemPauseOnFrame()) - ticks = 0; - } - - UPDATE_REG(0x04, DISPSTAT); - CPUCompareVCOUNT(); - - } else { - if(frameCount >= framesToSkip) - { - (*renderLine)(); - switch(systemColorDepth) { - case 16: - { - u16 *dest = (u16 *)pix + 242 * (VCOUNT+1); - for(int x = 0; x < 240;) { - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - } - // for filters that read past the screen - *dest++ = 0; - } - break; - case 24: - { - u8 *dest = (u8 *)pix + 240 * VCOUNT * 3; - for(int x = 0; x < 240;) { - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - } - } - break; - case 32: - { - u32 *dest = (u32 *)pix + 241 * (VCOUNT+1); - for(int x = 0; x < 240; ) { - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - } - } - break; - } - } - // entering H-Blank - DISPSTAT |= 2; - UPDATE_REG(0x04, DISPSTAT); - lcdTicks += 224; - CPUCheckDMA(2, 0x0f); - if(DISPSTAT & 16) { - IF |= 2; - UPDATE_REG(0x202, IF); - } - } - } - } - - // we shouldn't be doing sound in stop state, but we loose synchronization - // if sound is disabled, so in stop state, soundTick will just produce - // mute sound - soundTicks -= clockTicks; - if(soundTicks <= 0) { - psoundTickfn(); - soundTicks += SOUND_CLOCK_TICKS; - } - - if(!stopState) { - if(timer0On) { - timer0Ticks -= clockTicks; - if(timer0Ticks <= 0) { - timer0Ticks += (0x10000 - timer0Reload) << timer0ClockReload; - timerOverflow |= 1; - soundTimerOverflow(0); - if(TM0CNT & 0x40) { - IF |= 0x08; - UPDATE_REG(0x202, IF); - } - } - TM0D = 0xFFFF - (timer0Ticks >> timer0ClockReload); - UPDATE_REG(0x100, TM0D); - } - - if(timer1On) { - if(TM1CNT & 4) { - if(timerOverflow & 1) { - TM1D++; - if(TM1D == 0) { - TM1D += timer1Reload; - timerOverflow |= 2; - soundTimerOverflow(1); - if(TM1CNT & 0x40) { - IF |= 0x10; - UPDATE_REG(0x202, IF); - } - } - UPDATE_REG(0x104, TM1D); - } - } else { - timer1Ticks -= clockTicks; - if(timer1Ticks <= 0) { - timer1Ticks += (0x10000 - timer1Reload) << timer1ClockReload; - timerOverflow |= 2; - soundTimerOverflow(1); - if(TM1CNT & 0x40) { - IF |= 0x10; - UPDATE_REG(0x202, IF); - } - } - TM1D = 0xFFFF - (timer1Ticks >> timer1ClockReload); - UPDATE_REG(0x104, TM1D); - } - } - - if(timer2On) { - if(TM2CNT & 4) { - if(timerOverflow & 2) { - TM2D++; - if(TM2D == 0) { - TM2D += timer2Reload; - timerOverflow |= 4; - if(TM2CNT & 0x40) { - IF |= 0x20; - UPDATE_REG(0x202, IF); - } - } - UPDATE_REG(0x108, TM2D); - } - } else { - timer2Ticks -= clockTicks; - if(timer2Ticks <= 0) { - timer2Ticks += (0x10000 - timer2Reload) << timer2ClockReload; - timerOverflow |= 4; - if(TM2CNT & 0x40) { - IF |= 0x20; - UPDATE_REG(0x202, IF); - } - } - TM2D = 0xFFFF - (timer2Ticks >> timer2ClockReload); - UPDATE_REG(0x108, TM2D); - } - } - - if(timer3On) { - if(TM3CNT & 4) { - if(timerOverflow & 4) { - TM3D++; - if(TM3D == 0) { - TM3D += timer3Reload; - if(TM3CNT & 0x40) { - IF |= 0x40; - UPDATE_REG(0x202, IF); - } - } - UPDATE_REG(0x10C, TM3D); - } - } else { - timer3Ticks -= clockTicks; - if(timer3Ticks <= 0) { - timer3Ticks += (0x10000 - timer3Reload) << timer3ClockReload; - if(TM3CNT & 0x40) { - IF |= 0x40; - UPDATE_REG(0x202, IF); - } - } - TM3D = 0xFFFF - (timer3Ticks >> timer3ClockReload); - UPDATE_REG(0x10C, TM3D); - } - } - } - - timerOverflow = 0; - - - -#ifdef PROFILING - profilingTicks -= clockTicks; - if(profilingTicks <= 0) { - profilingTicks += profilingTicksReload; - if(profilSegment) { - profile_segment *seg = profilSegment; - do { - u16 *b = (u16 *)seg->sbuf; - int pc = ((reg[15].I - seg->s_lowpc) * seg->s_scale)/0x10000; - if(pc >= 0 && pc < seg->ssiz) { - b[pc]++; - break; - } - - seg = seg->next; - } while(seg); - } - } -#endif - - ticks -= clockTicks; -#ifdef LINK_EMULATION - if (linkenable) - LinkUpdate(clockTicks); -#endif - cpuNextEvent = CPUUpdateTicks(); - - if(cpuDmaTicksToUpdate > 0) { - if(cpuDmaTicksToUpdate > cpuNextEvent) - clockTicks = cpuNextEvent; - else - clockTicks = cpuDmaTicksToUpdate; - cpuDmaTicksToUpdate -= clockTicks; - if(cpuDmaTicksToUpdate < 0) - cpuDmaTicksToUpdate = 0; - cpuDmaHack = true; - goto updateLoop; - } -#ifdef LINK_EMULATION - if(linkenable) - cpuNextEvent = 1; -#endif - if(IF && (IME & 1) && armIrqEnable) { - int res = IF & IE; - if(stopState) - res &= 0x3080; - if(res) { - if (intState) - { - if (!IRQTicks) - { - CPUInterrupt(); - intState = false; - holdState = false; - stopState = false; - holdType = 0; - } - } - else - { - if (!holdState) - { - intState = true; - IRQTicks=7; - if (cpuNextEvent> IRQTicks) - cpuNextEvent = IRQTicks; - } - else - { - CPUInterrupt(); - holdState = false; - stopState = false; - holdType = 0; - } - } - - // Stops the SWI Ticks emulation if an IRQ is executed - //(to avoid problems with nested IRQ/SWI) - if (SWITicks) - SWITicks = 0; - } - } - - if(remainingTicks > 0) { - if(remainingTicks > cpuNextEvent) - clockTicks = cpuNextEvent; - else - clockTicks = remainingTicks; - remainingTicks -= clockTicks; - if(remainingTicks < 0) - remainingTicks = 0; - goto updateLoop; - } - - if (timerOnOffDelay) - applyTimer(); - - if(cpuNextEvent > ticks) - cpuNextEvent = ticks; - - if(ticks <= 0 || cpuBreakLoop) - break; - - } - } -} - - - -struct EmulatedSystem GBASystem = { - // emuMain - CPULoop, - // emuReset - CPUReset, - // emuCleanUp - CPUCleanUp, - // emuReadBattery - CPUReadBatteryFile, - // emuWriteBattery - CPUWriteBatteryFile, - // emuReadState - CPUReadState, - // emuWriteState - CPUWriteState, - // emuReadMemState - CPUReadMemState, - // emuWriteMemState - CPUWriteMemState, - // emuWritePNG - CPUWritePNGFile, - // emuWriteBMP - CPUWriteBMPFile, - // emuUpdateCPSR - CPUUpdateCPSR, - // emuHasDebugger - true, - // emuCount -#ifdef FINAL_VERSION - 250000 -#else - 5000 -#endif -}; +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team +// Copyright (C) VBA-M development team +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include +#include +#include +#include +#include "GBA.h" +#include "GBAcpu.h" +#include "GBAinline.h" +#include "../Globals.h" +#include "GBAGfx.h" +#include "../EEprom.h" +#include "../Flash.h" +#include "../Sound.h" +#include "../Sram.h" +#include "../bios.h" +#include "../Cheats.h" +#include "../NLS.h" +#include "../elf.h" +#include "../Util.h" +#include "../Port.h" +#include "../System.h" +#include "agbprint.h" +#ifdef PROFILING +#include "prof/prof.h" +#endif + +#ifdef __GNUC__ +#define _stricmp strcasecmp +#endif + + +extern int emulating; +#ifdef LINK_EMULATION +extern int linktime; +extern void StartLink(u16); +extern void StartJOYLink(u16); +extern void StartGPLink(u16); +extern void LinkSSend(u16); +extern void LinkUpdate(int); +extern int linktime2; +#endif +int SWITicks = 0; +int IRQTicks = 0; + +u32 mastercode = 0; +int layerEnableDelay = 0; +bool busPrefetch = false; +bool busPrefetchEnable = false; +u32 busPrefetchCount = 0; +int cpuDmaTicksToUpdate = 0; +int cpuDmaCount = 0; +bool cpuDmaHack = false; +u32 cpuDmaLast = 0; +int dummyAddress = 0; + +bool cpuBreakLoop = false; +int cpuNextEvent = 0; + +int gbaSaveType = 0; // used to remember the save type on reset +bool intState = false; +bool stopState = false; +bool holdState = false; +int holdType = 0; +bool cpuSramEnabled = true; +bool cpuFlashEnabled = true; +bool cpuEEPROMEnabled = true; +bool cpuEEPROMSensorEnabled = false; + +u32 cpuPrefetch[2]; + +int cpuTotalTicks = 0; +#ifdef PROFILING +int profilingTicks = 0; +int profilingTicksReload = 0; +static profile_segment *profilSegment = NULL; +#endif + +#ifdef BKPT_SUPPORT +u8 freezeWorkRAM[0x40000]; +u8 freezeInternalRAM[0x8000]; +u8 freezeVRAM[0x18000]; +u8 freezePRAM[0x400]; +u8 freezeOAM[0x400]; +bool debugger_last; +#endif + +int lcdTicks = (useBios && !skipBios) ? 1008 : 208; +u8 timerOnOffDelay = 0; +u16 timer0Value = 0; +bool timer0On = false; +int timer0Ticks = 0; +int timer0Reload = 0; +int timer0ClockReload = 0; +u16 timer1Value = 0; +bool timer1On = false; +int timer1Ticks = 0; +int timer1Reload = 0; +int timer1ClockReload = 0; +u16 timer2Value = 0; +bool timer2On = false; +int timer2Ticks = 0; +int timer2Reload = 0; +int timer2ClockReload = 0; +u16 timer3Value = 0; +bool timer3On = false; +int timer3Ticks = 0; +int timer3Reload = 0; +int timer3ClockReload = 0; +u32 dma0Source = 0; +u32 dma0Dest = 0; +u32 dma1Source = 0; +u32 dma1Dest = 0; +u32 dma2Source = 0; +u32 dma2Dest = 0; +u32 dma3Source = 0; +u32 dma3Dest = 0; +void (*cpuSaveGameFunc)(u32,u8) = flashSaveDecide; +void (*renderLine)() = mode0RenderLine; +bool fxOn = false; +bool windowOn = false; +int frameCount = 0; +char buffer[1024]; +FILE *out = NULL; +u32 lastTime = 0; +int count = 0; + +int capture = 0; +int capturePrevious = 0; +int captureNumber = 0; + +const int TIMER_TICKS[4] = { + 0, + 6, + 8, + 10 +}; + +const u32 objTilesAddress [3] = {0x010000, 0x014000, 0x014000}; +const u8 gamepakRamWaitState[4] = { 4, 3, 2, 8 }; +const u8 gamepakWaitState[4] = { 4, 3, 2, 8 }; +const u8 gamepakWaitState0[2] = { 2, 1 }; +const u8 gamepakWaitState1[2] = { 4, 1 }; +const u8 gamepakWaitState2[2] = { 8, 1 }; +const bool isInRom [16]= + { false, false, false, false, false, false, false, false, + true, true, true, true, true, true, false, false }; + +u8 memoryWait[16] = + { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 }; +u8 memoryWait32[16] = + { 0, 0, 5, 0, 0, 1, 1, 0, 7, 7, 9, 9, 13, 13, 4, 0 }; +u8 memoryWaitSeq[16] = + { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 }; +u8 memoryWaitSeq32[16] = + { 0, 0, 5, 0, 0, 1, 1, 0, 5, 5, 9, 9, 17, 17, 4, 0 }; + +// The videoMemoryWait constants are used to add some waitstates +// if the opcode access video memory data outside of vblank/hblank +// It seems to happen on only one ticks for each pixel. +// Not used for now (too problematic with current code). +//const u8 videoMemoryWait[16] = +// {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + +u8 biosProtected[4]; + +#ifdef WORDS_BIGENDIAN +bool cpuBiosSwapped = false; +#endif + +u32 myROM[] = { +0xEA000006, +0xEA000093, +0xEA000006, +0x00000000, +0x00000000, +0x00000000, +0xEA000088, +0x00000000, +0xE3A00302, +0xE1A0F000, +0xE92D5800, +0xE55EC002, +0xE28FB03C, +0xE79BC10C, +0xE14FB000, +0xE92D0800, +0xE20BB080, +0xE38BB01F, +0xE129F00B, +0xE92D4004, +0xE1A0E00F, +0xE12FFF1C, +0xE8BD4004, +0xE3A0C0D3, +0xE129F00C, +0xE8BD0800, +0xE169F00B, +0xE8BD5800, +0xE1B0F00E, +0x0000009C, +0x0000009C, +0x0000009C, +0x0000009C, +0x000001F8, +0x000001F0, +0x000000AC, +0x000000A0, +0x000000FC, +0x00000168, +0xE12FFF1E, +0xE1A03000, +0xE1A00001, +0xE1A01003, +0xE2113102, +0x42611000, +0xE033C040, +0x22600000, +0xE1B02001, +0xE15200A0, +0x91A02082, +0x3AFFFFFC, +0xE1500002, +0xE0A33003, +0x20400002, +0xE1320001, +0x11A020A2, +0x1AFFFFF9, +0xE1A01000, +0xE1A00003, +0xE1B0C08C, +0x22600000, +0x42611000, +0xE12FFF1E, +0xE92D0010, +0xE1A0C000, +0xE3A01001, +0xE1500001, +0x81A000A0, +0x81A01081, +0x8AFFFFFB, +0xE1A0000C, +0xE1A04001, +0xE3A03000, +0xE1A02001, +0xE15200A0, +0x91A02082, +0x3AFFFFFC, +0xE1500002, +0xE0A33003, +0x20400002, +0xE1320001, +0x11A020A2, +0x1AFFFFF9, +0xE0811003, +0xE1B010A1, +0xE1510004, +0x3AFFFFEE, +0xE1A00004, +0xE8BD0010, +0xE12FFF1E, +0xE0010090, +0xE1A01741, +0xE2611000, +0xE3A030A9, +0xE0030391, +0xE1A03743, +0xE2833E39, +0xE0030391, +0xE1A03743, +0xE2833C09, +0xE283301C, +0xE0030391, +0xE1A03743, +0xE2833C0F, +0xE28330B6, +0xE0030391, +0xE1A03743, +0xE2833C16, +0xE28330AA, +0xE0030391, +0xE1A03743, +0xE2833A02, +0xE2833081, +0xE0030391, +0xE1A03743, +0xE2833C36, +0xE2833051, +0xE0030391, +0xE1A03743, +0xE2833CA2, +0xE28330F9, +0xE0000093, +0xE1A00840, +0xE12FFF1E, +0xE3A00001, +0xE3A01001, +0xE92D4010, +0xE3A03000, +0xE3A04001, +0xE3500000, +0x1B000004, +0xE5CC3301, +0xEB000002, +0x0AFFFFFC, +0xE8BD4010, +0xE12FFF1E, +0xE3A0C301, +0xE5CC3208, +0xE15C20B8, +0xE0110002, +0x10222000, +0x114C20B8, +0xE5CC4208, +0xE12FFF1E, +0xE92D500F, +0xE3A00301, +0xE1A0E00F, +0xE510F004, +0xE8BD500F, +0xE25EF004, +0xE59FD044, +0xE92D5000, +0xE14FC000, +0xE10FE000, +0xE92D5000, +0xE3A0C302, +0xE5DCE09C, +0xE35E00A5, +0x1A000004, +0x05DCE0B4, +0x021EE080, +0xE28FE004, +0x159FF018, +0x059FF018, +0xE59FD018, +0xE8BD5000, +0xE169F00C, +0xE8BD5000, +0xE25EF004, +0x03007FF0, +0x09FE2000, +0x09FFC000, +0x03007FE0 +}; + +variable_desc saveGameStruct[] = { + { &DISPCNT , sizeof(u16) }, + { &DISPSTAT , sizeof(u16) }, + { &VCOUNT , sizeof(u16) }, + { &BG0CNT , sizeof(u16) }, + { &BG1CNT , sizeof(u16) }, + { &BG2CNT , sizeof(u16) }, + { &BG3CNT , sizeof(u16) }, + { &BG0HOFS , sizeof(u16) }, + { &BG0VOFS , sizeof(u16) }, + { &BG1HOFS , sizeof(u16) }, + { &BG1VOFS , sizeof(u16) }, + { &BG2HOFS , sizeof(u16) }, + { &BG2VOFS , sizeof(u16) }, + { &BG3HOFS , sizeof(u16) }, + { &BG3VOFS , sizeof(u16) }, + { &BG2PA , sizeof(u16) }, + { &BG2PB , sizeof(u16) }, + { &BG2PC , sizeof(u16) }, + { &BG2PD , sizeof(u16) }, + { &BG2X_L , sizeof(u16) }, + { &BG2X_H , sizeof(u16) }, + { &BG2Y_L , sizeof(u16) }, + { &BG2Y_H , sizeof(u16) }, + { &BG3PA , sizeof(u16) }, + { &BG3PB , sizeof(u16) }, + { &BG3PC , sizeof(u16) }, + { &BG3PD , sizeof(u16) }, + { &BG3X_L , sizeof(u16) }, + { &BG3X_H , sizeof(u16) }, + { &BG3Y_L , sizeof(u16) }, + { &BG3Y_H , sizeof(u16) }, + { &WIN0H , sizeof(u16) }, + { &WIN1H , sizeof(u16) }, + { &WIN0V , sizeof(u16) }, + { &WIN1V , sizeof(u16) }, + { &WININ , sizeof(u16) }, + { &WINOUT , sizeof(u16) }, + { &MOSAIC , sizeof(u16) }, + { &BLDMOD , sizeof(u16) }, + { &COLEV , sizeof(u16) }, + { &COLY , sizeof(u16) }, + { &DM0SAD_L , sizeof(u16) }, + { &DM0SAD_H , sizeof(u16) }, + { &DM0DAD_L , sizeof(u16) }, + { &DM0DAD_H , sizeof(u16) }, + { &DM0CNT_L , sizeof(u16) }, + { &DM0CNT_H , sizeof(u16) }, + { &DM1SAD_L , sizeof(u16) }, + { &DM1SAD_H , sizeof(u16) }, + { &DM1DAD_L , sizeof(u16) }, + { &DM1DAD_H , sizeof(u16) }, + { &DM1CNT_L , sizeof(u16) }, + { &DM1CNT_H , sizeof(u16) }, + { &DM2SAD_L , sizeof(u16) }, + { &DM2SAD_H , sizeof(u16) }, + { &DM2DAD_L , sizeof(u16) }, + { &DM2DAD_H , sizeof(u16) }, + { &DM2CNT_L , sizeof(u16) }, + { &DM2CNT_H , sizeof(u16) }, + { &DM3SAD_L , sizeof(u16) }, + { &DM3SAD_H , sizeof(u16) }, + { &DM3DAD_L , sizeof(u16) }, + { &DM3DAD_H , sizeof(u16) }, + { &DM3CNT_L , sizeof(u16) }, + { &DM3CNT_H , sizeof(u16) }, + { &TM0D , sizeof(u16) }, + { &TM0CNT , sizeof(u16) }, + { &TM1D , sizeof(u16) }, + { &TM1CNT , sizeof(u16) }, + { &TM2D , sizeof(u16) }, + { &TM2CNT , sizeof(u16) }, + { &TM3D , sizeof(u16) }, + { &TM3CNT , sizeof(u16) }, + { &P1 , sizeof(u16) }, + { &IE , sizeof(u16) }, + { &IF , sizeof(u16) }, + { &IME , sizeof(u16) }, + { &holdState, sizeof(bool) }, + { &holdType, sizeof(int) }, + { &lcdTicks, sizeof(int) }, + { &timer0On , sizeof(bool) }, + { &timer0Ticks , sizeof(int) }, + { &timer0Reload , sizeof(int) }, + { &timer0ClockReload , sizeof(int) }, + { &timer1On , sizeof(bool) }, + { &timer1Ticks , sizeof(int) }, + { &timer1Reload , sizeof(int) }, + { &timer1ClockReload , sizeof(int) }, + { &timer2On , sizeof(bool) }, + { &timer2Ticks , sizeof(int) }, + { &timer2Reload , sizeof(int) }, + { &timer2ClockReload , sizeof(int) }, + { &timer3On , sizeof(bool) }, + { &timer3Ticks , sizeof(int) }, + { &timer3Reload , sizeof(int) }, + { &timer3ClockReload , sizeof(int) }, + { &dma0Source , sizeof(u32) }, + { &dma0Dest , sizeof(u32) }, + { &dma1Source , sizeof(u32) }, + { &dma1Dest , sizeof(u32) }, + { &dma2Source , sizeof(u32) }, + { &dma2Dest , sizeof(u32) }, + { &dma3Source , sizeof(u32) }, + { &dma3Dest , sizeof(u32) }, + { &fxOn, sizeof(bool) }, + { &windowOn, sizeof(bool) }, + { &N_FLAG , sizeof(bool) }, + { &C_FLAG , sizeof(bool) }, + { &Z_FLAG , sizeof(bool) }, + { &V_FLAG , sizeof(bool) }, + { &armState , sizeof(bool) }, + { &armIrqEnable , sizeof(bool) }, + { &armNextPC , sizeof(u32) }, + { &armMode , sizeof(int) }, + { &saveType , sizeof(int) }, + { NULL, 0 } +}; + +static int romSize = 0x2000000; + +#ifdef PROFILING +void cpuProfil(profile_segment *seg) +{ + profilSegment = seg; +} + +void cpuEnableProfiling(int hz) +{ + if(hz == 0) + hz = 100; + profilingTicks = profilingTicksReload = 16777216 / hz; + profSetHertz(hz); +} +#endif + + +inline int CPUUpdateTicks() +{ + int cpuLoopTicks = lcdTicks; + + if(soundTicks < cpuLoopTicks) + cpuLoopTicks = soundTicks; + + if(timer0On && (timer0Ticks < cpuLoopTicks)) { + cpuLoopTicks = timer0Ticks; + } + if(timer1On && !(TM1CNT & 4) && (timer1Ticks < cpuLoopTicks)) { + cpuLoopTicks = timer1Ticks; + } + if(timer2On && !(TM2CNT & 4) && (timer2Ticks < cpuLoopTicks)) { + cpuLoopTicks = timer2Ticks; + } + if(timer3On && !(TM3CNT & 4) && (timer3Ticks < cpuLoopTicks)) { + cpuLoopTicks = timer3Ticks; + } +#ifdef PROFILING + if(profilingTicksReload != 0) { + if(profilingTicks < cpuLoopTicks) { + cpuLoopTicks = profilingTicks; + } + } +#endif + + if (SWITicks) { + if (SWITicks < cpuLoopTicks) + cpuLoopTicks = SWITicks; + } + + if (IRQTicks) { + if (IRQTicks < cpuLoopTicks) + cpuLoopTicks = IRQTicks; + } + + return cpuLoopTicks; +} + +void CPUUpdateWindow0() +{ + int x00 = WIN0H>>8; + int x01 = WIN0H & 255; + + if(x00 <= x01) { + for(int i = 0; i < 240; i++) { + gfxInWin0[i] = (i >= x00 && i < x01); + } + } else { + for(int i = 0; i < 240; i++) { + gfxInWin0[i] = (i >= x00 || i < x01); + } + } +} + +void CPUUpdateWindow1() +{ + int x00 = WIN1H>>8; + int x01 = WIN1H & 255; + + if(x00 <= x01) { + for(int i = 0; i < 240; i++) { + gfxInWin1[i] = (i >= x00 && i < x01); + } + } else { + for(int i = 0; i < 240; i++) { + gfxInWin1[i] = (i >= x00 || i < x01); + } + } +} + +extern u32 line0[240]; +extern u32 line1[240]; +extern u32 line2[240]; +extern u32 line3[240]; + +#define CLEAR_ARRAY(a) \ + {\ + u32 *array = (a);\ + for(int i = 0; i < 240; i++) {\ + *array++ = 0x80000000;\ + }\ + }\ + +void CPUUpdateRenderBuffers(bool force) +{ + if(!(layerEnable & 0x0100) || force) { + CLEAR_ARRAY(line0); + } + if(!(layerEnable & 0x0200) || force) { + CLEAR_ARRAY(line1); + } + if(!(layerEnable & 0x0400) || force) { + CLEAR_ARRAY(line2); + } + if(!(layerEnable & 0x0800) || force) { + CLEAR_ARRAY(line3); + } +} + +static bool CPUWriteState(gzFile gzFile) +{ + utilWriteInt(gzFile, SAVE_GAME_VERSION); + + utilGzWrite(gzFile, &rom[0xa0], 16); + + utilWriteInt(gzFile, useBios); + + utilGzWrite(gzFile, ®[0], sizeof(reg)); + + utilWriteData(gzFile, saveGameStruct); + + // new to version 0.7.1 + utilWriteInt(gzFile, stopState); + // new to version 0.8 + utilWriteInt(gzFile, IRQTicks); + + utilGzWrite(gzFile, internalRAM, 0x8000); + utilGzWrite(gzFile, paletteRAM, 0x400); + utilGzWrite(gzFile, workRAM, 0x40000); + utilGzWrite(gzFile, vram, 0x20000); + utilGzWrite(gzFile, oam, 0x400); + utilGzWrite(gzFile, pix, 4*241*162); + utilGzWrite(gzFile, ioMem, 0x400); + + eepromSaveGame(gzFile); + flashSaveGame(gzFile); + soundSaveGame(gzFile); + + cheatsSaveGame(gzFile); + + // version 1.5 + rtcSaveGame(gzFile); + + return true; +} + +bool CPUWriteState(const char *file) +{ + gzFile gzFile = utilGzOpen(file, "wb"); + + if(gzFile == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), file); + return false; + } + + bool res = CPUWriteState(gzFile); + + utilGzClose(gzFile); + + return res; +} + +bool CPUWriteMemState(char *memory, int available) +{ + gzFile gzFile = utilMemGzOpen(memory, available, "w"); + + if(gzFile == NULL) { + return false; + } + + bool res = CPUWriteState(gzFile); + + long pos = utilGzMemTell(gzFile)+8; + + if(pos >= (available)) + res = false; + + utilGzClose(gzFile); + + return res; +} + +static bool CPUReadState(gzFile gzFile) +{ + int version = utilReadInt(gzFile); + + if(version > SAVE_GAME_VERSION || version < SAVE_GAME_VERSION_1) { + systemMessage(MSG_UNSUPPORTED_VBA_SGM, + N_("Unsupported VisualBoyAdvance save game version %d"), + version); + return false; + } + + u8 romname[17]; + + utilGzRead(gzFile, romname, 16); + + if(memcmp(&rom[0xa0], romname, 16) != 0) { + romname[16]=0; + for(int i = 0; i < 16; i++) + if(romname[i] < 32) + romname[i] = 32; + systemMessage(MSG_CANNOT_LOAD_SGM, N_("Cannot load save game for %s"), romname); + return false; + } + + bool ub = utilReadInt(gzFile) ? true : false; + + if(ub != useBios) { + if(useBios) + systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS, + N_("Save game is not using the BIOS files")); + else + systemMessage(MSG_SAVE_GAME_USING_BIOS, + N_("Save game is using the BIOS file")); + return false; + } + + utilGzRead(gzFile, ®[0], sizeof(reg)); + + utilReadData(gzFile, saveGameStruct); + + if(version < SAVE_GAME_VERSION_3) + stopState = false; + else + stopState = utilReadInt(gzFile) ? true : false; + + if(version < SAVE_GAME_VERSION_4) + { + IRQTicks = 0; + intState = false; + } + else + { + IRQTicks = utilReadInt(gzFile); + if (IRQTicks>0) + intState = true; + else + { + intState = false; + IRQTicks = 0; + } + } + + utilGzRead(gzFile, internalRAM, 0x8000); + utilGzRead(gzFile, paletteRAM, 0x400); + utilGzRead(gzFile, workRAM, 0x40000); + utilGzRead(gzFile, vram, 0x20000); + utilGzRead(gzFile, oam, 0x400); + if(version < SAVE_GAME_VERSION_6) + utilGzRead(gzFile, pix, 4*240*160); + else + utilGzRead(gzFile, pix, 4*241*162); + utilGzRead(gzFile, ioMem, 0x400); + + eepromReadGame(gzFile, version); + flashReadGame(gzFile, version); + soundReadGame(gzFile, version); + + if(version > SAVE_GAME_VERSION_1) { + cheatsReadGame(gzFile, version); + } + if(version > SAVE_GAME_VERSION_6) { + rtcReadGame(gzFile); + } + + if(version <= SAVE_GAME_VERSION_7) { + u32 temp; +#define SWAP(a,b,c) \ + temp = (a);\ + (a) = (b)<<16|(c);\ + (b) = (temp) >> 16;\ + (c) = (temp) & 0xFFFF; + + SWAP(dma0Source, DM0SAD_H, DM0SAD_L); + SWAP(dma0Dest, DM0DAD_H, DM0DAD_L); + SWAP(dma1Source, DM1SAD_H, DM1SAD_L); + SWAP(dma1Dest, DM1DAD_H, DM1DAD_L); + SWAP(dma2Source, DM2SAD_H, DM2SAD_L); + SWAP(dma2Dest, DM2DAD_H, DM2DAD_L); + SWAP(dma3Source, DM3SAD_H, DM3SAD_L); + SWAP(dma3Dest, DM3DAD_H, DM3DAD_L); + } + + if(version <= SAVE_GAME_VERSION_8) { + timer0ClockReload = TIMER_TICKS[TM0CNT & 3]; + timer1ClockReload = TIMER_TICKS[TM1CNT & 3]; + timer2ClockReload = TIMER_TICKS[TM2CNT & 3]; + timer3ClockReload = TIMER_TICKS[TM3CNT & 3]; + + timer0Ticks = ((0x10000 - TM0D) << timer0ClockReload) - timer0Ticks; + timer1Ticks = ((0x10000 - TM1D) << timer1ClockReload) - timer1Ticks; + timer2Ticks = ((0x10000 - TM2D) << timer2ClockReload) - timer2Ticks; + timer3Ticks = ((0x10000 - TM3D) << timer3ClockReload) - timer3Ticks; + interp_rate(); + } + + // set pointers! + layerEnable = layerSettings & DISPCNT; + + CPUUpdateRender(); + CPUUpdateRenderBuffers(true); + CPUUpdateWindow0(); + CPUUpdateWindow1(); + gbaSaveType = 0; + switch(saveType) { + case 0: + cpuSaveGameFunc = flashSaveDecide; + break; + case 1: + cpuSaveGameFunc = sramWrite; + gbaSaveType = 1; + break; + case 2: + cpuSaveGameFunc = flashWrite; + gbaSaveType = 2; + break; + case 3: + break; + case 5: + gbaSaveType = 5; + break; + default: + systemMessage(MSG_UNSUPPORTED_SAVE_TYPE, + N_("Unsupported save type %d"), saveType); + break; + } + if(eepromInUse) + gbaSaveType = 3; + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + if(armState) { + ARM_PREFETCH; + } else { + THUMB_PREFETCH; + } + + CPUUpdateRegister(0x204, CPUReadHalfWordQuick(0x4000204)); + + return true; +} + +bool CPUReadMemState(char *memory, int available) +{ + gzFile gzFile = utilMemGzOpen(memory, available, "r"); + + bool res = CPUReadState(gzFile); + + utilGzClose(gzFile); + + return res; +} + +bool CPUReadState(const char * file) +{ + gzFile gzFile = utilGzOpen(file, "rb"); + + if(gzFile == NULL) + return false; + + bool res = CPUReadState(gzFile); + + utilGzClose(gzFile); + + return res; +} + +bool CPUExportEepromFile(const char *fileName) +{ + if(eepromInUse) { + FILE *file = fopen(fileName, "wb"); + + if(!file) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), + fileName); + return false; + } + + for(int i = 0; i < eepromSize;) { + for(int j = 0; j < 8; j++) { + if(fwrite(&eepromData[i+7-j], 1, 1, file) != 1) { + fclose(file); + return false; + } + } + i += 8; + } + fclose(file); + } + return true; +} + +bool CPUWriteBatteryFile(const char *fileName) +{ + if(gbaSaveType == 0) { + if(eepromInUse) + gbaSaveType = 3; + else switch(saveType) { + case 1: + gbaSaveType = 1; + break; + case 2: + gbaSaveType = 2; + break; + } + } + + if((gbaSaveType) && (gbaSaveType!=5)) { + FILE *file = fopen(fileName, "wb"); + + if(!file) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), + fileName); + return false; + } + + // only save if Flash/Sram in use or EEprom in use + if(gbaSaveType != 3) { + if(gbaSaveType == 2) { + if(fwrite(flashSaveMemory, 1, flashSize, file) != (size_t)flashSize) { + fclose(file); + return false; + } + } else { + if(fwrite(flashSaveMemory, 1, 0x10000, file) != 0x10000) { + fclose(file); + return false; + } + } + } else { + if(fwrite(eepromData, 1, eepromSize, file) != (size_t)eepromSize) { + fclose(file); + return false; + } + } + fclose(file); + } + return true; +} + +bool CPUReadGSASnapshot(const char *fileName) +{ + int i; + FILE *file = fopen(fileName, "rb"); + + if(!file) { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); + return false; + } + + // check file size to know what we should read + fseek(file, 0, SEEK_END); + + // long size = ftell(file); + fseek(file, 0x0, SEEK_SET); + fread(&i, 1, 4, file); + fseek(file, i, SEEK_CUR); // Skip SharkPortSave + fseek(file, 4, SEEK_CUR); // skip some sort of flag + fread(&i, 1, 4, file); // name length + fseek(file, i, SEEK_CUR); // skip name + fread(&i, 1, 4, file); // desc length + fseek(file, i, SEEK_CUR); // skip desc + fread(&i, 1, 4, file); // notes length + fseek(file, i, SEEK_CUR); // skip notes + int saveSize; + fread(&saveSize, 1, 4, file); // read length + saveSize -= 0x1c; // remove header size + char buffer[17]; + char buffer2[17]; + fread(buffer, 1, 16, file); + buffer[16] = 0; + for(i = 0; i < 16; i++) + if(buffer[i] < 32) + buffer[i] = 32; + memcpy(buffer2, &rom[0xa0], 16); + buffer2[16] = 0; + for(i = 0; i < 16; i++) + if(buffer2[i] < 32) + buffer2[i] = 32; + if(memcmp(buffer, buffer2, 16)) { + systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, + N_("Cannot import snapshot for %s. Current game is %s"), + buffer, + buffer2); + fclose(file); + return false; + } + fseek(file, 12, SEEK_CUR); // skip some flags + if(saveSize >= 65536) { + if(fread(flashSaveMemory, 1, saveSize, file) != (size_t)saveSize) { + fclose(file); + return false; + } + } else { + systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, + N_("Unsupported snapshot file %s"), + fileName); + fclose(file); + return false; + } + fclose(file); + CPUReset(); + return true; +} + +bool CPUWriteGSASnapshot(const char *fileName, + const char *title, + const char *desc, + const char *notes) +{ + FILE *file = fopen(fileName, "wb"); + + if(!file) { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); + return false; + } + + u8 buffer[17]; + + utilPutDword(buffer, 0x0d); // SharkPortSave length + fwrite(buffer, 1, 4, file); + fwrite("SharkPortSave", 1, 0x0d, file); + utilPutDword(buffer, 0x000f0000); + fwrite(buffer, 1, 4, file); // save type 0x000f0000 = GBA save + utilPutDword(buffer, (u32)strlen(title)); + fwrite(buffer, 1, 4, file); // title length + fwrite(title, 1, strlen(title), file); + utilPutDword(buffer, (u32)strlen(desc)); + fwrite(buffer, 1, 4, file); // desc length + fwrite(desc, 1, strlen(desc), file); + utilPutDword(buffer, (u32)strlen(notes)); + fwrite(buffer, 1, 4, file); // notes length + fwrite(notes, 1, strlen(notes), file); + int saveSize = 0x10000; + if(gbaSaveType == 2) + saveSize = flashSize; + int totalSize = saveSize + 0x1c; + + utilPutDword(buffer, totalSize); // length of remainder of save - CRC + fwrite(buffer, 1, 4, file); + + char temp[0x2001c]; + memset(temp, 0, 28); + memcpy(temp, &rom[0xa0], 16); // copy internal name + temp[0x10] = rom[0xbe]; // reserved area (old checksum) + temp[0x11] = rom[0xbf]; // reserved area (old checksum) + temp[0x12] = rom[0xbd]; // complement check + temp[0x13] = rom[0xb0]; // maker + temp[0x14] = 1; // 1 save ? + memcpy(&temp[0x1c], flashSaveMemory, saveSize); // copy save + fwrite(temp, 1, totalSize, file); // write save + header + u32 crc = 0; + + for(int i = 0; i < totalSize; i++) { + crc += ((u32)temp[i] << (crc % 0x18)); + } + + utilPutDword(buffer, crc); + fwrite(buffer, 1, 4, file); // CRC? + + fclose(file); + return true; +} + +bool CPUImportEepromFile(const char *fileName) +{ + FILE *file = fopen(fileName, "rb"); + + if(!file) + return false; + + // check file size to know what we should read + fseek(file, 0, SEEK_END); + + long size = ftell(file); + fseek(file, 0, SEEK_SET); + if(size == 512 || size == 0x2000) { + if(fread(eepromData, 1, size, file) != (size_t)size) { + fclose(file); + return false; + } + for(int i = 0; i < size;) { + u8 tmp = eepromData[i]; + eepromData[i] = eepromData[7-i]; + eepromData[7-i] = tmp; + i++; + tmp = eepromData[i]; + eepromData[i] = eepromData[7-i]; + eepromData[7-i] = tmp; + i++; + tmp = eepromData[i]; + eepromData[i] = eepromData[7-i]; + eepromData[7-i] = tmp; + i++; + tmp = eepromData[i]; + eepromData[i] = eepromData[7-i]; + eepromData[7-i] = tmp; + i++; + i += 4; + } + } else + return false; + fclose(file); + return true; +} + +bool CPUReadBatteryFile(const char *fileName) +{ + FILE *file = fopen(fileName, "rb"); + + if(!file) + return false; + + // check file size to know what we should read + fseek(file, 0, SEEK_END); + + long size = ftell(file); + fseek(file, 0, SEEK_SET); + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + if(size == 512 || size == 0x2000) { + if(fread(eepromData, 1, size, file) != (size_t)size) { + fclose(file); + return false; + } + } else { + if(size == 0x20000) { + if(fread(flashSaveMemory, 1, 0x20000, file) != 0x20000) { + fclose(file); + return false; + } + flashSetSize(0x20000); + } else { + if(fread(flashSaveMemory, 1, 0x10000, file) != 0x10000) { + fclose(file); + return false; + } + flashSetSize(0x10000); + } + } + fclose(file); + return true; +} + +bool CPUWritePNGFile(const char *fileName) +{ + return utilWritePNGFile(fileName, 240, 160, pix); +} + +bool CPUWriteBMPFile(const char *fileName) +{ + return utilWriteBMPFile(fileName, 240, 160, pix); +} + +bool CPUIsZipFile(const char * file) +{ + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".zip") == 0) + return true; + } + } + + return false; +} + +bool CPUIsGBAImage(const char * file) +{ + cpuIsMultiBoot = false; + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".gba") == 0) + return true; + if(_stricmp(p, ".agb") == 0) + return true; + if(_stricmp(p, ".bin") == 0) + return true; + if(_stricmp(p, ".elf") == 0) + return true; + if(_stricmp(p, ".mb") == 0) { + cpuIsMultiBoot = true; + return true; + } + } + } + + return false; +} + +bool CPUIsGBABios(const char * file) +{ + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".gba") == 0) + return true; + if(_stricmp(p, ".agb") == 0) + return true; + if(_stricmp(p, ".bin") == 0) + return true; + if(_stricmp(p, ".bios") == 0) + return true; + if(_stricmp(p, ".rom") == 0) + return true; + } + } + + return false; +} + +bool CPUIsELF(const char *file) +{ + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".elf") == 0) + return true; + } + } + return false; +} + +void CPUCleanUp() +{ +#ifdef PROFILING + if(profilingTicksReload) { + profCleanup(); + } +#endif + + if(rom != NULL) { + free(rom); + rom = NULL; + } + + if(vram != NULL) { + free(vram); + vram = NULL; + } + + if(paletteRAM != NULL) { + free(paletteRAM); + paletteRAM = NULL; + } + + if(internalRAM != NULL) { + free(internalRAM); + internalRAM = NULL; + } + + if(workRAM != NULL) { + free(workRAM); + workRAM = NULL; + } + + if(bios != NULL) { + free(bios); + bios = NULL; + } + + if(pix != NULL) { + free(pix); + pix = NULL; + } + + if(oam != NULL) { + free(oam); + oam = NULL; + } + + if(ioMem != NULL) { + free(ioMem); + ioMem = NULL; + } + + elfCleanUp(); + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + emulating = 0; +} + +int CPULoadRom(const char *szFile) +{ + romSize = 0x2000000; + if(rom != NULL) { + CPUCleanUp(); + } + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + rom = (u8 *)malloc(0x2000000); + if(rom == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "ROM"); + return 0; + } + workRAM = (u8 *)calloc(1, 0x40000); + if(workRAM == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "WRAM"); + return 0; + } + + u8 *whereToLoad = cpuIsMultiBoot ? workRAM : rom; + + if(CPUIsELF(szFile)) { + FILE *f = fopen(szFile, "rb"); + if(!f) { + systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), + szFile); + free(rom); + rom = NULL; + free(workRAM); + workRAM = NULL; + return 0; + } + bool res = elfRead(szFile, romSize, f); + if(!res || romSize == 0) { + free(rom); + rom = NULL; + free(workRAM); + workRAM = NULL; + elfCleanUp(); + return 0; + } + } else if(!utilLoad(szFile, + utilIsGBAImage, + whereToLoad, + romSize)) { + free(rom); + rom = NULL; + free(workRAM); + workRAM = NULL; + return 0; + } + + u16 *temp = (u16 *)(rom+((romSize+1)&~1)); + int i; + for(i = (romSize+1)&~1; i < 0x2000000; i+=2) { + WRITE16LE(temp, (i >> 1) & 0xFFFF); + temp++; + } + + bios = (u8 *)calloc(1,0x4000); + if(bios == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "BIOS"); + CPUCleanUp(); + return 0; + } + internalRAM = (u8 *)calloc(1,0x8000); + if(internalRAM == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "IRAM"); + CPUCleanUp(); + return 0; + } + paletteRAM = (u8 *)calloc(1,0x400); + if(paletteRAM == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "PRAM"); + CPUCleanUp(); + return 0; + } + vram = (u8 *)calloc(1, 0x20000); + if(vram == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "VRAM"); + CPUCleanUp(); + return 0; + } + oam = (u8 *)calloc(1, 0x400); + if(oam == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "OAM"); + CPUCleanUp(); + return 0; + } + pix = (u8 *)calloc(1, 4 * 241 * 162); + if(pix == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "PIX"); + CPUCleanUp(); + return 0; + } + ioMem = (u8 *)calloc(1, 0x400); + if(ioMem == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "IO"); + CPUCleanUp(); + return 0; + } + + flashInit(); + eepromInit(); + + CPUUpdateRenderBuffers(true); + + return romSize; +} + +void doMirroring (bool b) +{ + u32 mirroredRomSize = (((romSize)>>20) & 0x3F)<<20; + u32 mirroredRomAddress = romSize; + if ((mirroredRomSize <=0x800000) && (b)) + { + mirroredRomAddress = mirroredRomSize; + if (mirroredRomSize==0) + mirroredRomSize=0x100000; + while (mirroredRomAddress<0x01000000) + { + memcpy ((u16 *)(rom+mirroredRomAddress), (u16 *)(rom), mirroredRomSize); + mirroredRomAddress+=mirroredRomSize; + } + } +} + +void CPUUpdateRender() +{ + switch(DISPCNT & 7) { + case 0: + if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || + cpuDisableSfx) + renderLine = mode0RenderLine; + else if(fxOn && !windowOn && !(layerEnable & 0x8000)) + renderLine = mode0RenderLineNoWindow; + else + renderLine = mode0RenderLineAll; + break; + case 1: + if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || + cpuDisableSfx) + renderLine = mode1RenderLine; + else if(fxOn && !windowOn && !(layerEnable & 0x8000)) + renderLine = mode1RenderLineNoWindow; + else + renderLine = mode1RenderLineAll; + break; + case 2: + if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || + cpuDisableSfx) + renderLine = mode2RenderLine; + else if(fxOn && !windowOn && !(layerEnable & 0x8000)) + renderLine = mode2RenderLineNoWindow; + else + renderLine = mode2RenderLineAll; + break; + case 3: + if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || + cpuDisableSfx) + renderLine = mode3RenderLine; + else if(fxOn && !windowOn && !(layerEnable & 0x8000)) + renderLine = mode3RenderLineNoWindow; + else + renderLine = mode3RenderLineAll; + break; + case 4: + if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || + cpuDisableSfx) + renderLine = mode4RenderLine; + else if(fxOn && !windowOn && !(layerEnable & 0x8000)) + renderLine = mode4RenderLineNoWindow; + else + renderLine = mode4RenderLineAll; + break; + case 5: + if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || + cpuDisableSfx) + renderLine = mode5RenderLine; + else if(fxOn && !windowOn && !(layerEnable & 0x8000)) + renderLine = mode5RenderLineNoWindow; + else + renderLine = mode5RenderLineAll; + default: + break; + } +} + +void CPUUpdateCPSR() +{ + u32 CPSR = reg[16].I & 0x40; + if(N_FLAG) + CPSR |= 0x80000000; + if(Z_FLAG) + CPSR |= 0x40000000; + if(C_FLAG) + CPSR |= 0x20000000; + if(V_FLAG) + CPSR |= 0x10000000; + if(!armState) + CPSR |= 0x00000020; + if(!armIrqEnable) + CPSR |= 0x80; + CPSR |= (armMode & 0x1F); + reg[16].I = CPSR; +} + +void CPUUpdateFlags(bool breakLoop) +{ + u32 CPSR = reg[16].I; + + N_FLAG = (CPSR & 0x80000000) ? true: false; + Z_FLAG = (CPSR & 0x40000000) ? true: false; + C_FLAG = (CPSR & 0x20000000) ? true: false; + V_FLAG = (CPSR & 0x10000000) ? true: false; + armState = (CPSR & 0x20) ? false : true; + armIrqEnable = (CPSR & 0x80) ? false : true; + if(breakLoop) { + if (armIrqEnable && (IF & IE) && (IME & 1)) + cpuNextEvent = cpuTotalTicks; + } +} + +void CPUUpdateFlags() +{ + CPUUpdateFlags(true); +} + +#ifdef WORDS_BIGENDIAN +static void CPUSwap(volatile u32 *a, volatile u32 *b) +{ + volatile u32 c = *b; + *b = *a; + *a = c; +} +#else +static void CPUSwap(u32 *a, u32 *b) +{ + u32 c = *b; + *b = *a; + *a = c; +} +#endif + +void CPUSwitchMode(int mode, bool saveState, bool breakLoop) +{ + // if(armMode == mode) + // return; + + CPUUpdateCPSR(); + + switch(armMode) { + case 0x10: + case 0x1F: + reg[R13_USR].I = reg[13].I; + reg[R14_USR].I = reg[14].I; + reg[17].I = reg[16].I; + break; + case 0x11: + CPUSwap(®[R8_FIQ].I, ®[8].I); + CPUSwap(®[R9_FIQ].I, ®[9].I); + CPUSwap(®[R10_FIQ].I, ®[10].I); + CPUSwap(®[R11_FIQ].I, ®[11].I); + CPUSwap(®[R12_FIQ].I, ®[12].I); + reg[R13_FIQ].I = reg[13].I; + reg[R14_FIQ].I = reg[14].I; + reg[SPSR_FIQ].I = reg[17].I; + break; + case 0x12: + reg[R13_IRQ].I = reg[13].I; + reg[R14_IRQ].I = reg[14].I; + reg[SPSR_IRQ].I = reg[17].I; + break; + case 0x13: + reg[R13_SVC].I = reg[13].I; + reg[R14_SVC].I = reg[14].I; + reg[SPSR_SVC].I = reg[17].I; + break; + case 0x17: + reg[R13_ABT].I = reg[13].I; + reg[R14_ABT].I = reg[14].I; + reg[SPSR_ABT].I = reg[17].I; + break; + case 0x1b: + reg[R13_UND].I = reg[13].I; + reg[R14_UND].I = reg[14].I; + reg[SPSR_UND].I = reg[17].I; + break; + } + + u32 CPSR = reg[16].I; + u32 SPSR = reg[17].I; + + switch(mode) { + case 0x10: + case 0x1F: + reg[13].I = reg[R13_USR].I; + reg[14].I = reg[R14_USR].I; + reg[16].I = SPSR; + break; + case 0x11: + CPUSwap(®[8].I, ®[R8_FIQ].I); + CPUSwap(®[9].I, ®[R9_FIQ].I); + CPUSwap(®[10].I, ®[R10_FIQ].I); + CPUSwap(®[11].I, ®[R11_FIQ].I); + CPUSwap(®[12].I, ®[R12_FIQ].I); + reg[13].I = reg[R13_FIQ].I; + reg[14].I = reg[R14_FIQ].I; + if(saveState) + reg[17].I = CPSR; + else + reg[17].I = reg[SPSR_FIQ].I; + break; + case 0x12: + reg[13].I = reg[R13_IRQ].I; + reg[14].I = reg[R14_IRQ].I; + reg[16].I = SPSR; + if(saveState) + reg[17].I = CPSR; + else + reg[17].I = reg[SPSR_IRQ].I; + break; + case 0x13: + reg[13].I = reg[R13_SVC].I; + reg[14].I = reg[R14_SVC].I; + reg[16].I = SPSR; + if(saveState) + reg[17].I = CPSR; + else + reg[17].I = reg[SPSR_SVC].I; + break; + case 0x17: + reg[13].I = reg[R13_ABT].I; + reg[14].I = reg[R14_ABT].I; + reg[16].I = SPSR; + if(saveState) + reg[17].I = CPSR; + else + reg[17].I = reg[SPSR_ABT].I; + break; + case 0x1b: + reg[13].I = reg[R13_UND].I; + reg[14].I = reg[R14_UND].I; + reg[16].I = SPSR; + if(saveState) + reg[17].I = CPSR; + else + reg[17].I = reg[SPSR_UND].I; + break; + default: + systemMessage(MSG_UNSUPPORTED_ARM_MODE, N_("Unsupported ARM mode %02x"), mode); + break; + } + armMode = mode; + CPUUpdateFlags(breakLoop); + CPUUpdateCPSR(); +} + +void CPUSwitchMode(int mode, bool saveState) +{ + CPUSwitchMode(mode, saveState, true); +} + +void CPUUndefinedException() +{ + u32 PC = reg[15].I; + bool savedArmState = armState; + CPUSwitchMode(0x1b, true, false); + reg[14].I = PC - (savedArmState ? 4 : 2); + reg[15].I = 0x04; + armState = true; + armIrqEnable = false; + armNextPC = 0x04; + ARM_PREFETCH; + reg[15].I += 4; +} + +void CPUSoftwareInterrupt() +{ + u32 PC = reg[15].I; + bool savedArmState = armState; + CPUSwitchMode(0x13, true, false); + reg[14].I = PC - (savedArmState ? 4 : 2); + reg[15].I = 0x08; + armState = true; + armIrqEnable = false; + armNextPC = 0x08; + ARM_PREFETCH; + reg[15].I += 4; +} + +void CPUSoftwareInterrupt(int comment) +{ + static bool disableMessage = false; + if(armState) comment >>= 16; +#ifdef BKPT_SUPPORT + if(comment == 0xff) { + dbgOutput(NULL, reg[0].I); + return; + } +#endif +#ifdef PROFILING + if(comment == 0xfe) { + profStartup(reg[0].I, reg[1].I); + return; + } + if(comment == 0xfd) { + profControl(reg[0].I); + return; + } + if(comment == 0xfc) { + profCleanup(); + return; + } + if(comment == 0xfb) { + profCount(); + return; + } +#endif + if(comment == 0xfa) { + agbPrintFlush(); + return; + } +#ifdef SDL + if(comment == 0xf9) { + emulating = 0; + cpuNextEvent = cpuTotalTicks; + cpuBreakLoop = true; + return; + } +#endif + if(useBios) { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, + armState ? armNextPC - 4: armNextPC -2, + reg[0].I, + reg[1].I, + reg[2].I, + VCOUNT); + } +#endif + CPUSoftwareInterrupt(); + return; + } + // This would be correct, but it causes problems if uncommented + // else { + // biosProtected = 0xe3a02004; + // } + + switch(comment) { + case 0x00: + BIOS_SoftReset(); + ARM_PREFETCH; + break; + case 0x01: + BIOS_RegisterRamReset(); + break; + case 0x02: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("Halt: (VCOUNT = %2d)\n", + VCOUNT); + } +#endif + holdState = true; + holdType = -1; + cpuNextEvent = cpuTotalTicks; + break; + case 0x03: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("Stop: (VCOUNT = %2d)\n", + VCOUNT); + } +#endif + holdState = true; + holdType = -1; + stopState = true; + cpuNextEvent = cpuTotalTicks; + break; + case 0x04: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n", + reg[0].I, + reg[1].I, + VCOUNT); + } +#endif + CPUSoftwareInterrupt(); + break; + case 0x05: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("VBlankIntrWait: (VCOUNT = %2d)\n", + VCOUNT); + } +#endif + CPUSoftwareInterrupt(); + break; + case 0x06: + CPUSoftwareInterrupt(); + break; + case 0x07: + CPUSoftwareInterrupt(); + break; + case 0x08: + BIOS_Sqrt(); + break; + case 0x09: + BIOS_ArcTan(); + break; + case 0x0A: + BIOS_ArcTan2(); + break; + case 0x0B: + { + int len = (reg[2].I & 0x1FFFFF) >>1; + if (!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + len) & 0xe000000) == 0)) + { + if ((reg[2].I >> 24) & 1) + { + if ((reg[2].I >> 26) & 1) + SWITicks = (7 + memoryWait32[(reg[1].I>>24) & 0xF]) * (len>>1); + else + SWITicks = (8 + memoryWait[(reg[1].I>>24) & 0xF]) * (len); + } + else + { + if ((reg[2].I >> 26) & 1) + SWITicks = (10 + memoryWait32[(reg[0].I>>24) & 0xF] + + memoryWait32[(reg[1].I>>24) & 0xF]) * (len>>1); + else + SWITicks = (11 + memoryWait[(reg[0].I>>24) & 0xF] + + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + } + } + BIOS_CpuSet(); + break; + case 0x0C: + { + int len = (reg[2].I & 0x1FFFFF) >>5; + if (!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + len) & 0xe000000) == 0)) + { + if ((reg[2].I >> 24) & 1) + SWITicks = (6 + memoryWait32[(reg[1].I>>24) & 0xF] + + 7 * (memoryWaitSeq32[(reg[1].I>>24) & 0xF] + 1)) * len; + else + SWITicks = (9 + memoryWait32[(reg[0].I>>24) & 0xF] + + memoryWait32[(reg[1].I>>24) & 0xF] + + 7 * (memoryWaitSeq32[(reg[0].I>>24) & 0xF] + + memoryWaitSeq32[(reg[1].I>>24) & 0xF] + 2)) * len; + } + } + BIOS_CpuFastSet(); + break; + case 0x0D: + BIOS_GetBiosChecksum(); + break; + case 0x0E: + BIOS_BgAffineSet(); + break; + case 0x0F: + BIOS_ObjAffineSet(); + break; + case 0x10: + { + int len = CPUReadHalfWord(reg[2].I); + if (!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + len) & 0xe000000) == 0)) + SWITicks = (32 + memoryWait[(reg[0].I>>24) & 0xF]) * len; + } + BIOS_BitUnPack(); + break; + case 0x11: + { + u32 len = CPUReadMemory(reg[0].I) >> 8; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (9 + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_LZ77UnCompWram(); + break; + case 0x12: + { + u32 len = CPUReadMemory(reg[0].I) >> 8; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (19 + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_LZ77UnCompVram(); + break; + case 0x13: + { + u32 len = CPUReadMemory(reg[0].I) >> 8; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (29 + (memoryWait[(reg[0].I>>24) & 0xF]<<1)) * len; + } + BIOS_HuffUnComp(); + break; + case 0x14: + { + u32 len = CPUReadMemory(reg[0].I) >> 8; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (11 + memoryWait[(reg[0].I>>24) & 0xF] + + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_RLUnCompWram(); + break; + case 0x15: + { + u32 len = CPUReadMemory(reg[0].I) >> 9; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (34 + (memoryWait[(reg[0].I>>24) & 0xF] << 1) + + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_RLUnCompVram(); + break; + case 0x16: + { + u32 len = CPUReadMemory(reg[0].I) >> 8; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (13 + memoryWait[(reg[0].I>>24) & 0xF] + + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_Diff8bitUnFilterWram(); + break; + case 0x17: + { + u32 len = CPUReadMemory(reg[0].I) >> 9; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (39 + (memoryWait[(reg[0].I>>24) & 0xF]<<1) + + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_Diff8bitUnFilterVram(); + break; + case 0x18: + { + u32 len = CPUReadMemory(reg[0].I) >> 9; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (13 + memoryWait[(reg[0].I>>24) & 0xF] + + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_Diff16bitUnFilter(); + break; + case 0x19: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n", + reg[0].I, + VCOUNT); + } +#endif + if(reg[0].I) + systemSoundPause(); + else + systemSoundResume(); + break; + case 0x1F: + BIOS_MidiKey2Freq(); + break; + case 0x2A: + BIOS_SndDriverJmpTableCopy(); + // let it go, because we don't really emulate this function + default: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, + armState ? armNextPC - 4: armNextPC -2, + reg[0].I, + reg[1].I, + reg[2].I, + VCOUNT); + } +#endif + + if(!disableMessage) { + systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION, + N_("Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."), + comment, + armMode ? armNextPC - 4: armNextPC - 2); + disableMessage = true; + } + break; + } +} + +void CPUCompareVCOUNT() +{ + if(VCOUNT == (DISPSTAT >> 8)) { + DISPSTAT |= 4; + UPDATE_REG(0x04, DISPSTAT); + + if(DISPSTAT & 0x20) { + IF |= 4; + UPDATE_REG(0x202, IF); + } + } else { + DISPSTAT &= 0xFFFB; + UPDATE_REG(0x4, DISPSTAT); + } + if (layerEnableDelay>0) + { + layerEnableDelay--; + if (layerEnableDelay==1) + layerEnable = layerSettings & DISPCNT; + } + +} + +void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32) +{ + int sm = s >> 24; + int dm = d >> 24; + int sw = 0; + int dw = 0; + int sc = c; + + cpuDmaCount = c; + // This is done to get the correct waitstates. + if (sm>15) + sm=15; + if (dm>15) + dm=15; + + //if ((sm>=0x05) && (sm<=0x07) || (dm>=0x05) && (dm <=0x07)) + // blank = (((DISPSTAT | ((DISPSTAT>>1)&1))==1) ? true : false); + + if(transfer32) { + s &= 0xFFFFFFFC; + if(s < 0x02000000 && (reg[15].I >> 24)) { + while(c != 0) { + CPUWriteMemory(d, 0); + d += di; + c--; + } + } else { + while(c != 0) { + cpuDmaLast = CPUReadMemory(s); + CPUWriteMemory(d, cpuDmaLast); + d += di; + s += si; + c--; + } + } + } else { + s &= 0xFFFFFFFE; + si = (int)si >> 1; + di = (int)di >> 1; + if(s < 0x02000000 && (reg[15].I >> 24)) { + while(c != 0) { + CPUWriteHalfWord(d, 0); + d += di; + c--; + } + } else { + while(c != 0) { + cpuDmaLast = CPUReadHalfWord(s); + CPUWriteHalfWord(d, cpuDmaLast); + cpuDmaLast |= (cpuDmaLast<<16); + d += di; + s += si; + c--; + } + } + } + + cpuDmaCount = 0; + + int totalTicks = 0; + + if(transfer32) { + sw =1+memoryWaitSeq32[sm & 15]; + dw =1+memoryWaitSeq32[dm & 15]; + totalTicks = (sw+dw)*(sc-1) + 6 + memoryWait32[sm & 15] + + memoryWaitSeq32[dm & 15]; + } + else + { + sw = 1+memoryWaitSeq[sm & 15]; + dw = 1+memoryWaitSeq[dm & 15]; + totalTicks = (sw+dw)*(sc-1) + 6 + memoryWait[sm & 15] + + memoryWaitSeq[dm & 15]; + } + + cpuDmaTicksToUpdate += totalTicks; + +} + +void CPUCheckDMA(int reason, int dmamask) +{ + // DMA 0 + if((DM0CNT_H & 0x8000) && (dmamask & 1)) { + if(((DM0CNT_H >> 12) & 3) == reason) { + u32 sourceIncrement = 4; + u32 destIncrement = 4; + switch((DM0CNT_H >> 7) & 3) { + case 0: + break; + case 1: + sourceIncrement = (u32)-4; + break; + case 2: + sourceIncrement = 0; + break; + } + switch((DM0CNT_H >> 5) & 3) { + case 0: + break; + case 1: + destIncrement = (u32)-4; + break; + case 2: + destIncrement = 0; + break; + } +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_DMA0) { + int count = (DM0CNT_L ? DM0CNT_L : 0x4000) << 1; + if(DM0CNT_H & 0x0400) + count <<= 1; + log("DMA0: s=%08x d=%08x c=%04x count=%08x\n", dma0Source, dma0Dest, + DM0CNT_H, + count); + } +#endif + doDMA(dma0Source, dma0Dest, sourceIncrement, destIncrement, + DM0CNT_L ? DM0CNT_L : 0x4000, + DM0CNT_H & 0x0400); + cpuDmaHack = true; + + if(DM0CNT_H & 0x4000) { + IF |= 0x0100; + UPDATE_REG(0x202, IF); + cpuNextEvent = cpuTotalTicks; + } + + if(((DM0CNT_H >> 5) & 3) == 3) { + dma0Dest = DM0DAD_L | (DM0DAD_H << 16); + } + + if(!(DM0CNT_H & 0x0200) || (reason == 0)) { + DM0CNT_H &= 0x7FFF; + UPDATE_REG(0xBA, DM0CNT_H); + } + } + } + + // DMA 1 + if((DM1CNT_H & 0x8000) && (dmamask & 2)) { + if(((DM1CNT_H >> 12) & 3) == reason) { + u32 sourceIncrement = 4; + u32 destIncrement = 4; + switch((DM1CNT_H >> 7) & 3) { + case 0: + break; + case 1: + sourceIncrement = (u32)-4; + break; + case 2: + sourceIncrement = 0; + break; + } + switch((DM1CNT_H >> 5) & 3) { + case 0: + break; + case 1: + destIncrement = (u32)-4; + break; + case 2: + destIncrement = 0; + break; + } + if(reason == 3) { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_DMA1) { + log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest, + DM1CNT_H, + 16); + } +#endif + doDMA(dma1Source, dma1Dest, sourceIncrement, 0, 4, + 0x0400); + } else { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_DMA1) { + int count = (DM1CNT_L ? DM1CNT_L : 0x4000) << 1; + if(DM1CNT_H & 0x0400) + count <<= 1; + log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest, + DM1CNT_H, + count); + } +#endif + doDMA(dma1Source, dma1Dest, sourceIncrement, destIncrement, + DM1CNT_L ? DM1CNT_L : 0x4000, + DM1CNT_H & 0x0400); + } + cpuDmaHack = true; + + if(DM1CNT_H & 0x4000) { + IF |= 0x0200; + UPDATE_REG(0x202, IF); + cpuNextEvent = cpuTotalTicks; + } + + if(((DM1CNT_H >> 5) & 3) == 3) { + dma1Dest = DM1DAD_L | (DM1DAD_H << 16); + } + + if(!(DM1CNT_H & 0x0200) || (reason == 0)) { + DM1CNT_H &= 0x7FFF; + UPDATE_REG(0xC6, DM1CNT_H); + } + } + } + + // DMA 2 + if((DM2CNT_H & 0x8000) && (dmamask & 4)) { + if(((DM2CNT_H >> 12) & 3) == reason) { + u32 sourceIncrement = 4; + u32 destIncrement = 4; + switch((DM2CNT_H >> 7) & 3) { + case 0: + break; + case 1: + sourceIncrement = (u32)-4; + break; + case 2: + sourceIncrement = 0; + break; + } + switch((DM2CNT_H >> 5) & 3) { + case 0: + break; + case 1: + destIncrement = (u32)-4; + break; + case 2: + destIncrement = 0; + break; + } + if(reason == 3) { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_DMA2) { + int count = (4) << 2; + log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest, + DM2CNT_H, + count); + } +#endif + doDMA(dma2Source, dma2Dest, sourceIncrement, 0, 4, + 0x0400); + } else { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_DMA2) { + int count = (DM2CNT_L ? DM2CNT_L : 0x4000) << 1; + if(DM2CNT_H & 0x0400) + count <<= 1; + log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest, + DM2CNT_H, + count); + } +#endif + doDMA(dma2Source, dma2Dest, sourceIncrement, destIncrement, + DM2CNT_L ? DM2CNT_L : 0x4000, + DM2CNT_H & 0x0400); + } + cpuDmaHack = true; + + if(DM2CNT_H & 0x4000) { + IF |= 0x0400; + UPDATE_REG(0x202, IF); + cpuNextEvent = cpuTotalTicks; + } + + if(((DM2CNT_H >> 5) & 3) == 3) { + dma2Dest = DM2DAD_L | (DM2DAD_H << 16); + } + + if(!(DM2CNT_H & 0x0200) || (reason == 0)) { + DM2CNT_H &= 0x7FFF; + UPDATE_REG(0xD2, DM2CNT_H); + } + } + } + + // DMA 3 + if((DM3CNT_H & 0x8000) && (dmamask & 8)) { + if(((DM3CNT_H >> 12) & 3) == reason) { + u32 sourceIncrement = 4; + u32 destIncrement = 4; + switch((DM3CNT_H >> 7) & 3) { + case 0: + break; + case 1: + sourceIncrement = (u32)-4; + break; + case 2: + sourceIncrement = 0; + break; + } + switch((DM3CNT_H >> 5) & 3) { + case 0: + break; + case 1: + destIncrement = (u32)-4; + break; + case 2: + destIncrement = 0; + break; + } +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_DMA3) { + int count = (DM3CNT_L ? DM3CNT_L : 0x10000) << 1; + if(DM3CNT_H & 0x0400) + count <<= 1; + log("DMA3: s=%08x d=%08x c=%04x count=%08x\n", dma3Source, dma3Dest, + DM3CNT_H, + count); + } +#endif + doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement, + DM3CNT_L ? DM3CNT_L : 0x10000, + DM3CNT_H & 0x0400); + if(DM3CNT_H & 0x4000) { + IF |= 0x0800; + UPDATE_REG(0x202, IF); + cpuNextEvent = cpuTotalTicks; + } + + if(((DM3CNT_H >> 5) & 3) == 3) { + dma3Dest = DM3DAD_L | (DM3DAD_H << 16); + } + + if(!(DM3CNT_H & 0x0200) || (reason == 0)) { + DM3CNT_H &= 0x7FFF; + UPDATE_REG(0xDE, DM3CNT_H); + } + } + } +} + +void CPUUpdateRegister(u32 address, u16 value) +{ + switch(address) { + case 0x00: + { + if ((value & 7) >5) + DISPCNT = (value &7); + bool change = ((DISPCNT ^ value) & 0x80) ? true : false; + bool changeBG = ((DISPCNT ^ value) & 0x0F00) ? true : false; + u16 changeBGon = (((~DISPCNT) & value) & 0x0F00); + DISPCNT = (value & 0xFFF7); + UPDATE_REG(0x00, DISPCNT); + + if (changeBGon) + { + layerEnableDelay=4; + layerEnable = layerSettings & value & (~changeBGon); + } + else + layerEnable = layerSettings & value; + // CPUUpdateTicks(); + + windowOn = (layerEnable & 0x6000) ? true : false; + if(change && !((value & 0x80))) { + if(!(DISPSTAT & 1)) { + lcdTicks = 1008; + // VCOUNT = 0; + // UPDATE_REG(0x06, VCOUNT); + DISPSTAT &= 0xFFFC; + UPDATE_REG(0x04, DISPSTAT); + CPUCompareVCOUNT(); + } + // (*renderLine)(); + } + CPUUpdateRender(); + // we only care about changes in BG0-BG3 + if(changeBG) + CPUUpdateRenderBuffers(false); + } + break; + case 0x04: + DISPSTAT = (value & 0xFF38) | (DISPSTAT & 7); + UPDATE_REG(0x04, DISPSTAT); + break; + case 0x06: + // not writable + break; + case 0x08: + BG0CNT = (value & 0xDFCF); + UPDATE_REG(0x08, BG0CNT); + break; + case 0x0A: + BG1CNT = (value & 0xDFCF); + UPDATE_REG(0x0A, BG1CNT); + break; + case 0x0C: + BG2CNT = (value & 0xFFCF); + UPDATE_REG(0x0C, BG2CNT); + break; + case 0x0E: + BG3CNT = (value & 0xFFCF); + UPDATE_REG(0x0E, BG3CNT); + break; + case 0x10: + BG0HOFS = value & 511; + UPDATE_REG(0x10, BG0HOFS); + break; + case 0x12: + BG0VOFS = value & 511; + UPDATE_REG(0x12, BG0VOFS); + break; + case 0x14: + BG1HOFS = value & 511; + UPDATE_REG(0x14, BG1HOFS); + break; + case 0x16: + BG1VOFS = value & 511; + UPDATE_REG(0x16, BG1VOFS); + break; + case 0x18: + BG2HOFS = value & 511; + UPDATE_REG(0x18, BG2HOFS); + break; + case 0x1A: + BG2VOFS = value & 511; + UPDATE_REG(0x1A, BG2VOFS); + break; + case 0x1C: + BG3HOFS = value & 511; + UPDATE_REG(0x1C, BG3HOFS); + break; + case 0x1E: + BG3VOFS = value & 511; + UPDATE_REG(0x1E, BG3VOFS); + break; + case 0x20: + BG2PA = value; + UPDATE_REG(0x20, BG2PA); + break; + case 0x22: + BG2PB = value; + UPDATE_REG(0x22, BG2PB); + break; + case 0x24: + BG2PC = value; + UPDATE_REG(0x24, BG2PC); + break; + case 0x26: + BG2PD = value; + UPDATE_REG(0x26, BG2PD); + break; + case 0x28: + BG2X_L = value; + UPDATE_REG(0x28, BG2X_L); + gfxBG2Changed |= 1; + break; + case 0x2A: + BG2X_H = (value & 0xFFF); + UPDATE_REG(0x2A, BG2X_H); + gfxBG2Changed |= 1; + break; + case 0x2C: + BG2Y_L = value; + UPDATE_REG(0x2C, BG2Y_L); + gfxBG2Changed |= 2; + break; + case 0x2E: + BG2Y_H = value & 0xFFF; + UPDATE_REG(0x2E, BG2Y_H); + gfxBG2Changed |= 2; + break; + case 0x30: + BG3PA = value; + UPDATE_REG(0x30, BG3PA); + break; + case 0x32: + BG3PB = value; + UPDATE_REG(0x32, BG3PB); + break; + case 0x34: + BG3PC = value; + UPDATE_REG(0x34, BG3PC); + break; + case 0x36: + BG3PD = value; + UPDATE_REG(0x36, BG3PD); + break; + case 0x38: + BG3X_L = value; + UPDATE_REG(0x38, BG3X_L); + gfxBG3Changed |= 1; + break; + case 0x3A: + BG3X_H = value & 0xFFF; + UPDATE_REG(0x3A, BG3X_H); + gfxBG3Changed |= 1; + break; + case 0x3C: + BG3Y_L = value; + UPDATE_REG(0x3C, BG3Y_L); + gfxBG3Changed |= 2; + break; + case 0x3E: + BG3Y_H = value & 0xFFF; + UPDATE_REG(0x3E, BG3Y_H); + gfxBG3Changed |= 2; + break; + case 0x40: + WIN0H = value; + UPDATE_REG(0x40, WIN0H); + CPUUpdateWindow0(); + break; + case 0x42: + WIN1H = value; + UPDATE_REG(0x42, WIN1H); + CPUUpdateWindow1(); + break; + case 0x44: + WIN0V = value; + UPDATE_REG(0x44, WIN0V); + break; + case 0x46: + WIN1V = value; + UPDATE_REG(0x46, WIN1V); + break; + case 0x48: + WININ = value & 0x3F3F; + UPDATE_REG(0x48, WININ); + break; + case 0x4A: + WINOUT = value & 0x3F3F; + UPDATE_REG(0x4A, WINOUT); + break; + case 0x4C: + MOSAIC = value; + UPDATE_REG(0x4C, MOSAIC); + break; + case 0x50: + BLDMOD = value & 0x3FFF; + UPDATE_REG(0x50, BLDMOD); + fxOn = ((BLDMOD>>6)&3) != 0; + CPUUpdateRender(); + break; + case 0x52: + COLEV = value & 0x1F1F; + UPDATE_REG(0x52, COLEV); + break; + case 0x54: + COLY = value & 0x1F; + UPDATE_REG(0x54, COLY); + break; + case 0x60: + case 0x62: + case 0x64: + case 0x68: + case 0x6c: + case 0x70: + case 0x72: + case 0x74: + case 0x78: + case 0x7c: + case 0x80: + case 0x84: + soundEvent(address&0xFF, (u8)(value & 0xFF)); + soundEvent((address&0xFF)+1, (u8)(value>>8)); + break; + case 0x82: + case 0x88: + case 0xa0: + case 0xa2: + case 0xa4: + case 0xa6: + case 0x90: + case 0x92: + case 0x94: + case 0x96: + case 0x98: + case 0x9a: + case 0x9c: + case 0x9e: + soundEvent(address&0xFF, value); + break; + case 0xB0: + DM0SAD_L = value; + UPDATE_REG(0xB0, DM0SAD_L); + break; + case 0xB2: + DM0SAD_H = value & 0x07FF; + UPDATE_REG(0xB2, DM0SAD_H); + break; + case 0xB4: + DM0DAD_L = value; + UPDATE_REG(0xB4, DM0DAD_L); + break; + case 0xB6: + DM0DAD_H = value & 0x07FF; + UPDATE_REG(0xB6, DM0DAD_H); + break; + case 0xB8: + DM0CNT_L = value & 0x3FFF; + UPDATE_REG(0xB8, 0); + break; + case 0xBA: + { + bool start = ((DM0CNT_H ^ value) & 0x8000) ? true : false; + value &= 0xF7E0; + + DM0CNT_H = value; + UPDATE_REG(0xBA, DM0CNT_H); + + if(start && (value & 0x8000)) { + dma0Source = DM0SAD_L | (DM0SAD_H << 16); + dma0Dest = DM0DAD_L | (DM0DAD_H << 16); + CPUCheckDMA(0, 1); + } + } + break; + case 0xBC: + DM1SAD_L = value; + UPDATE_REG(0xBC, DM1SAD_L); + break; + case 0xBE: + DM1SAD_H = value & 0x0FFF; + UPDATE_REG(0xBE, DM1SAD_H); + break; + case 0xC0: + DM1DAD_L = value; + UPDATE_REG(0xC0, DM1DAD_L); + break; + case 0xC2: + DM1DAD_H = value & 0x07FF; + UPDATE_REG(0xC2, DM1DAD_H); + break; + case 0xC4: + DM1CNT_L = value & 0x3FFF; + UPDATE_REG(0xC4, 0); + break; + case 0xC6: + { + bool start = ((DM1CNT_H ^ value) & 0x8000) ? true : false; + value &= 0xF7E0; + + DM1CNT_H = value; + UPDATE_REG(0xC6, DM1CNT_H); + + if(start && (value & 0x8000)) { + dma1Source = DM1SAD_L | (DM1SAD_H << 16); + dma1Dest = DM1DAD_L | (DM1DAD_H << 16); + CPUCheckDMA(0, 2); + } + } + break; + case 0xC8: + DM2SAD_L = value; + UPDATE_REG(0xC8, DM2SAD_L); + break; + case 0xCA: + DM2SAD_H = value & 0x0FFF; + UPDATE_REG(0xCA, DM2SAD_H); + break; + case 0xCC: + DM2DAD_L = value; + UPDATE_REG(0xCC, DM2DAD_L); + break; + case 0xCE: + DM2DAD_H = value & 0x07FF; + UPDATE_REG(0xCE, DM2DAD_H); + break; + case 0xD0: + DM2CNT_L = value & 0x3FFF; + UPDATE_REG(0xD0, 0); + break; + case 0xD2: + { + bool start = ((DM2CNT_H ^ value) & 0x8000) ? true : false; + + value &= 0xF7E0; + + DM2CNT_H = value; + UPDATE_REG(0xD2, DM2CNT_H); + + if(start && (value & 0x8000)) { + dma2Source = DM2SAD_L | (DM2SAD_H << 16); + dma2Dest = DM2DAD_L | (DM2DAD_H << 16); + + CPUCheckDMA(0, 4); + } + } + break; + case 0xD4: + DM3SAD_L = value; + UPDATE_REG(0xD4, DM3SAD_L); + break; + case 0xD6: + DM3SAD_H = value & 0x0FFF; + UPDATE_REG(0xD6, DM3SAD_H); + break; + case 0xD8: + DM3DAD_L = value; + UPDATE_REG(0xD8, DM3DAD_L); + break; + case 0xDA: + DM3DAD_H = value & 0x0FFF; + UPDATE_REG(0xDA, DM3DAD_H); + break; + case 0xDC: + DM3CNT_L = value; + UPDATE_REG(0xDC, 0); + break; + case 0xDE: + { + bool start = ((DM3CNT_H ^ value) & 0x8000) ? true : false; + + value &= 0xFFE0; + + DM3CNT_H = value; + UPDATE_REG(0xDE, DM3CNT_H); + + if(start && (value & 0x8000)) { + dma3Source = DM3SAD_L | (DM3SAD_H << 16); + dma3Dest = DM3DAD_L | (DM3DAD_H << 16); + CPUCheckDMA(0,8); + } + } + break; + case 0x100: + timer0Reload = value; + interp_rate(); + break; + case 0x102: + timer0Value = value; + timerOnOffDelay|=1; + cpuNextEvent = cpuTotalTicks; + break; + case 0x104: + timer1Reload = value; + interp_rate(); + break; + case 0x106: + timer1Value = value; + timerOnOffDelay|=2; + cpuNextEvent = cpuTotalTicks; + break; + case 0x108: + timer2Reload = value; + break; + case 0x10A: + timer2Value = value; + timerOnOffDelay|=4; + cpuNextEvent = cpuTotalTicks; + break; + case 0x10C: + timer3Reload = value; + break; + case 0x10E: + timer3Value = value; + timerOnOffDelay|=8; + cpuNextEvent = cpuTotalTicks; + break; + case 0x128: + #ifdef LINK_EMULATION + if (linkenable) + { + StartLink(value); + } + else +#endif + { + if(value & 0x80) { + value &= 0xff7f; + if(value & 1 && (value & 0x4000)) { + UPDATE_REG(0x12a, 0xFF); + IF |= 0x80; + UPDATE_REG(0x202, IF); + value &= 0x7f7f; + } + } + UPDATE_REG(0x128, value); + } + break; + case 0x12a: + #ifdef LINK_EMULATION + if(linkenable && lspeed) + LinkSSend(value); + #endif + { + UPDATE_REG(0x134, value); + } + break; + case 0x130: + P1 |= (value & 0x3FF); + UPDATE_REG(0x130, P1); + break; + case 0x132: + UPDATE_REG(0x132, value & 0xC3FF); + break; + case 0x134: +#ifdef LINK_EMULATION + if (linkenable) + StartGPLink(value); + else +#endif + UPDATE_REG(0x134, value); + + break; + case 0x140: +#ifdef LINK_EMULATION + if (linkenable) + StartJOYLink(value); + else +#endif + UPDATE_REG(0x140, value); + + break; + case 0x200: + IE = value & 0x3FFF; + UPDATE_REG(0x200, IE); + if ((IME & 1) && (IF & IE) && armIrqEnable) + cpuNextEvent = cpuTotalTicks; + break; + case 0x202: + IF ^= (value & IF); + UPDATE_REG(0x202, IF); + break; + case 0x204: + { + memoryWait[0x0e] = memoryWaitSeq[0x0e] = gamepakRamWaitState[value & 3]; + + if(!speedHack) { + memoryWait[0x08] = memoryWait[0x09] = gamepakWaitState[(value >> 2) & 3]; + memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = + gamepakWaitState0[(value >> 4) & 1]; + + memoryWait[0x0a] = memoryWait[0x0b] = gamepakWaitState[(value >> 5) & 3]; + memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = + gamepakWaitState1[(value >> 7) & 1]; + + memoryWait[0x0c] = memoryWait[0x0d] = gamepakWaitState[(value >> 8) & 3]; + memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = + gamepakWaitState2[(value >> 10) & 1]; + } else { + memoryWait[0x08] = memoryWait[0x09] = 3; + memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = 1; + + memoryWait[0x0a] = memoryWait[0x0b] = 3; + memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = 1; + + memoryWait[0x0c] = memoryWait[0x0d] = 3; + memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = 1; + } + + for(int i = 8; i < 15; i++) { + memoryWait32[i] = memoryWait[i] + memoryWaitSeq[i] + 1; + memoryWaitSeq32[i] = memoryWaitSeq[i]*2 + 1; + } + + if((value & 0x4000) == 0x4000) { + busPrefetchEnable = true; + busPrefetch = false; + busPrefetchCount = 0; + } else { + busPrefetchEnable = false; + busPrefetch = false; + busPrefetchCount = 0; + } + UPDATE_REG(0x204, value & 0x7FFF); + + } + break; + case 0x208: + IME = value & 1; + UPDATE_REG(0x208, IME); + if ((IME & 1) && (IF & IE) && armIrqEnable) + cpuNextEvent = cpuTotalTicks; + break; + case 0x300: + if(value != 0) + value &= 0xFFFE; + UPDATE_REG(0x300, value); + break; + default: + UPDATE_REG(address&0x3FE, value); + break; + } +} + +void applyTimer () +{ + if (timerOnOffDelay & 1) + { + timer0ClockReload = TIMER_TICKS[timer0Value & 3]; + if(!timer0On && (timer0Value & 0x80)) { + // reload the counter + TM0D = timer0Reload; + timer0Ticks = (0x10000 - TM0D) << timer0ClockReload; + UPDATE_REG(0x100, TM0D); + } + timer0On = timer0Value & 0x80 ? true : false; + TM0CNT = timer0Value & 0xC7; + interp_rate(); + UPDATE_REG(0x102, TM0CNT); + // CPUUpdateTicks(); + } + if (timerOnOffDelay & 2) + { + timer1ClockReload = TIMER_TICKS[timer1Value & 3]; + if(!timer1On && (timer1Value & 0x80)) { + // reload the counter + TM1D = timer1Reload; + timer1Ticks = (0x10000 - TM1D) << timer1ClockReload; + UPDATE_REG(0x104, TM1D); + } + timer1On = timer1Value & 0x80 ? true : false; + TM1CNT = timer1Value & 0xC7; + interp_rate(); + UPDATE_REG(0x106, TM1CNT); + } + if (timerOnOffDelay & 4) + { + timer2ClockReload = TIMER_TICKS[timer2Value & 3]; + if(!timer2On && (timer2Value & 0x80)) { + // reload the counter + TM2D = timer2Reload; + timer2Ticks = (0x10000 - TM2D) << timer2ClockReload; + UPDATE_REG(0x108, TM2D); + } + timer2On = timer2Value & 0x80 ? true : false; + TM2CNT = timer2Value & 0xC7; + UPDATE_REG(0x10A, TM2CNT); + } + if (timerOnOffDelay & 8) + { + timer3ClockReload = TIMER_TICKS[timer3Value & 3]; + if(!timer3On && (timer3Value & 0x80)) { + // reload the counter + TM3D = timer3Reload; + timer3Ticks = (0x10000 - TM3D) << timer3ClockReload; + UPDATE_REG(0x10C, TM3D); + } + timer3On = timer3Value & 0x80 ? true : false; + TM3CNT = timer3Value & 0xC7; + UPDATE_REG(0x10E, TM3CNT); + } + cpuNextEvent = CPUUpdateTicks(); + timerOnOffDelay = 0; +} + +u8 cpuBitsSet[256]; +u8 cpuLowestBitSet[256]; + +void CPUInit(const char *biosFileName, bool useBiosFile) +{ +#ifdef WORDS_BIGENDIAN + if(!cpuBiosSwapped) { + for(unsigned int i = 0; i < sizeof(myROM)/4; i++) { + WRITE32LE(&myROM[i], myROM[i]); + } + cpuBiosSwapped = true; + } +#endif + gbaSaveType = 0; + eepromInUse = 0; + saveType = 0; + useBios = false; + + if(useBiosFile) { + int size = 0x4000; + if(utilLoad(biosFileName, + CPUIsGBABios, + bios, + size)) { + if(size == 0x4000) + useBios = true; + else + systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BIOS file size")); + } + } + + if(!useBios) { + memcpy(bios, myROM, sizeof(myROM)); + } + + int i = 0; + + biosProtected[0] = 0x00; + biosProtected[1] = 0xf0; + biosProtected[2] = 0x29; + biosProtected[3] = 0xe1; + + for(i = 0; i < 256; i++) { + int count = 0; + int j; + for(j = 0; j < 8; j++) + if(i & (1 << j)) + count++; + cpuBitsSet[i] = count; + + for(j = 0; j < 8; j++) + if(i & (1 << j)) + break; + cpuLowestBitSet[i] = j; + } + + for(i = 0; i < 0x400; i++) + ioReadable[i] = true; + for(i = 0x10; i < 0x48; i++) + ioReadable[i] = false; + for(i = 0x4c; i < 0x50; i++) + ioReadable[i] = false; + for(i = 0x54; i < 0x60; i++) + ioReadable[i] = false; + for(i = 0x8c; i < 0x90; i++) + ioReadable[i] = false; + for(i = 0xa0; i < 0xb8; i++) + ioReadable[i] = false; + for(i = 0xbc; i < 0xc4; i++) + ioReadable[i] = false; + for(i = 0xc8; i < 0xd0; i++) + ioReadable[i] = false; + for(i = 0xd4; i < 0xdc; i++) + ioReadable[i] = false; + for(i = 0xe0; i < 0x100; i++) + ioReadable[i] = false; + for(i = 0x110; i < 0x120; i++) + ioReadable[i] = false; + for(i = 0x12c; i < 0x130; i++) + ioReadable[i] = false; + for(i = 0x138; i < 0x140; i++) + ioReadable[i] = false; + for(i = 0x144; i < 0x150; i++) + ioReadable[i] = false; + for(i = 0x15c; i < 0x200; i++) + ioReadable[i] = false; + for(i = 0x20c; i < 0x300; i++) + ioReadable[i] = false; + for(i = 0x304; i < 0x400; i++) + ioReadable[i] = false; + + if(romSize < 0x1fe2000) { + *((u16 *)&rom[0x1fe209c]) = 0xdffa; // SWI 0xFA + *((u16 *)&rom[0x1fe209e]) = 0x4770; // BX LR + } else { + agbPrintEnable(false); + } +} + +void CPUReset() +{ + if(gbaSaveType == 0) { + if(eepromInUse) + gbaSaveType = 3; + else + switch(saveType) { + case 1: + gbaSaveType = 1; + break; + case 2: + gbaSaveType = 2; + break; + } + } + rtcReset(); + // clean registers + memset(®[0], 0, sizeof(reg)); + // clean OAM + memset(oam, 0, 0x400); + // clean palette + memset(paletteRAM, 0, 0x400); + // clean picture + memset(pix, 0, 4*160*240); + // clean vram + memset(vram, 0, 0x20000); + // clean io memory + memset(ioMem, 0, 0x400); + + DISPCNT = 0x0080; + DISPSTAT = 0x0000; + VCOUNT = (useBios && !skipBios) ? 0 :0x007E; + BG0CNT = 0x0000; + BG1CNT = 0x0000; + BG2CNT = 0x0000; + BG3CNT = 0x0000; + BG0HOFS = 0x0000; + BG0VOFS = 0x0000; + BG1HOFS = 0x0000; + BG1VOFS = 0x0000; + BG2HOFS = 0x0000; + BG2VOFS = 0x0000; + BG3HOFS = 0x0000; + BG3VOFS = 0x0000; + BG2PA = 0x0100; + BG2PB = 0x0000; + BG2PC = 0x0000; + BG2PD = 0x0100; + BG2X_L = 0x0000; + BG2X_H = 0x0000; + BG2Y_L = 0x0000; + BG2Y_H = 0x0000; + BG3PA = 0x0100; + BG3PB = 0x0000; + BG3PC = 0x0000; + BG3PD = 0x0100; + BG3X_L = 0x0000; + BG3X_H = 0x0000; + BG3Y_L = 0x0000; + BG3Y_H = 0x0000; + WIN0H = 0x0000; + WIN1H = 0x0000; + WIN0V = 0x0000; + WIN1V = 0x0000; + WININ = 0x0000; + WINOUT = 0x0000; + MOSAIC = 0x0000; + BLDMOD = 0x0000; + COLEV = 0x0000; + COLY = 0x0000; + DM0SAD_L = 0x0000; + DM0SAD_H = 0x0000; + DM0DAD_L = 0x0000; + DM0DAD_H = 0x0000; + DM0CNT_L = 0x0000; + DM0CNT_H = 0x0000; + DM1SAD_L = 0x0000; + DM1SAD_H = 0x0000; + DM1DAD_L = 0x0000; + DM1DAD_H = 0x0000; + DM1CNT_L = 0x0000; + DM1CNT_H = 0x0000; + DM2SAD_L = 0x0000; + DM2SAD_H = 0x0000; + DM2DAD_L = 0x0000; + DM2DAD_H = 0x0000; + DM2CNT_L = 0x0000; + DM2CNT_H = 0x0000; + DM3SAD_L = 0x0000; + DM3SAD_H = 0x0000; + DM3DAD_L = 0x0000; + DM3DAD_H = 0x0000; + DM3CNT_L = 0x0000; + DM3CNT_H = 0x0000; + TM0D = 0x0000; + TM0CNT = 0x0000; + TM1D = 0x0000; + TM1CNT = 0x0000; + TM2D = 0x0000; + TM2CNT = 0x0000; + TM3D = 0x0000; + TM3CNT = 0x0000; + P1 = 0x03FF; + IE = 0x0000; + IF = 0x0000; + IME = 0x0000; + + armMode = 0x1F; + + if(cpuIsMultiBoot) { + reg[13].I = 0x03007F00; + reg[15].I = 0x02000000; + reg[16].I = 0x00000000; + reg[R13_IRQ].I = 0x03007FA0; + reg[R13_SVC].I = 0x03007FE0; + armIrqEnable = true; + } else { + if(useBios && !skipBios) { + reg[15].I = 0x00000000; + armMode = 0x13; + armIrqEnable = false; + } else { + reg[13].I = 0x03007F00; + reg[15].I = 0x08000000; + reg[16].I = 0x00000000; + reg[R13_IRQ].I = 0x03007FA0; + reg[R13_SVC].I = 0x03007FE0; + armIrqEnable = true; + } + } + armState = true; + C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false; + UPDATE_REG(0x00, DISPCNT); + UPDATE_REG(0x06, VCOUNT); + UPDATE_REG(0x20, BG2PA); + UPDATE_REG(0x26, BG2PD); + UPDATE_REG(0x30, BG3PA); + UPDATE_REG(0x36, BG3PD); + UPDATE_REG(0x130, P1); + UPDATE_REG(0x88, 0x200); + + // disable FIQ + reg[16].I |= 0x40; + + CPUUpdateCPSR(); + + armNextPC = reg[15].I; + reg[15].I += 4; + + // reset internal state + holdState = false; + holdType = 0; + + biosProtected[0] = 0x00; + biosProtected[1] = 0xf0; + biosProtected[2] = 0x29; + biosProtected[3] = 0xe1; + + lcdTicks = (useBios && !skipBios) ? 1008 : 208; + timer0On = false; + timer0Ticks = 0; + timer0Reload = 0; + timer0ClockReload = 0; + timer1On = false; + timer1Ticks = 0; + timer1Reload = 0; + timer1ClockReload = 0; + timer2On = false; + timer2Ticks = 0; + timer2Reload = 0; + timer2ClockReload = 0; + timer3On = false; + timer3Ticks = 0; + timer3Reload = 0; + timer3ClockReload = 0; + dma0Source = 0; + dma0Dest = 0; + dma1Source = 0; + dma1Dest = 0; + dma2Source = 0; + dma2Dest = 0; + dma3Source = 0; + dma3Dest = 0; + cpuSaveGameFunc = flashSaveDecide; + renderLine = mode0RenderLine; + fxOn = false; + windowOn = false; + frameCount = 0; + saveType = 0; + layerEnable = DISPCNT & layerSettings; + + CPUUpdateRenderBuffers(true); + + for(int i = 0; i < 256; i++) { + map[i].address = (u8 *)&dummyAddress; + map[i].mask = 0; + } + + map[0].address = bios; + map[0].mask = 0x3FFF; + map[2].address = workRAM; + map[2].mask = 0x3FFFF; + map[3].address = internalRAM; + map[3].mask = 0x7FFF; + map[4].address = ioMem; + map[4].mask = 0x3FF; + map[5].address = paletteRAM; + map[5].mask = 0x3FF; + map[6].address = vram; + map[6].mask = 0x1FFFF; + map[7].address = oam; + map[7].mask = 0x3FF; + map[8].address = rom; + map[8].mask = 0x1FFFFFF; + map[9].address = rom; + map[9].mask = 0x1FFFFFF; + map[10].address = rom; + map[10].mask = 0x1FFFFFF; + map[12].address = rom; + map[12].mask = 0x1FFFFFF; + map[14].address = flashSaveMemory; + map[14].mask = 0xFFFF; + + eepromReset(); + flashReset(); + + soundReset(); + + CPUUpdateWindow0(); + CPUUpdateWindow1(); + + // make sure registers are correctly initialized if not using BIOS + if(!useBios) { + if(cpuIsMultiBoot) + BIOS_RegisterRamReset(0xfe); + else + BIOS_RegisterRamReset(0xff); + } else { + if(cpuIsMultiBoot) + BIOS_RegisterRamReset(0xfe); + } + + switch(cpuSaveType) { + case 0: // automatic + cpuSramEnabled = true; + cpuFlashEnabled = true; + cpuEEPROMEnabled = true; + cpuEEPROMSensorEnabled = false; + saveType = gbaSaveType = 0; + break; + case 1: // EEPROM + cpuSramEnabled = false; + cpuFlashEnabled = false; + cpuEEPROMEnabled = true; + cpuEEPROMSensorEnabled = false; + saveType = gbaSaveType = 3; + // EEPROM usage is automatically detected + break; + case 2: // SRAM + cpuSramEnabled = true; + cpuFlashEnabled = false; + cpuEEPROMEnabled = false; + cpuEEPROMSensorEnabled = false; + cpuSaveGameFunc = sramDelayedWrite; // to insure we detect the write + saveType = gbaSaveType = 1; + break; + case 3: // FLASH + cpuSramEnabled = false; + cpuFlashEnabled = true; + cpuEEPROMEnabled = false; + cpuEEPROMSensorEnabled = false; + cpuSaveGameFunc = flashDelayedWrite; // to insure we detect the write + saveType = gbaSaveType = 2; + break; + case 4: // EEPROM+Sensor + cpuSramEnabled = false; + cpuFlashEnabled = false; + cpuEEPROMEnabled = true; + cpuEEPROMSensorEnabled = true; + // EEPROM usage is automatically detected + saveType = gbaSaveType = 3; + break; + case 5: // NONE + cpuSramEnabled = false; + cpuFlashEnabled = false; + cpuEEPROMEnabled = false; + cpuEEPROMSensorEnabled = false; + // no save at all + saveType = gbaSaveType = 5; + break; + } + + ARM_PREFETCH; + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + cpuDmaHack = false; + + lastTime = systemGetClock(); + + SWITicks = 0; +} + +void CPUInterrupt() +{ + u32 PC = reg[15].I; + bool savedState = armState; + CPUSwitchMode(0x12, true, false); + reg[14].I = PC; + if(!savedState) + reg[14].I += 2; + reg[15].I = 0x18; + armState = true; + armIrqEnable = false; + + armNextPC = reg[15].I; + reg[15].I += 4; + ARM_PREFETCH; + + // if(!holdState) + biosProtected[0] = 0x02; + biosProtected[1] = 0xc0; + biosProtected[2] = 0x5e; + biosProtected[3] = 0xe5; +} + +#ifdef SDL +void log(const char *defaultMsg, ...) +{ + char buffer[2048]; + va_list valist; + + va_start(valist, defaultMsg); + vsprintf(buffer, defaultMsg, valist); + + if(out == NULL) { + out = fopen("trace.log","w"); + } + + fputs(buffer, out); + + va_end(valist); +} +#else +extern void winlog(const char *, ...); +#endif + +void CPULoop(int ticks) +{ + int clockTicks; + int timerOverflow = 0; + // variable used by the CPU core + cpuTotalTicks = 0; +#ifdef LINK_EMULATION + if(linkenable) + cpuNextEvent = 1; +#endif + cpuBreakLoop = false; + cpuNextEvent = CPUUpdateTicks(); + if(cpuNextEvent > ticks) + cpuNextEvent = ticks; + + + for(;;) { +#ifndef FINAL_VERSION + if(systemDebug) { + if(systemDebug >= 10 && !holdState) { + CPUUpdateCPSR(); +#ifdef BKPT_SUPPORT + if (debugger_last) + { + sprintf(buffer, "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n", + oldreg[0], oldreg[1], oldreg[2], oldreg[3], oldreg[4], oldreg[5], + oldreg[6], oldreg[7], oldreg[8], oldreg[9], oldreg[10], oldreg[11], + oldreg[12], oldreg[13], oldreg[14], oldreg[15], oldreg[16], + oldreg[17]); + } +#endif + sprintf(buffer, "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n", + reg[0].I, reg[1].I, reg[2].I, reg[3].I, reg[4].I, reg[5].I, + reg[6].I, reg[7].I, reg[8].I, reg[9].I, reg[10].I, reg[11].I, + reg[12].I, reg[13].I, reg[14].I, reg[15].I, reg[16].I, + reg[17].I); +#ifdef SDL + log(buffer); +#else + winlog(buffer); +#endif + } else if(!holdState) { + sprintf(buffer, "PC=%08x\n", armNextPC); +#ifdef SDL + log(buffer); +#else + winlog(buffer); +#endif + } + } +#endif /* FINAL_VERSION */ + + if(!holdState && !SWITicks) { + if(armState) { + if (!armExecute()) + return; + } else { + if (!thumbExecute()) + return; + } + clockTicks = 0; + } else + clockTicks = CPUUpdateTicks(); + + cpuTotalTicks += clockTicks; + + + if(cpuTotalTicks >= cpuNextEvent) { + int remainingTicks = cpuTotalTicks - cpuNextEvent; + + if (SWITicks) + { + SWITicks-=clockTicks; + if (SWITicks<0) + SWITicks = 0; + } + + clockTicks = cpuNextEvent; + cpuTotalTicks = 0; + cpuDmaHack = false; + + updateLoop: + + if (IRQTicks) + { + IRQTicks -= clockTicks; + if (IRQTicks<0) + IRQTicks = 0; + } + + lcdTicks -= clockTicks; + + + if(lcdTicks <= 0) { + if(DISPSTAT & 1) { // V-BLANK + // if in V-Blank mode, keep computing... + if(DISPSTAT & 2) { + lcdTicks += 1008; + VCOUNT++; + UPDATE_REG(0x06, VCOUNT); + DISPSTAT &= 0xFFFD; + UPDATE_REG(0x04, DISPSTAT); + CPUCompareVCOUNT(); + } else { + lcdTicks += 224; + DISPSTAT |= 2; + UPDATE_REG(0x04, DISPSTAT); + if(DISPSTAT & 16) { + IF |= 2; + UPDATE_REG(0x202, IF); + } + } + + if(VCOUNT >= 228) { //Reaching last line + DISPSTAT &= 0xFFFC; + UPDATE_REG(0x04, DISPSTAT); + VCOUNT = 0; + UPDATE_REG(0x06, VCOUNT); + CPUCompareVCOUNT(); + } + } else { + int framesToSkip = systemFrameSkip; + if(speedup) + framesToSkip = 9; // try 6 FPS during speedup + + if(DISPSTAT & 2) { + // if in H-Blank, leave it and move to drawing mode + VCOUNT++; + UPDATE_REG(0x06, VCOUNT); + + lcdTicks += 1008; + DISPSTAT &= 0xFFFD; + if(VCOUNT == 160) { + count++; + systemFrame(); + + if((count % 10) == 0) { + system10Frames(60); + } + if(count == 60) { + u32 time = systemGetClock(); + if(time != lastTime) { + u32 t = 100000/(time - lastTime); + systemShowSpeed(t); + } else + systemShowSpeed(0); + lastTime = time; + count = 0; + } + u32 joy = 0; + // update joystick information + if(systemReadJoypads()) + // read default joystick + joy = systemReadJoypad(-1); + P1 = 0x03FF ^ (joy & 0x3FF); + if(cpuEEPROMSensorEnabled) + systemUpdateMotionSensor(); + UPDATE_REG(0x130, P1); + u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132])); + // this seems wrong, but there are cases where the game + // can enter the stop state without requesting an IRQ from + // the joypad. + if((P1CNT & 0x4000) || stopState) { + u16 p1 = (0x3FF ^ P1) & 0x3FF; + if(P1CNT & 0x8000) { + if(p1 == (P1CNT & 0x3FF)) { + IF |= 0x1000; + UPDATE_REG(0x202, IF); + } + } else { + if(p1 & P1CNT) { + IF |= 0x1000; + UPDATE_REG(0x202, IF); + } + } + } + + u32 ext = (joy >> 10); + // If no (m) code is enabled, apply the cheats at each LCDline + if((cheatsEnabled) && (mastercode==0)) + remainingTicks += cheatsCheckKeys(P1^0x3FF, ext); + speedup = (ext & 1) ? true : false; + capture = (ext & 2) ? true : false; + + if(capture && !capturePrevious) { + captureNumber++; + systemScreenCapture(captureNumber); + } + capturePrevious = capture; + + DISPSTAT |= 1; + DISPSTAT &= 0xFFFD; + UPDATE_REG(0x04, DISPSTAT); + if(DISPSTAT & 0x0008) { + IF |= 1; + UPDATE_REG(0x202, IF); + } + CPUCheckDMA(1, 0x0f); + if(frameCount >= framesToSkip) { + systemDrawScreen(); + frameCount = 0; + } else + frameCount++; + if(systemPauseOnFrame()) + ticks = 0; + } + + UPDATE_REG(0x04, DISPSTAT); + CPUCompareVCOUNT(); + + } else { + if(frameCount >= framesToSkip) + { + (*renderLine)(); + switch(systemColorDepth) { + case 16: + { + u16 *dest = (u16 *)pix + 242 * (VCOUNT+1); + for(int x = 0; x < 240;) { + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; + } + // for filters that read past the screen + *dest++ = 0; + } + break; + case 24: + { + u8 *dest = (u8 *)pix + 240 * VCOUNT * 3; + for(int x = 0; x < 240;) { + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; + dest += 3; + } + } + break; + case 32: + { + u32 *dest = (u32 *)pix + 241 * (VCOUNT+1); + for(int x = 0; x < 240; ) { + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; + } + } + break; + } + } + // entering H-Blank + DISPSTAT |= 2; + UPDATE_REG(0x04, DISPSTAT); + lcdTicks += 224; + CPUCheckDMA(2, 0x0f); + if(DISPSTAT & 16) { + IF |= 2; + UPDATE_REG(0x202, IF); + } + } + } + } + + // we shouldn't be doing sound in stop state, but we loose synchronization + // if sound is disabled, so in stop state, soundTick will just produce + // mute sound + soundTicks -= clockTicks; + if(soundTicks <= 0) { + psoundTickfn(); + soundTicks += SOUND_CLOCK_TICKS; + } + + if(!stopState) { + if(timer0On) { + timer0Ticks -= clockTicks; + if(timer0Ticks <= 0) { + timer0Ticks += (0x10000 - timer0Reload) << timer0ClockReload; + timerOverflow |= 1; + soundTimerOverflow(0); + if(TM0CNT & 0x40) { + IF |= 0x08; + UPDATE_REG(0x202, IF); + } + } + TM0D = 0xFFFF - (timer0Ticks >> timer0ClockReload); + UPDATE_REG(0x100, TM0D); + } + + if(timer1On) { + if(TM1CNT & 4) { + if(timerOverflow & 1) { + TM1D++; + if(TM1D == 0) { + TM1D += timer1Reload; + timerOverflow |= 2; + soundTimerOverflow(1); + if(TM1CNT & 0x40) { + IF |= 0x10; + UPDATE_REG(0x202, IF); + } + } + UPDATE_REG(0x104, TM1D); + } + } else { + timer1Ticks -= clockTicks; + if(timer1Ticks <= 0) { + timer1Ticks += (0x10000 - timer1Reload) << timer1ClockReload; + timerOverflow |= 2; + soundTimerOverflow(1); + if(TM1CNT & 0x40) { + IF |= 0x10; + UPDATE_REG(0x202, IF); + } + } + TM1D = 0xFFFF - (timer1Ticks >> timer1ClockReload); + UPDATE_REG(0x104, TM1D); + } + } + + if(timer2On) { + if(TM2CNT & 4) { + if(timerOverflow & 2) { + TM2D++; + if(TM2D == 0) { + TM2D += timer2Reload; + timerOverflow |= 4; + if(TM2CNT & 0x40) { + IF |= 0x20; + UPDATE_REG(0x202, IF); + } + } + UPDATE_REG(0x108, TM2D); + } + } else { + timer2Ticks -= clockTicks; + if(timer2Ticks <= 0) { + timer2Ticks += (0x10000 - timer2Reload) << timer2ClockReload; + timerOverflow |= 4; + if(TM2CNT & 0x40) { + IF |= 0x20; + UPDATE_REG(0x202, IF); + } + } + TM2D = 0xFFFF - (timer2Ticks >> timer2ClockReload); + UPDATE_REG(0x108, TM2D); + } + } + + if(timer3On) { + if(TM3CNT & 4) { + if(timerOverflow & 4) { + TM3D++; + if(TM3D == 0) { + TM3D += timer3Reload; + if(TM3CNT & 0x40) { + IF |= 0x40; + UPDATE_REG(0x202, IF); + } + } + UPDATE_REG(0x10C, TM3D); + } + } else { + timer3Ticks -= clockTicks; + if(timer3Ticks <= 0) { + timer3Ticks += (0x10000 - timer3Reload) << timer3ClockReload; + if(TM3CNT & 0x40) { + IF |= 0x40; + UPDATE_REG(0x202, IF); + } + } + TM3D = 0xFFFF - (timer3Ticks >> timer3ClockReload); + UPDATE_REG(0x10C, TM3D); + } + } + } + + timerOverflow = 0; + + + +#ifdef PROFILING + profilingTicks -= clockTicks; + if(profilingTicks <= 0) { + profilingTicks += profilingTicksReload; + if(profilSegment) { + profile_segment *seg = profilSegment; + do { + u16 *b = (u16 *)seg->sbuf; + int pc = ((reg[15].I - seg->s_lowpc) * seg->s_scale)/0x10000; + if(pc >= 0 && pc < seg->ssiz) { + b[pc]++; + break; + } + + seg = seg->next; + } while(seg); + } + } +#endif + + ticks -= clockTicks; +#ifdef LINK_EMULATION + if (linkenable) + LinkUpdate(clockTicks); +#endif + cpuNextEvent = CPUUpdateTicks(); + + if(cpuDmaTicksToUpdate > 0) { + if(cpuDmaTicksToUpdate > cpuNextEvent) + clockTicks = cpuNextEvent; + else + clockTicks = cpuDmaTicksToUpdate; + cpuDmaTicksToUpdate -= clockTicks; + if(cpuDmaTicksToUpdate < 0) + cpuDmaTicksToUpdate = 0; + cpuDmaHack = true; + goto updateLoop; + } +#ifdef LINK_EMULATION + if(linkenable) + cpuNextEvent = 1; +#endif + if(IF && (IME & 1) && armIrqEnable) { + int res = IF & IE; + if(stopState) + res &= 0x3080; + if(res) { + if (intState) + { + if (!IRQTicks) + { + CPUInterrupt(); + intState = false; + holdState = false; + stopState = false; + holdType = 0; + } + } + else + { + if (!holdState) + { + intState = true; + IRQTicks=7; + if (cpuNextEvent> IRQTicks) + cpuNextEvent = IRQTicks; + } + else + { + CPUInterrupt(); + holdState = false; + stopState = false; + holdType = 0; + } + } + + // Stops the SWI Ticks emulation if an IRQ is executed + //(to avoid problems with nested IRQ/SWI) + if (SWITicks) + SWITicks = 0; + } + } + + if(remainingTicks > 0) { + if(remainingTicks > cpuNextEvent) + clockTicks = cpuNextEvent; + else + clockTicks = remainingTicks; + remainingTicks -= clockTicks; + if(remainingTicks < 0) + remainingTicks = 0; + goto updateLoop; + } + + if (timerOnOffDelay) + applyTimer(); + + if(cpuNextEvent > ticks) + cpuNextEvent = ticks; + + if(ticks <= 0 || cpuBreakLoop) + break; + + } + } +} + + + +struct EmulatedSystem GBASystem = { + // emuMain + CPULoop, + // emuReset + CPUReset, + // emuCleanUp + CPUCleanUp, + // emuReadBattery + CPUReadBatteryFile, + // emuWriteBattery + CPUWriteBatteryFile, + // emuReadState + CPUReadState, + // emuWriteState + CPUWriteState, + // emuReadMemState + CPUReadMemState, + // emuWriteMemState + CPUWriteMemState, + // emuWritePNG + CPUWritePNGFile, + // emuWriteBMP + CPUWriteBMPFile, + // emuUpdateCPSR + CPUUpdateCPSR, + // emuHasDebugger + true, + // emuCount +#ifdef FINAL_VERSION + 250000 +#else + 5000 +#endif +}; diff --git a/src/agb/GBA.h b/src/agb/GBA.h index a1c04a00..b173a6ee 100644 --- a/src/agb/GBA.h +++ b/src/agb/GBA.h @@ -1,160 +1,160 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef VBA_GBA_H -#define VBA_GBA_H - -#include "../System.h" - -#define SAVE_GAME_VERSION_1 1 -#define SAVE_GAME_VERSION_2 2 -#define SAVE_GAME_VERSION_3 3 -#define SAVE_GAME_VERSION_4 4 -#define SAVE_GAME_VERSION_5 5 -#define SAVE_GAME_VERSION_6 6 -#define SAVE_GAME_VERSION_7 7 -#define SAVE_GAME_VERSION_8 8 -#define SAVE_GAME_VERSION_9 9 -#define SAVE_GAME_VERSION_10 10 -#define SAVE_GAME_VERSION SAVE_GAME_VERSION_10 - -typedef struct { - u8 *address; - u32 mask; -} memoryMap; - -typedef union { - struct { -#ifdef WORDS_BIGENDIAN - u8 B3; - u8 B2; - u8 B1; - u8 B0; -#else - u8 B0; - u8 B1; - u8 B2; - u8 B3; -#endif - } B; - struct { -#ifdef WORDS_BIGENDIAN - u16 W1; - u16 W0; -#else - u16 W0; - u16 W1; -#endif - } W; -#ifdef WORDS_BIGENDIAN - volatile u32 I; -#else - u32 I; -#endif -} reg_pair; - -#ifndef NO_GBA_MAP -extern memoryMap map[256]; -#endif - -extern reg_pair reg[45]; -extern u8 biosProtected[4]; - -extern bool N_FLAG; -extern bool Z_FLAG; -extern bool C_FLAG; -extern bool V_FLAG; -extern bool armIrqEnable; -extern bool armState; -extern int armMode; -extern void (*cpuSaveGameFunc)(u32,u8); - -#ifdef BKPT_SUPPORT -extern u8 freezeWorkRAM[0x40000]; -extern u8 freezeInternalRAM[0x8000]; -extern u8 freezeVRAM[0x18000]; -extern u8 freezeOAM[0x400]; -extern u8 freezePRAM[0x400]; -extern bool debugger_last; -extern int oldreg[17]; -extern char oldbuffer[10]; -#endif - -extern bool CPUReadGSASnapshot(const char *); -extern bool CPUWriteGSASnapshot(const char *, const char *, const char *, const char *); -extern bool CPUWriteBatteryFile(const char *); -extern bool CPUReadBatteryFile(const char *); -extern bool CPUExportEepromFile(const char *); -extern bool CPUImportEepromFile(const char *); -extern bool CPUWritePNGFile(const char *); -extern bool CPUWriteBMPFile(const char *); -extern void CPUCleanUp(); -extern void CPUUpdateRender(); -extern void CPUUpdateRenderBuffers(bool); -extern bool CPUReadMemState(char *, int); -extern bool CPUReadState(const char *); -extern bool CPUWriteMemState(char *, int); -extern bool CPUWriteState(const char *); -extern int CPULoadRom(const char *); -extern void doMirroring(bool); -extern void CPUUpdateRegister(u32, u16); -extern void applyTimer (); -extern void CPUInit(const char *,bool); -extern void CPUReset(); -extern void CPULoop(int); -extern void CPUCheckDMA(int,int); -extern bool CPUIsGBAImage(const char *); -extern bool CPUIsZipFile(const char *); -#ifdef PROFILING -#include "prof/prof.h" -extern void cpuProfil(profile_segment *seg); -extern void cpuEnableProfiling(int hz); -#endif - -extern struct EmulatedSystem GBASystem; - -#define R13_IRQ 18 -#define R14_IRQ 19 -#define SPSR_IRQ 20 -#define R13_USR 26 -#define R14_USR 27 -#define R13_SVC 28 -#define R14_SVC 29 -#define SPSR_SVC 30 -#define R13_ABT 31 -#define R14_ABT 32 -#define SPSR_ABT 33 -#define R13_UND 34 -#define R14_UND 35 -#define SPSR_UND 36 -#define R8_FIQ 37 -#define R9_FIQ 38 -#define R10_FIQ 39 -#define R11_FIQ 40 -#define R12_FIQ 41 -#define R13_FIQ 42 -#define R14_FIQ 43 -#define SPSR_FIQ 44 - -#include "../Cheats.h" -#include "../Globals.h" -#include "../EEprom.h" -#include "../Flash.h" - -#endif //VBA_GBA_H +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef VBA_GBA_H +#define VBA_GBA_H + +#include "../System.h" + +#define SAVE_GAME_VERSION_1 1 +#define SAVE_GAME_VERSION_2 2 +#define SAVE_GAME_VERSION_3 3 +#define SAVE_GAME_VERSION_4 4 +#define SAVE_GAME_VERSION_5 5 +#define SAVE_GAME_VERSION_6 6 +#define SAVE_GAME_VERSION_7 7 +#define SAVE_GAME_VERSION_8 8 +#define SAVE_GAME_VERSION_9 9 +#define SAVE_GAME_VERSION_10 10 +#define SAVE_GAME_VERSION SAVE_GAME_VERSION_10 + +typedef struct { + u8 *address; + u32 mask; +} memoryMap; + +typedef union { + struct { +#ifdef WORDS_BIGENDIAN + u8 B3; + u8 B2; + u8 B1; + u8 B0; +#else + u8 B0; + u8 B1; + u8 B2; + u8 B3; +#endif + } B; + struct { +#ifdef WORDS_BIGENDIAN + u16 W1; + u16 W0; +#else + u16 W0; + u16 W1; +#endif + } W; +#ifdef WORDS_BIGENDIAN + volatile u32 I; +#else + u32 I; +#endif +} reg_pair; + +#ifndef NO_GBA_MAP +extern memoryMap map[256]; +#endif + +extern reg_pair reg[45]; +extern u8 biosProtected[4]; + +extern bool N_FLAG; +extern bool Z_FLAG; +extern bool C_FLAG; +extern bool V_FLAG; +extern bool armIrqEnable; +extern bool armState; +extern int armMode; +extern void (*cpuSaveGameFunc)(u32,u8); + +#ifdef BKPT_SUPPORT +extern u8 freezeWorkRAM[0x40000]; +extern u8 freezeInternalRAM[0x8000]; +extern u8 freezeVRAM[0x18000]; +extern u8 freezeOAM[0x400]; +extern u8 freezePRAM[0x400]; +extern bool debugger_last; +extern int oldreg[17]; +extern char oldbuffer[10]; +#endif + +extern bool CPUReadGSASnapshot(const char *); +extern bool CPUWriteGSASnapshot(const char *, const char *, const char *, const char *); +extern bool CPUWriteBatteryFile(const char *); +extern bool CPUReadBatteryFile(const char *); +extern bool CPUExportEepromFile(const char *); +extern bool CPUImportEepromFile(const char *); +extern bool CPUWritePNGFile(const char *); +extern bool CPUWriteBMPFile(const char *); +extern void CPUCleanUp(); +extern void CPUUpdateRender(); +extern void CPUUpdateRenderBuffers(bool); +extern bool CPUReadMemState(char *, int); +extern bool CPUReadState(const char *); +extern bool CPUWriteMemState(char *, int); +extern bool CPUWriteState(const char *); +extern int CPULoadRom(const char *); +extern void doMirroring(bool); +extern void CPUUpdateRegister(u32, u16); +extern void applyTimer (); +extern void CPUInit(const char *,bool); +extern void CPUReset(); +extern void CPULoop(int); +extern void CPUCheckDMA(int,int); +extern bool CPUIsGBAImage(const char *); +extern bool CPUIsZipFile(const char *); +#ifdef PROFILING +#include "prof/prof.h" +extern void cpuProfil(profile_segment *seg); +extern void cpuEnableProfiling(int hz); +#endif + +extern struct EmulatedSystem GBASystem; + +#define R13_IRQ 18 +#define R14_IRQ 19 +#define SPSR_IRQ 20 +#define R13_USR 26 +#define R14_USR 27 +#define R13_SVC 28 +#define R14_SVC 29 +#define SPSR_SVC 30 +#define R13_ABT 31 +#define R14_ABT 32 +#define SPSR_ABT 33 +#define R13_UND 34 +#define R14_UND 35 +#define SPSR_UND 36 +#define R8_FIQ 37 +#define R9_FIQ 38 +#define R10_FIQ 39 +#define R11_FIQ 40 +#define R12_FIQ 41 +#define R13_FIQ 42 +#define R14_FIQ 43 +#define SPSR_FIQ 44 + +#include "../Cheats.h" +#include "../Globals.h" +#include "../EEprom.h" +#include "../Flash.h" + +#endif //VBA_GBA_H diff --git a/src/agb/GBAGfx.cpp b/src/agb/GBAGfx.cpp index 24c73f68..e8284c4d 100644 --- a/src/agb/GBAGfx.cpp +++ b/src/agb/GBAGfx.cpp @@ -1,47 +1,47 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include "../System.h" - -int coeff[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; - -u32 line0[240]; -u32 line1[240]; -u32 line2[240]; -u32 line3[240]; -u32 lineOBJ[240]; -u32 lineOBJWin[240]; -u32 lineMix[240]; -bool gfxInWin0[240]; -bool gfxInWin1[240]; -int lineOBJpixleft[128]; - -int gfxBG2Changed = 0; -int gfxBG3Changed = 0; - -int gfxBG2X = 0; -int gfxBG2Y = 0; -int gfxBG2LastX = 0; -int gfxBG2LastY = 0; -int gfxBG3X = 0; -int gfxBG3Y = 0; -int gfxBG3LastX = 0; -int gfxBG3LastY = 0; -int gfxLastVCOUNT = 0; +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "../System.h" + +int coeff[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; + +u32 line0[240]; +u32 line1[240]; +u32 line2[240]; +u32 line3[240]; +u32 lineOBJ[240]; +u32 lineOBJWin[240]; +u32 lineMix[240]; +bool gfxInWin0[240]; +bool gfxInWin1[240]; +int lineOBJpixleft[128]; + +int gfxBG2Changed = 0; +int gfxBG3Changed = 0; + +int gfxBG2X = 0; +int gfxBG2Y = 0; +int gfxBG2LastX = 0; +int gfxBG2LastY = 0; +int gfxBG3X = 0; +int gfxBG3Y = 0; +int gfxBG3LastX = 0; +int gfxBG3LastY = 0; +int gfxLastVCOUNT = 0; diff --git a/src/agb/GBAGfx.h b/src/agb/GBAGfx.h index 73f1dd46..79285ece 100644 --- a/src/agb/GBAGfx.h +++ b/src/agb/GBAGfx.h @@ -1,1601 +1,1601 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005 Forgotten and the VBA development team -// Copyright (C) 2008 VBA-M development team -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef VBA_GFX_H -#define VBA_GFX_H - -#include "GBA.h" -#include "../Globals.h" - -#include "../Port.h" - -//#define SPRITE_DEBUG - -static void gfxDrawTextScreen(u16, u16, u16, u32 *); -static void gfxDrawRotScreen(u16, - u16, u16, - u16, u16, - u16, u16, - u16, u16, - int&, int&, - int, - u32*); -static void gfxDrawRotScreen16Bit(u16, - u16, u16, - u16, u16, - u16, u16, - u16, u16, - int&, int&, - int, - u32*); -static void gfxDrawRotScreen256(u16, - u16, u16, - u16, u16, - u16, u16, - u16, u16, - int&, int&, - int, - u32*); -static void gfxDrawRotScreen16Bit160(u16, - u16, u16, - u16, u16, - u16, u16, - u16, u16, - int&, int&, - int, - u32*); -static void gfxDrawSprites(u32 *); -static void gfxIncreaseBrightness(u32 *line, int coeff); -static void gfxDecreaseBrightness(u32 *line, int coeff); -static void gfxAlphaBlend(u32 *ta, u32 *tb, int ca, int cb); - -void mode0RenderLine(); -void mode0RenderLineNoWindow(); -void mode0RenderLineAll(); - -void mode1RenderLine(); -void mode1RenderLineNoWindow(); -void mode1RenderLineAll(); - -void mode2RenderLine(); -void mode2RenderLineNoWindow(); -void mode2RenderLineAll(); - -void mode3RenderLine(); -void mode3RenderLineNoWindow(); -void mode3RenderLineAll(); - -void mode4RenderLine(); -void mode4RenderLineNoWindow(); -void mode4RenderLineAll(); - -void mode5RenderLine(); -void mode5RenderLineNoWindow(); -void mode5RenderLineAll(); - -extern int coeff[32]; -extern u32 line0[240]; -extern u32 line1[240]; -extern u32 line2[240]; -extern u32 line3[240]; -extern u32 lineOBJ[240]; -extern u32 lineOBJWin[240]; -extern u32 lineMix[240]; -extern bool gfxInWin0[240]; -extern bool gfxInWin1[240]; -extern int lineOBJpixleft[128]; - -extern int gfxBG2Changed; -extern int gfxBG3Changed; - -extern int gfxBG2X; -extern int gfxBG2Y; -extern int gfxBG2LastX; -extern int gfxBG2LastY; -extern int gfxBG3X; -extern int gfxBG3Y; -extern int gfxBG3LastX; -extern int gfxBG3LastY; -extern int gfxLastVCOUNT; - -static inline void gfxClearArray(u32 *array) -{ - for(int i = 0; i < 240; i++) { - *array++ = 0x80000000; - } -} - -static inline void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs, - u32 *line) -{ - u16 *palette = (u16 *)paletteRAM; - u8 *charBase = &vram[((control >> 2) & 0x03) * 0x4000]; - u16 *screenBase = (u16 *)&vram[((control >> 8) & 0x1f) * 0x800]; - u32 prio = ((control & 3)<<25) + 0x1000000; - int sizeX = 256; - int sizeY = 256; - switch((control >> 14) & 3) { - case 0: - break; - case 1: - sizeX = 512; - break; - case 2: - sizeY = 512; - break; - case 3: - sizeX = 512; - sizeY = 512; - break; - } - - int maskX = sizeX-1; - int maskY = sizeY-1; - - bool mosaicOn = (control & 0x40) ? true : false; - - int xxx = hofs & maskX; - int yyy = (vofs + VCOUNT) & maskY; - int mosaicX = (MOSAIC & 0x000F)+1; - int mosaicY = ((MOSAIC & 0x00F0)>>4)+1; - - if(mosaicOn) { - if((VCOUNT % mosaicY) != 0) { - mosaicY = VCOUNT - (VCOUNT % mosaicY); - yyy = (vofs + mosaicY) & maskY; - } - } - - if(yyy > 255 && sizeY > 256) { - yyy &= 255; - screenBase += 0x400; - if(sizeX > 256) - screenBase += 0x400; - } - - int yshift = ((yyy>>3)<<5); - if((control) & 0x80) { - u16 *screenSource = screenBase + 0x400 * (xxx>>8) + ((xxx & 255)>>3) + yshift; - for(int x = 0; x < 240; x++) { - u16 data = READ16LE(screenSource); - - int tile = data & 0x3FF; - int tileX = (xxx & 7); - int tileY = yyy & 7; - - if(tileX == 7) - screenSource++; - - if(data & 0x0400) - tileX = 7 - tileX; - if(data & 0x0800) - tileY = 7 - tileY; - - u8 color = charBase[tile * 64 + tileY * 8 + tileX]; - - line[x] = color ? (READ16LE(&palette[color]) | prio): 0x80000000; - - xxx++; - if(xxx == 256) { - if(sizeX > 256) - screenSource = screenBase + 0x400 + yshift; - else { - screenSource = screenBase + yshift; - xxx = 0; - } - } else if(xxx >= sizeX) { - xxx = 0; - screenSource = screenBase + yshift; - } - } - } else { - u16 *screenSource = screenBase + 0x400*(xxx>>8)+((xxx&255)>>3) + - yshift; - for(int x = 0; x < 240; x++) { - u16 data = READ16LE(screenSource); - - int tile = data & 0x3FF; - int tileX = (xxx & 7); - int tileY = yyy & 7; - - if(tileX == 7) - screenSource++; - - if(data & 0x0400) - tileX = 7 - tileX; - if(data & 0x0800) - tileY = 7 - tileY; - - u8 color = charBase[(tile<<5) + (tileY<<2) + (tileX>>1)]; - - if(tileX & 1) { - color = (color >> 4); - } else { - color &= 0x0F; - } - - int pal = (data>>8) & 0xF0; - line[x] = color ? (READ16LE(&palette[pal + color])|prio): 0x80000000; - - xxx++; - if(xxx == 256) { - if(sizeX > 256) - screenSource = screenBase + 0x400 + yshift; - else { - screenSource = screenBase + yshift; - xxx = 0; - } - } else if(xxx >= sizeX) { - xxx = 0; - screenSource = screenBase + yshift; - } - } - } - if(mosaicOn) { - if(mosaicX > 1) { - int m = 1; - for(int i = 0; i < 239; i++) { - line[i+1] = line[i]; - m++; - if(m == mosaicX) { - m = 1; - i++; - } - } - } - } -} - -static inline void gfxDrawRotScreen(u16 control, - u16 x_l, u16 x_h, - u16 y_l, u16 y_h, - u16 pa, u16 pb, - u16 pc, u16 pd, - int& currentX, int& currentY, - int changed, - u32 *line) -{ - u16 *palette = (u16 *)paletteRAM; - u8 *charBase = &vram[((control >> 2) & 0x03) * 0x4000]; - u8 *screenBase = (u8 *)&vram[((control >> 8) & 0x1f) * 0x800]; - int prio = ((control & 3) << 25) + 0x1000000; - - int sizeX = 128; - int sizeY = 128; - switch((control >> 14) & 3) { - case 0: - break; - case 1: - sizeX = sizeY = 256; - break; - case 2: - sizeX = sizeY = 512; - break; - case 3: - sizeX = sizeY = 1024; - break; - } - - int maskX = sizeX-1; - int maskY = sizeY-1; - - int yshift = ((control >> 14) & 3)+4; - - int dx = pa & 0x7FFF; - if(pa & 0x8000) - dx |= 0xFFFF8000; - int dmx = pb & 0x7FFF; - if(pb & 0x8000) - dmx |= 0xFFFF8000; - int dy = pc & 0x7FFF; - if(pc & 0x8000) - dy |= 0xFFFF8000; - int dmy = pd & 0x7FFF; - if(pd & 0x8000) - dmy |= 0xFFFF8000; - - if(VCOUNT == 0) - changed = 3; - - if(changed & 1) { - currentX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - currentX |= 0xF8000000; - } else { - currentX += dmx; - } - - if(changed & 2) { - currentY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - currentY |= 0xF8000000; - } else { - currentY += dmy; - } - - int realX = currentX; - int realY = currentY; - - if(control & 0x40) { - int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; - int y = (VCOUNT % mosaicY); - realX -= y*dmx; - realY -= y*dmy; - } - - if(control & 0x2000) { - for(int x = 0; x < 240; x++) { - int xxx = (realX >> 8) & maskX; - int yyy = (realY >> 8) & maskY; - - int tile = screenBase[(xxx>>3) + ((yyy>>3)<> 8); - int yyy = (realY >> 8); - - if(xxx < 0 || - yyy < 0 || - xxx >= sizeX || - yyy >= sizeY) { - line[x] = 0x80000000; - } else { - int tile = screenBase[(xxx>>3) + ((yyy>>3)< 1) { - int m = 1; - for(int i = 0; i < 239; i++) { - line[i+1] = line[i]; - m++; - if(m == mosaicX) { - m = 1; - i++; - } - } - } - } -} - -static inline void gfxDrawRotScreen16Bit(u16 control, - u16 x_l, u16 x_h, - u16 y_l, u16 y_h, - u16 pa, u16 pb, - u16 pc, u16 pd, - int& currentX, int& currentY, - int changed, - u32 *line) -{ - u16 *screenBase = (u16 *)&vram[0]; - int prio = ((control & 3) << 25) + 0x1000000; - int sizeX = 240; - int sizeY = 160; - - int startX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - startX |= 0xF8000000; - int startY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - startY |= 0xF8000000; - - int dx = pa & 0x7FFF; - if(pa & 0x8000) - dx |= 0xFFFF8000; - int dmx = pb & 0x7FFF; - if(pb & 0x8000) - dmx |= 0xFFFF8000; - int dy = pc & 0x7FFF; - if(pc & 0x8000) - dy |= 0xFFFF8000; - int dmy = pd & 0x7FFF; - if(pd & 0x8000) - dmy |= 0xFFFF8000; - - if(VCOUNT == 0) - changed = 3; - - if(changed & 1) { - currentX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - currentX |= 0xF8000000; - } else - currentX += dmx; - - if(changed & 2) { - currentY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - currentY |= 0xF8000000; - } else { - currentY += dmy; - } - - int realX = currentX; - int realY = currentY; - - if(control & 0x40) { - int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; - int y = (VCOUNT % mosaicY); - realX -= y*dmx; - realY -= y*dmy; - } - - int xxx = (realX >> 8); - int yyy = (realY >> 8); - - for(int x = 0; x < 240; x++) { - if(xxx < 0 || - yyy < 0 || - xxx >= sizeX || - yyy >= sizeY) { - line[x] = 0x80000000; - } else { - line[x] = (READ16LE(&screenBase[yyy * sizeX + xxx]) | prio); - } - realX += dx; - realY += dy; - - xxx = (realX >> 8); - yyy = (realY >> 8); - } - - if(control & 0x40) { - int mosaicX = (MOSAIC & 0xF) + 1; - if(mosaicX > 1) { - int m = 1; - for(int i = 0; i < 239; i++) { - line[i+1] = line[i]; - m++; - if(m == mosaicX) { - m = 1; - i++; - } - } - } - } -} - -static inline void gfxDrawRotScreen256(u16 control, - u16 x_l, u16 x_h, - u16 y_l, u16 y_h, - u16 pa, u16 pb, - u16 pc, u16 pd, - int ¤tX, int& currentY, - int changed, - u32 *line) -{ - u16 *palette = (u16 *)paletteRAM; - u8 *screenBase = (DISPCNT & 0x0010) ? &vram[0xA000] : &vram[0x0000]; - int prio = ((control & 3) << 25) + 0x1000000; - int sizeX = 240; - int sizeY = 160; - - int startX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - startX |= 0xF8000000; - int startY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - startY |= 0xF8000000; - - int dx = pa & 0x7FFF; - if(pa & 0x8000) - dx |= 0xFFFF8000; - int dmx = pb & 0x7FFF; - if(pb & 0x8000) - dmx |= 0xFFFF8000; - int dy = pc & 0x7FFF; - if(pc & 0x8000) - dy |= 0xFFFF8000; - int dmy = pd & 0x7FFF; - if(pd & 0x8000) - dmy |= 0xFFFF8000; - - if(VCOUNT == 0) - changed = 3; - - if(changed & 1) { - currentX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - currentX |= 0xF8000000; - } else { - currentX += dmx; - } - - if(changed & 2) { - currentY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - currentY |= 0xF8000000; - } else { - currentY += dmy; - } - - int realX = currentX; - int realY = currentY; - - if(control & 0x40) { - int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; - int y = VCOUNT - (VCOUNT % mosaicY); - realX = startX + y*dmx; - realY = startY + y*dmy; - } - - int xxx = (realX >> 8); - int yyy = (realY >> 8); - - for(int x = 0; x < 240; x++) { - if(xxx < 0 || - yyy < 0 || - xxx >= sizeX || - yyy >= sizeY) { - line[x] = 0x80000000; - } else { - u8 color = screenBase[yyy * 240 + xxx]; - - line[x] = color ? (READ16LE(&palette[color])|prio): 0x80000000; - } - realX += dx; - realY += dy; - - xxx = (realX >> 8); - yyy = (realY >> 8); - } - - if(control & 0x40) { - int mosaicX = (MOSAIC & 0xF) + 1; - if(mosaicX > 1) { - int m = 1; - for(int i = 0; i < 239; i++) { - line[i+1] = line[i]; - m++; - if(m == mosaicX) { - m = 1; - i++; - } - } - } - } -} - -static inline void gfxDrawRotScreen16Bit160(u16 control, - u16 x_l, u16 x_h, - u16 y_l, u16 y_h, - u16 pa, u16 pb, - u16 pc, u16 pd, - int& currentX, int& currentY, - int changed, - u32 *line) -{ - u16 *screenBase = (DISPCNT & 0x0010) ? (u16 *)&vram[0xa000] : - (u16 *)&vram[0]; - int prio = ((control & 3) << 25) + 0x1000000; - int sizeX = 160; - int sizeY = 128; - - int startX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - startX |= 0xF8000000; - int startY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - startY |= 0xF8000000; - - int dx = pa & 0x7FFF; - if(pa & 0x8000) - dx |= 0xFFFF8000; - int dmx = pb & 0x7FFF; - if(pb & 0x8000) - dmx |= 0xFFFF8000; - int dy = pc & 0x7FFF; - if(pc & 0x8000) - dy |= 0xFFFF8000; - int dmy = pd & 0x7FFF; - if(pd & 0x8000) - dmy |= 0xFFFF8000; - - if(VCOUNT == 0) - changed = 3; - - if(changed & 1) { - currentX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - currentX |= 0xF8000000; - } else { - currentX += dmx; - } - - if(changed & 2) { - currentY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - currentY |= 0xF8000000; - } else { - currentY += dmy; - } - - int realX = currentX; - int realY = currentY; - - if(control & 0x40) { - int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; - int y = VCOUNT - (VCOUNT % mosaicY); - realX = startX + y*dmx; - realY = startY + y*dmy; - } - - int xxx = (realX >> 8); - int yyy = (realY >> 8); - - for(int x = 0; x < 240; x++) { - if(xxx < 0 || - yyy < 0 || - xxx >= sizeX || - yyy >= sizeY) { - line[x] = 0x80000000; - } else { - line[x] = (READ16LE(&screenBase[yyy * sizeX + xxx]) | prio); - } - realX += dx; - realY += dy; - - xxx = (realX >> 8); - yyy = (realY >> 8); - } - - if(control & 0x40) { - int mosaicX = (MOSAIC & 0xF) + 1; - if(mosaicX > 1) { - int m = 1; - for(int i = 0; i < 239; i++) { - line[i+1] = line[i]; - m++; - if(m == mosaicX) { - m = 1; - i++; - } - } - } - } -} - -static inline void gfxDrawSprites(u32 *lineOBJ) -{ - // lineOBJpix is used to keep track of the drawn OBJs - // and to stop drawing them if the 'maximum number of OBJ per line' - // has been reached. - int lineOBJpix = (DISPCNT & 0x20) ? 954 : 1226; - int m=0; - gfxClearArray(lineOBJ); - if(layerEnable & 0x1000) { - u16 *sprites = (u16 *)oam; - u16 *spritePalette = &((u16 *)paletteRAM)[256]; - int mosaicY = ((MOSAIC & 0xF000)>>12) + 1; - int mosaicX = ((MOSAIC & 0xF00)>>8) + 1; - for(int x = 0; x < 128 ; x++) { - u16 a0 = READ16LE(sprites++); - u16 a1 = READ16LE(sprites++); - u16 a2 = READ16LE(sprites++); - sprites++; - - lineOBJpixleft[x]=lineOBJpix; - - lineOBJpix-=2; - if (lineOBJpix<=0) - continue; - - if ((a0 & 0x0c00) == 0x0c00) - a0 &=0xF3FF; - - if ((a0>>14) == 3) - { - a0 &= 0x3FFF; - a1 &= 0x3FFF; - } - - int sizeX = 8<<(a1>>14); - int sizeY = sizeX; - - if ((a0>>14) & 1) - { - if (sizeX<32) - sizeX<<=1; - if (sizeY>8) - sizeY>>=1; - } - else if ((a0>>14) & 2) - { - if (sizeX>8) - sizeX>>=1; - if (sizeY<32) - sizeY<<=1; - } - -#ifdef SPRITE_DEBUG - int maskX = sizeX-1; - int maskY = sizeY-1; -#endif - - int sy = (a0 & 255); - int sx = (a1 & 0x1FF); - - // computes ticks used by OBJ-WIN if OBJWIN is enabled - if (((a0 & 0x0c00) == 0x0800) && (layerEnable & 0x8000)) - { - if ((a0 & 0x0300) == 0x0300) - { - sizeX<<=1; - sizeY<<=1; - } - if((sy+sizeY) > 256) - sy -= 256; - if ((sx+sizeX)> 512) - sx-=512; - if (sx<0) - { - sizeX+=sx; - sx = 0; - } - else if ((sx+sizeX)>240) - sizeX=240-sx; - if ((VCOUNT>=sy) && (VCOUNT 256) - sy -= 256; - int t = VCOUNT - sy; - if((t >= 0) && (t < fieldY)) { - int startpix = 0; - if ((sx+fieldX)> 512) - { - startpix=512-sx; - } - if (lineOBJpix>0) - if((sx < 240) || startpix) { - lineOBJpix-=8; - // int t2 = t - (fieldY >> 1); - int rot = (a1 >> 9) & 0x1F; - u16 *OAM = (u16 *)oam; - int dx = READ16LE(&OAM[3 + (rot << 4)]); - if(dx & 0x8000) - dx |= 0xFFFF8000; - int dmx = READ16LE(&OAM[7 + (rot << 4)]); - if(dmx & 0x8000) - dmx |= 0xFFFF8000; - int dy = READ16LE(&OAM[11 + (rot << 4)]); - if(dy & 0x8000) - dy |= 0xFFFF8000; - int dmy = READ16LE(&OAM[15 + (rot << 4)]); - if(dmy & 0x8000) - dmy |= 0xFFFF8000; - - if(a0 & 0x1000) { - t -= (t % mosaicY); - } - - int realX = ((sizeX) << 7) - (fieldX >> 1)*dx - (fieldY>>1)*dmx - + t * dmx; - int realY = ((sizeY) << 7) - (fieldX >> 1)*dy - (fieldY>>1)*dmy - + t * dmy; - - u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - - if(a0 & 0x2000) { - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - int inc = 32; - if(DISPCNT & 0x40) - inc = sizeX >> 2; - else - c &= 0x3FE; - for(int x = 0; x < fieldX; x++) { - if (x >= startpix) - lineOBJpix-=2; - if (lineOBJpix<0) - continue; - int xxx = realX >> 8; - int yyy = realY >> 8; - - if(xxx < 0 || xxx >= sizeX || - yyy < 0 || yyy >= sizeY || - sx >= 240); - else { - u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) - + ((yyy & 7)<<3) + ((xxx >> 3)<<6) + - (xxx & 7))&0x7FFF)]; - if ((color==0) && (((prio >> 25)&3) < - ((lineOBJ[sx]>>25)&3))) { - lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { - lineOBJ[sx] = READ16LE(&spritePalette[color]) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - - if (a0 & 0x1000) { - m++; - if (m==mosaicX) - m=0; - } -#ifdef SPRITE_DEBUG - if(t == 0 || t == maskY || x == 0 || x == maskX) - lineOBJ[sx] = 0x001F; -#endif - } - sx = (sx+1)&511; - realX += dx; - realY += dy; - } - } else { - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - if(DISPCNT & 0x40) - inc = sizeX >> 3; - int palette = (a2 >> 8) & 0xF0; - for(int x = 0; x < fieldX; x++) { - if (x >= startpix) - lineOBJpix-=2; - if (lineOBJpix<0) - continue; - int xxx = realX >> 8; - int yyy = realY >> 8; - if(xxx < 0 || xxx >= sizeX || - yyy < 0 || yyy >= sizeY || - sx >= 240); - else { - u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) - + ((yyy & 7)<<2) + ((xxx >> 3)<<5) + - ((xxx & 7)>>1))&0x7FFF)]; - if(xxx & 1) - color >>= 4; - else - color &= 0x0F; - - if ((color==0) && (((prio >> 25)&3) < - ((lineOBJ[sx]>>25)&3))) { - lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { - lineOBJ[sx] = READ16LE(&spritePalette[palette+color]) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - } - if((a0 & 0x1000) && m) { - m++; - if (m==mosaicX) - m=0; - } - -#ifdef SPRITE_DEBUG - if(t == 0 || t == maskY || x == 0 || x == maskX) - lineOBJ[sx] = 0x001F; -#endif - sx = (sx+1)&511; - realX += dx; - realY += dy; - - } - } - } - } - } else { - if(sy+sizeY > 256) - sy -= 256; - int t = VCOUNT - sy; - if((t >= 0) && (t < sizeY)) { - int startpix = 0; - if ((sx+sizeX)> 512) - { - startpix=512-sx; - } - if((sx < 240) || startpix) { - lineOBJpix+=2; - if(a0 & 0x2000) { - if(a1 & 0x2000) - t = sizeY - t - 1; - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - if(DISPCNT & 0x40) { - inc = sizeX >> 2; - } else { - c &= 0x3FE; - } - int xxx = 0; - if(a1 & 0x1000) - xxx = sizeX-1; - - if(a0 & 0x1000) { - t -= (t % mosaicY); - } - - int address = 0x10000 + ((((c+ (t>>3) * inc) << 5) - + ((t & 7) << 3) + ((xxx>>3)<<6) + (xxx & 7)) & 0x7FFF); - - if(a1 & 0x1000) - xxx = 7; - u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - - for(int xx = 0; xx < sizeX; xx++) { - if (xx >= startpix) - lineOBJpix--; - if (lineOBJpix<0) - continue; - if(sx < 240) { - u8 color = vram[address]; - if ((color==0) && (((prio >> 25)&3) < - ((lineOBJ[sx]>>25)&3))) { - lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { - lineOBJ[sx] = READ16LE(&spritePalette[color]) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - - if (a0 & 0x1000) { - m++; - if (m==mosaicX) - m=0; - } - -#ifdef SPRITE_DEBUG - if(t == 0 || t == maskY || xx == 0 || xx == maskX) - lineOBJ[sx] = 0x001F; -#endif - } - - sx = (sx+1) & 511; - if(a1 & 0x1000) { - xxx--; - address--; - if(xxx == -1) { - address -= 56; - xxx = 7; - } - if(address < 0x10000) - address += 0x8000; - } else { - xxx++; - address++; - if(xxx == 8) { - address += 56; - xxx = 0; - } - if(address > 0x17fff) - address -= 0x8000; - } - } - } else { - if(a1 & 0x2000) - t = sizeY - t - 1; - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - if(DISPCNT & 0x40) { - inc = sizeX >> 3; - } - int xxx = 0; - if(a1 & 0x1000) - xxx = sizeX - 1; - - if(a0 & 0x1000) { - t -= (t % mosaicY); - } - - int address = 0x10000 + ((((c + (t>>3) * inc)<<5) - + ((t & 7)<<2) + ((xxx>>3)<<5) + ((xxx & 7) >> 1))&0x7FFF); - u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - int palette = (a2 >> 8) & 0xF0; - if(a1 & 0x1000) { - xxx = 7; - for(int xx = sizeX - 1; xx >= 0; xx--) { - if (xx >= startpix) - lineOBJpix--; - if (lineOBJpix<0) - continue; - if(sx < 240) { - u8 color = vram[address]; - if(xx & 1) { - color = (color >> 4); - } else - color &= 0x0F; - - if ((color==0) && (((prio >> 25)&3) < - ((lineOBJ[sx]>>25)&3))) { - lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { - lineOBJ[sx] = READ16LE(&spritePalette[palette + color]) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - } - if (a0 & 0x1000) { - m++; - if (m==mosaicX) - m=0; - } -#ifdef SPRITE_DEBUG - if(t == 0 || t == maskY || xx == 0 || xx == maskX) - lineOBJ[sx] = 0x001F; -#endif - sx = (sx+1) & 511; - xxx--; - if(!(xx & 1)) - address--; - if(xxx == -1) { - xxx = 7; - address -= 28; - } - if(address < 0x10000) - address += 0x8000; - } - } else { - for(int xx = 0; xx < sizeX; xx++) { - if (xx >= startpix) - lineOBJpix--; - if (lineOBJpix<0) - continue; - if(sx < 240) { - u8 color = vram[address]; - if(xx & 1) { - color = (color >> 4); - } else - color &= 0x0F; - - if ((color==0) && (((prio >> 25)&3) < - ((lineOBJ[sx]>>25)&3))) { - lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { - lineOBJ[sx] = READ16LE(&spritePalette[palette + color]) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - - } - } - if (a0 & 0x1000) { - m++; - if (m==mosaicX) - m=0; - } -#ifdef SPRITE_DEBUG - if(t == 0 || t == maskY || xx == 0 || xx == maskX) - lineOBJ[sx] = 0x001F; -#endif - sx = (sx+1) & 511; - xxx++; - if(xx & 1) - address++; - if(xxx == 8) { - address += 28; - xxx = 0; - } - if(address > 0x17fff) - address -= 0x8000; - } - } - } - } - } - } - } - } -} - -static inline void gfxDrawOBJWin(u32 *lineOBJWin) -{ - gfxClearArray(lineOBJWin); - if((layerEnable & 0x9000) == 0x9000) { - u16 *sprites = (u16 *)oam; - // u16 *spritePalette = &((u16 *)paletteRAM)[256]; - for(int x = 0; x < 128 ; x++) { - int lineOBJpix = lineOBJpixleft[x]; - u16 a0 = READ16LE(sprites++); - u16 a1 = READ16LE(sprites++); - u16 a2 = READ16LE(sprites++); - sprites++; - - if (lineOBJpix<=0) - continue; - - // ignores non OBJ-WIN and disabled OBJ-WIN - if(((a0 & 0x0c00) != 0x0800) || ((a0 & 0x0300) == 0x0200)) - continue; - - if ((a0 & 0x0c00) == 0x0c00) - a0 &=0xF3FF; - - if ((a0>>14) == 3) - { - a0 &= 0x3FFF; - a1 &= 0x3FFF; - } - - int sizeX = 8<<(a1>>14); - int sizeY = sizeX; - - if ((a0>>14) & 1) - { - if (sizeX<32) - sizeX<<=1; - if (sizeY>8) - sizeY>>=1; - } - else if ((a0>>14) & 2) - { - if (sizeX>8) - sizeX>>=1; - if (sizeY<32) - sizeY<<=1; - } - - int sy = (a0 & 255); - - if(a0 & 0x0100) { - int fieldX = sizeX; - int fieldY = sizeY; - if(a0 & 0x0200) { - fieldX <<= 1; - fieldY <<= 1; - } - if((sy+fieldY) > 256) - sy -= 256; - int t = VCOUNT - sy; - if((t >= 0) && (t < fieldY)) { - int sx = (a1 & 0x1FF); - int startpix = 0; - if ((sx+fieldX)> 512) - { - startpix=512-sx; - } - if((sx < 240) || startpix) { - lineOBJpix-=8; - // int t2 = t - (fieldY >> 1); - int rot = (a1 >> 9) & 0x1F; - u16 *OAM = (u16 *)oam; - int dx = READ16LE(&OAM[3 + (rot << 4)]); - if(dx & 0x8000) - dx |= 0xFFFF8000; - int dmx = READ16LE(&OAM[7 + (rot << 4)]); - if(dmx & 0x8000) - dmx |= 0xFFFF8000; - int dy = READ16LE(&OAM[11 + (rot << 4)]); - if(dy & 0x8000) - dy |= 0xFFFF8000; - int dmy = READ16LE(&OAM[15 + (rot << 4)]); - if(dmy & 0x8000) - dmy |= 0xFFFF8000; - - int realX = ((sizeX) << 7) - (fieldX >> 1)*dx - (fieldY>>1)*dmx - + t * dmx; - int realY = ((sizeY) << 7) - (fieldX >> 1)*dy - (fieldY>>1)*dmy - + t * dmy; - - // u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - - if(a0 & 0x2000) { - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - int inc = 32; - if(DISPCNT & 0x40) - inc = sizeX >> 2; - else - c &= 0x3FE; - for(int x = 0; x < fieldX; x++) { - if (x >= startpix) - lineOBJpix-=2; - if (lineOBJpix<0) - continue; - int xxx = realX >> 8; - int yyy = realY >> 8; - - if(xxx < 0 || xxx >= sizeX || - yyy < 0 || yyy >= sizeY || - sx >= 240) { - } else { - u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) - + ((yyy & 7)<<3) + ((xxx >> 3)<<6) + - (xxx & 7))&0x7fff)]; - if(color) { - lineOBJWin[sx] = 1; - } - } - sx = (sx+1)&511; - realX += dx; - realY += dy; - } - } else { - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - if(DISPCNT & 0x40) - inc = sizeX >> 3; - // int palette = (a2 >> 8) & 0xF0; - for(int x = 0; x < fieldX; x++) { - if (x >= startpix) - lineOBJpix-=2; - if (lineOBJpix<0) - continue; - int xxx = realX >> 8; - int yyy = realY >> 8; - - // if(x == 0 || x == (sizeX-1) || - // t == 0 || t == (sizeY-1)) { - // lineOBJ[sx] = 0x001F | prio; - // } else { - if(xxx < 0 || xxx >= sizeX || - yyy < 0 || yyy >= sizeY || - sx >= 240) { - } else { - u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) - + ((yyy & 7)<<2) + ((xxx >> 3)<<5) + - ((xxx & 7)>>1))&0x7fff)]; - if(xxx & 1) - color >>= 4; - else - color &= 0x0F; - - if(color) { - lineOBJWin[sx] = 1; - } - } - // } - sx = (sx+1)&511; - realX += dx; - realY += dy; - } - } - } - } - } else { - if((sy+sizeY) > 256) - sy -= 256; - int t = VCOUNT - sy; - if((t >= 0) && (t < sizeY)) { - int sx = (a1 & 0x1FF); - int startpix = 0; - if ((sx+sizeX)> 512) - { - startpix=512-sx; - } - if((sx < 240) || startpix) { - lineOBJpix+=2; - if(a0 & 0x2000) { - if(a1 & 0x2000) - t = sizeY - t - 1; - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - if(DISPCNT & 0x40) { - inc = sizeX >> 2; - } else { - c &= 0x3FE; - } - int xxx = 0; - if(a1 & 0x1000) - xxx = sizeX-1; - int address = 0x10000 + ((((c+ (t>>3) * inc) << 5) - + ((t & 7) << 3) + ((xxx>>3)<<6) + (xxx & 7))&0x7fff); - if(a1 & 0x1000) - xxx = 7; - // u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - for(int xx = 0; xx < sizeX; xx++) { - if (xx >= startpix) - lineOBJpix--; - if (lineOBJpix<0) - continue; - if(sx < 240) { - u8 color = vram[address]; - if(color) { - lineOBJWin[sx] = 1; - } - } - - sx = (sx+1) & 511; - if(a1 & 0x1000) { - xxx--; - address--; - if(xxx == -1) { - address -= 56; - xxx = 7; - } - if(address < 0x10000) - address += 0x8000; - } else { - xxx++; - address++; - if(xxx == 8) { - address += 56; - xxx = 0; - } - if(address > 0x17fff) - address -= 0x8000; - } - } - } else { - if(a1 & 0x2000) - t = sizeY - t - 1; - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - if(DISPCNT & 0x40) { - inc = sizeX >> 3; - } - int xxx = 0; - if(a1 & 0x1000) - xxx = sizeX - 1; - int address = 0x10000 + ((((c + (t>>3) * inc)<<5) - + ((t & 7)<<2) + ((xxx>>3)<<5) + ((xxx & 7) >> 1))&0x7fff); - // u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - // int palette = (a2 >> 8) & 0xF0; - if(a1 & 0x1000) { - xxx = 7; - for(int xx = sizeX - 1; xx >= 0; xx--) { - if (xx >= startpix) - lineOBJpix--; - if (lineOBJpix<0) - continue; - if(sx < 240) { - u8 color = vram[address]; - if(xx & 1) { - color = (color >> 4); - } else - color &= 0x0F; - - if(color) { - lineOBJWin[sx] = 1; - } - } - sx = (sx+1) & 511; - xxx--; - if(!(xx & 1)) - address--; - if(xxx == -1) { - xxx = 7; - address -= 28; - } - if(address < 0x10000) - address += 0x8000; - } - } else { - for(int xx = 0; xx < sizeX; xx++) { - if (xx >= startpix) - lineOBJpix--; - if (lineOBJpix<0) - continue; - if(sx < 240) { - u8 color = vram[address]; - if(xx & 1) { - color = (color >> 4); - } else - color &= 0x0F; - - if(color) { - lineOBJWin[sx] = 1; - } - } - sx = (sx+1) & 511; - xxx++; - if(xx & 1) - address++; - if(xxx == 8) { - address += 28; - xxx = 0; - } - if(address > 0x17fff) - address -= 0x8000; - } - } - } - } - } - } - } - } -} - -static inline u32 gfxIncreaseBrightness(u32 color, int coeff) -{ - color &= 0xffff; - color = ((color << 16) | color) & 0x3E07C1F; - - color = color + (((0x3E07C1F - color) * coeff) >> 4); - color &= 0x3E07C1F; - - return (color >> 16) | color; -} - -static inline void gfxIncreaseBrightness(u32 *line, int coeff) -{ - for(int x = 0; x < 240; x++) { - u32 color = *line; - int r = (color & 0x1F); - int g = ((color >> 5) & 0x1F); - int b = ((color >> 10) & 0x1F); - - r = r + (((31 - r) * coeff) >> 4); - g = g + (((31 - g) * coeff) >> 4); - b = b + (((31 - b) * coeff) >> 4); - if(r > 31) - r = 31; - if(g > 31) - g = 31; - if(b > 31) - b = 31; - *line++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; - } -} - -static inline u32 gfxDecreaseBrightness(u32 color, int coeff) -{ - color &= 0xffff; - color = ((color << 16) | color) & 0x3E07C1F; - - color = color - (((color * coeff) >> 4) & 0x3E07C1F); - - return (color >> 16) | color; -} - -static inline void gfxDecreaseBrightness(u32 *line, int coeff) -{ - for(int x = 0; x < 240; x++) { - u32 color = *line; - int r = (color & 0x1F); - int g = ((color >> 5) & 0x1F); - int b = ((color >> 10) & 0x1F); - - r = r - ((r * coeff) >> 4); - g = g - ((g * coeff) >> 4); - b = b - ((b * coeff) >> 4); - if(r < 0) - r = 0; - if(g < 0) - g = 0; - if(b < 0) - b = 0; - *line++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; - } -} - -static inline u32 gfxAlphaBlend(u32 color, u32 color2, int ca, int cb) -{ - if(color < 0x80000000) { - color&=0xffff; - color2&=0xffff; - - color = ((color << 16) | color) & 0x03E07C1F; - color2 = ((color2 << 16) | color2) & 0x03E07C1F; - color = ((color * ca) + (color2 * cb)) >> 4; - - if ((ca + cb)>16) - { - if (color & 0x20) - color |= 0x1f; - if (color & 0x8000) - color |= 0x7C00; - if (color & 0x4000000) - color |= 0x03E00000; - } - - color &= 0x03E07C1F; - color = (color >> 16) | color; - } - return color; -} - -static inline void gfxAlphaBlend(u32 *ta, u32 *tb, int ca, int cb) -{ - for(int x = 0; x < 240; x++) { - u32 color = *ta; - if(color < 0x80000000) { - int r = (color & 0x1F); - int g = ((color >> 5) & 0x1F); - int b = ((color >> 10) & 0x1F); - u32 color2 = (*tb++); - int r0 = (color2 & 0x1F); - int g0 = ((color2 >> 5) & 0x1F); - int b0 = ((color2 >> 10) & 0x1F); - - r = ((r * ca) + (r0 * cb)) >> 4; - g = ((g * ca) + (g0 * cb)) >> 4; - b = ((b * ca) + (b0 * cb)) >> 4; - - if(r > 31) - r = 31; - if(g > 31) - g = 31; - if(b > 31) - b = 31; - - *ta++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; - } else { - ta++; - tb++; - } - } -} - -#endif // VBA_GFX_H +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 Forgotten and the VBA development team +// Copyright (C) 2008 VBA-M development team +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef VBA_GFX_H +#define VBA_GFX_H + +#include "GBA.h" +#include "../Globals.h" + +#include "../Port.h" + +//#define SPRITE_DEBUG + +static void gfxDrawTextScreen(u16, u16, u16, u32 *); +static void gfxDrawRotScreen(u16, + u16, u16, + u16, u16, + u16, u16, + u16, u16, + int&, int&, + int, + u32*); +static void gfxDrawRotScreen16Bit(u16, + u16, u16, + u16, u16, + u16, u16, + u16, u16, + int&, int&, + int, + u32*); +static void gfxDrawRotScreen256(u16, + u16, u16, + u16, u16, + u16, u16, + u16, u16, + int&, int&, + int, + u32*); +static void gfxDrawRotScreen16Bit160(u16, + u16, u16, + u16, u16, + u16, u16, + u16, u16, + int&, int&, + int, + u32*); +static void gfxDrawSprites(u32 *); +static void gfxIncreaseBrightness(u32 *line, int coeff); +static void gfxDecreaseBrightness(u32 *line, int coeff); +static void gfxAlphaBlend(u32 *ta, u32 *tb, int ca, int cb); + +void mode0RenderLine(); +void mode0RenderLineNoWindow(); +void mode0RenderLineAll(); + +void mode1RenderLine(); +void mode1RenderLineNoWindow(); +void mode1RenderLineAll(); + +void mode2RenderLine(); +void mode2RenderLineNoWindow(); +void mode2RenderLineAll(); + +void mode3RenderLine(); +void mode3RenderLineNoWindow(); +void mode3RenderLineAll(); + +void mode4RenderLine(); +void mode4RenderLineNoWindow(); +void mode4RenderLineAll(); + +void mode5RenderLine(); +void mode5RenderLineNoWindow(); +void mode5RenderLineAll(); + +extern int coeff[32]; +extern u32 line0[240]; +extern u32 line1[240]; +extern u32 line2[240]; +extern u32 line3[240]; +extern u32 lineOBJ[240]; +extern u32 lineOBJWin[240]; +extern u32 lineMix[240]; +extern bool gfxInWin0[240]; +extern bool gfxInWin1[240]; +extern int lineOBJpixleft[128]; + +extern int gfxBG2Changed; +extern int gfxBG3Changed; + +extern int gfxBG2X; +extern int gfxBG2Y; +extern int gfxBG2LastX; +extern int gfxBG2LastY; +extern int gfxBG3X; +extern int gfxBG3Y; +extern int gfxBG3LastX; +extern int gfxBG3LastY; +extern int gfxLastVCOUNT; + +static inline void gfxClearArray(u32 *array) +{ + for(int i = 0; i < 240; i++) { + *array++ = 0x80000000; + } +} + +static inline void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs, + u32 *line) +{ + u16 *palette = (u16 *)paletteRAM; + u8 *charBase = &vram[((control >> 2) & 0x03) * 0x4000]; + u16 *screenBase = (u16 *)&vram[((control >> 8) & 0x1f) * 0x800]; + u32 prio = ((control & 3)<<25) + 0x1000000; + int sizeX = 256; + int sizeY = 256; + switch((control >> 14) & 3) { + case 0: + break; + case 1: + sizeX = 512; + break; + case 2: + sizeY = 512; + break; + case 3: + sizeX = 512; + sizeY = 512; + break; + } + + int maskX = sizeX-1; + int maskY = sizeY-1; + + bool mosaicOn = (control & 0x40) ? true : false; + + int xxx = hofs & maskX; + int yyy = (vofs + VCOUNT) & maskY; + int mosaicX = (MOSAIC & 0x000F)+1; + int mosaicY = ((MOSAIC & 0x00F0)>>4)+1; + + if(mosaicOn) { + if((VCOUNT % mosaicY) != 0) { + mosaicY = VCOUNT - (VCOUNT % mosaicY); + yyy = (vofs + mosaicY) & maskY; + } + } + + if(yyy > 255 && sizeY > 256) { + yyy &= 255; + screenBase += 0x400; + if(sizeX > 256) + screenBase += 0x400; + } + + int yshift = ((yyy>>3)<<5); + if((control) & 0x80) { + u16 *screenSource = screenBase + 0x400 * (xxx>>8) + ((xxx & 255)>>3) + yshift; + for(int x = 0; x < 240; x++) { + u16 data = READ16LE(screenSource); + + int tile = data & 0x3FF; + int tileX = (xxx & 7); + int tileY = yyy & 7; + + if(tileX == 7) + screenSource++; + + if(data & 0x0400) + tileX = 7 - tileX; + if(data & 0x0800) + tileY = 7 - tileY; + + u8 color = charBase[tile * 64 + tileY * 8 + tileX]; + + line[x] = color ? (READ16LE(&palette[color]) | prio): 0x80000000; + + xxx++; + if(xxx == 256) { + if(sizeX > 256) + screenSource = screenBase + 0x400 + yshift; + else { + screenSource = screenBase + yshift; + xxx = 0; + } + } else if(xxx >= sizeX) { + xxx = 0; + screenSource = screenBase + yshift; + } + } + } else { + u16 *screenSource = screenBase + 0x400*(xxx>>8)+((xxx&255)>>3) + + yshift; + for(int x = 0; x < 240; x++) { + u16 data = READ16LE(screenSource); + + int tile = data & 0x3FF; + int tileX = (xxx & 7); + int tileY = yyy & 7; + + if(tileX == 7) + screenSource++; + + if(data & 0x0400) + tileX = 7 - tileX; + if(data & 0x0800) + tileY = 7 - tileY; + + u8 color = charBase[(tile<<5) + (tileY<<2) + (tileX>>1)]; + + if(tileX & 1) { + color = (color >> 4); + } else { + color &= 0x0F; + } + + int pal = (data>>8) & 0xF0; + line[x] = color ? (READ16LE(&palette[pal + color])|prio): 0x80000000; + + xxx++; + if(xxx == 256) { + if(sizeX > 256) + screenSource = screenBase + 0x400 + yshift; + else { + screenSource = screenBase + yshift; + xxx = 0; + } + } else if(xxx >= sizeX) { + xxx = 0; + screenSource = screenBase + yshift; + } + } + } + if(mosaicOn) { + if(mosaicX > 1) { + int m = 1; + for(int i = 0; i < 239; i++) { + line[i+1] = line[i]; + m++; + if(m == mosaicX) { + m = 1; + i++; + } + } + } + } +} + +static inline void gfxDrawRotScreen(u16 control, + u16 x_l, u16 x_h, + u16 y_l, u16 y_h, + u16 pa, u16 pb, + u16 pc, u16 pd, + int& currentX, int& currentY, + int changed, + u32 *line) +{ + u16 *palette = (u16 *)paletteRAM; + u8 *charBase = &vram[((control >> 2) & 0x03) * 0x4000]; + u8 *screenBase = (u8 *)&vram[((control >> 8) & 0x1f) * 0x800]; + int prio = ((control & 3) << 25) + 0x1000000; + + int sizeX = 128; + int sizeY = 128; + switch((control >> 14) & 3) { + case 0: + break; + case 1: + sizeX = sizeY = 256; + break; + case 2: + sizeX = sizeY = 512; + break; + case 3: + sizeX = sizeY = 1024; + break; + } + + int maskX = sizeX-1; + int maskY = sizeY-1; + + int yshift = ((control >> 14) & 3)+4; + + int dx = pa & 0x7FFF; + if(pa & 0x8000) + dx |= 0xFFFF8000; + int dmx = pb & 0x7FFF; + if(pb & 0x8000) + dmx |= 0xFFFF8000; + int dy = pc & 0x7FFF; + if(pc & 0x8000) + dy |= 0xFFFF8000; + int dmy = pd & 0x7FFF; + if(pd & 0x8000) + dmy |= 0xFFFF8000; + + if(VCOUNT == 0) + changed = 3; + + if(changed & 1) { + currentX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + currentX |= 0xF8000000; + } else { + currentX += dmx; + } + + if(changed & 2) { + currentY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + currentY |= 0xF8000000; + } else { + currentY += dmy; + } + + int realX = currentX; + int realY = currentY; + + if(control & 0x40) { + int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; + int y = (VCOUNT % mosaicY); + realX -= y*dmx; + realY -= y*dmy; + } + + if(control & 0x2000) { + for(int x = 0; x < 240; x++) { + int xxx = (realX >> 8) & maskX; + int yyy = (realY >> 8) & maskY; + + int tile = screenBase[(xxx>>3) + ((yyy>>3)<> 8); + int yyy = (realY >> 8); + + if(xxx < 0 || + yyy < 0 || + xxx >= sizeX || + yyy >= sizeY) { + line[x] = 0x80000000; + } else { + int tile = screenBase[(xxx>>3) + ((yyy>>3)< 1) { + int m = 1; + for(int i = 0; i < 239; i++) { + line[i+1] = line[i]; + m++; + if(m == mosaicX) { + m = 1; + i++; + } + } + } + } +} + +static inline void gfxDrawRotScreen16Bit(u16 control, + u16 x_l, u16 x_h, + u16 y_l, u16 y_h, + u16 pa, u16 pb, + u16 pc, u16 pd, + int& currentX, int& currentY, + int changed, + u32 *line) +{ + u16 *screenBase = (u16 *)&vram[0]; + int prio = ((control & 3) << 25) + 0x1000000; + int sizeX = 240; + int sizeY = 160; + + int startX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + startX |= 0xF8000000; + int startY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + startY |= 0xF8000000; + + int dx = pa & 0x7FFF; + if(pa & 0x8000) + dx |= 0xFFFF8000; + int dmx = pb & 0x7FFF; + if(pb & 0x8000) + dmx |= 0xFFFF8000; + int dy = pc & 0x7FFF; + if(pc & 0x8000) + dy |= 0xFFFF8000; + int dmy = pd & 0x7FFF; + if(pd & 0x8000) + dmy |= 0xFFFF8000; + + if(VCOUNT == 0) + changed = 3; + + if(changed & 1) { + currentX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + currentX |= 0xF8000000; + } else + currentX += dmx; + + if(changed & 2) { + currentY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + currentY |= 0xF8000000; + } else { + currentY += dmy; + } + + int realX = currentX; + int realY = currentY; + + if(control & 0x40) { + int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; + int y = (VCOUNT % mosaicY); + realX -= y*dmx; + realY -= y*dmy; + } + + int xxx = (realX >> 8); + int yyy = (realY >> 8); + + for(int x = 0; x < 240; x++) { + if(xxx < 0 || + yyy < 0 || + xxx >= sizeX || + yyy >= sizeY) { + line[x] = 0x80000000; + } else { + line[x] = (READ16LE(&screenBase[yyy * sizeX + xxx]) | prio); + } + realX += dx; + realY += dy; + + xxx = (realX >> 8); + yyy = (realY >> 8); + } + + if(control & 0x40) { + int mosaicX = (MOSAIC & 0xF) + 1; + if(mosaicX > 1) { + int m = 1; + for(int i = 0; i < 239; i++) { + line[i+1] = line[i]; + m++; + if(m == mosaicX) { + m = 1; + i++; + } + } + } + } +} + +static inline void gfxDrawRotScreen256(u16 control, + u16 x_l, u16 x_h, + u16 y_l, u16 y_h, + u16 pa, u16 pb, + u16 pc, u16 pd, + int ¤tX, int& currentY, + int changed, + u32 *line) +{ + u16 *palette = (u16 *)paletteRAM; + u8 *screenBase = (DISPCNT & 0x0010) ? &vram[0xA000] : &vram[0x0000]; + int prio = ((control & 3) << 25) + 0x1000000; + int sizeX = 240; + int sizeY = 160; + + int startX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + startX |= 0xF8000000; + int startY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + startY |= 0xF8000000; + + int dx = pa & 0x7FFF; + if(pa & 0x8000) + dx |= 0xFFFF8000; + int dmx = pb & 0x7FFF; + if(pb & 0x8000) + dmx |= 0xFFFF8000; + int dy = pc & 0x7FFF; + if(pc & 0x8000) + dy |= 0xFFFF8000; + int dmy = pd & 0x7FFF; + if(pd & 0x8000) + dmy |= 0xFFFF8000; + + if(VCOUNT == 0) + changed = 3; + + if(changed & 1) { + currentX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + currentX |= 0xF8000000; + } else { + currentX += dmx; + } + + if(changed & 2) { + currentY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + currentY |= 0xF8000000; + } else { + currentY += dmy; + } + + int realX = currentX; + int realY = currentY; + + if(control & 0x40) { + int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; + int y = VCOUNT - (VCOUNT % mosaicY); + realX = startX + y*dmx; + realY = startY + y*dmy; + } + + int xxx = (realX >> 8); + int yyy = (realY >> 8); + + for(int x = 0; x < 240; x++) { + if(xxx < 0 || + yyy < 0 || + xxx >= sizeX || + yyy >= sizeY) { + line[x] = 0x80000000; + } else { + u8 color = screenBase[yyy * 240 + xxx]; + + line[x] = color ? (READ16LE(&palette[color])|prio): 0x80000000; + } + realX += dx; + realY += dy; + + xxx = (realX >> 8); + yyy = (realY >> 8); + } + + if(control & 0x40) { + int mosaicX = (MOSAIC & 0xF) + 1; + if(mosaicX > 1) { + int m = 1; + for(int i = 0; i < 239; i++) { + line[i+1] = line[i]; + m++; + if(m == mosaicX) { + m = 1; + i++; + } + } + } + } +} + +static inline void gfxDrawRotScreen16Bit160(u16 control, + u16 x_l, u16 x_h, + u16 y_l, u16 y_h, + u16 pa, u16 pb, + u16 pc, u16 pd, + int& currentX, int& currentY, + int changed, + u32 *line) +{ + u16 *screenBase = (DISPCNT & 0x0010) ? (u16 *)&vram[0xa000] : + (u16 *)&vram[0]; + int prio = ((control & 3) << 25) + 0x1000000; + int sizeX = 160; + int sizeY = 128; + + int startX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + startX |= 0xF8000000; + int startY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + startY |= 0xF8000000; + + int dx = pa & 0x7FFF; + if(pa & 0x8000) + dx |= 0xFFFF8000; + int dmx = pb & 0x7FFF; + if(pb & 0x8000) + dmx |= 0xFFFF8000; + int dy = pc & 0x7FFF; + if(pc & 0x8000) + dy |= 0xFFFF8000; + int dmy = pd & 0x7FFF; + if(pd & 0x8000) + dmy |= 0xFFFF8000; + + if(VCOUNT == 0) + changed = 3; + + if(changed & 1) { + currentX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + currentX |= 0xF8000000; + } else { + currentX += dmx; + } + + if(changed & 2) { + currentY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + currentY |= 0xF8000000; + } else { + currentY += dmy; + } + + int realX = currentX; + int realY = currentY; + + if(control & 0x40) { + int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; + int y = VCOUNT - (VCOUNT % mosaicY); + realX = startX + y*dmx; + realY = startY + y*dmy; + } + + int xxx = (realX >> 8); + int yyy = (realY >> 8); + + for(int x = 0; x < 240; x++) { + if(xxx < 0 || + yyy < 0 || + xxx >= sizeX || + yyy >= sizeY) { + line[x] = 0x80000000; + } else { + line[x] = (READ16LE(&screenBase[yyy * sizeX + xxx]) | prio); + } + realX += dx; + realY += dy; + + xxx = (realX >> 8); + yyy = (realY >> 8); + } + + if(control & 0x40) { + int mosaicX = (MOSAIC & 0xF) + 1; + if(mosaicX > 1) { + int m = 1; + for(int i = 0; i < 239; i++) { + line[i+1] = line[i]; + m++; + if(m == mosaicX) { + m = 1; + i++; + } + } + } + } +} + +static inline void gfxDrawSprites(u32 *lineOBJ) +{ + // lineOBJpix is used to keep track of the drawn OBJs + // and to stop drawing them if the 'maximum number of OBJ per line' + // has been reached. + int lineOBJpix = (DISPCNT & 0x20) ? 954 : 1226; + int m=0; + gfxClearArray(lineOBJ); + if(layerEnable & 0x1000) { + u16 *sprites = (u16 *)oam; + u16 *spritePalette = &((u16 *)paletteRAM)[256]; + int mosaicY = ((MOSAIC & 0xF000)>>12) + 1; + int mosaicX = ((MOSAIC & 0xF00)>>8) + 1; + for(int x = 0; x < 128 ; x++) { + u16 a0 = READ16LE(sprites++); + u16 a1 = READ16LE(sprites++); + u16 a2 = READ16LE(sprites++); + sprites++; + + lineOBJpixleft[x]=lineOBJpix; + + lineOBJpix-=2; + if (lineOBJpix<=0) + continue; + + if ((a0 & 0x0c00) == 0x0c00) + a0 &=0xF3FF; + + if ((a0>>14) == 3) + { + a0 &= 0x3FFF; + a1 &= 0x3FFF; + } + + int sizeX = 8<<(a1>>14); + int sizeY = sizeX; + + if ((a0>>14) & 1) + { + if (sizeX<32) + sizeX<<=1; + if (sizeY>8) + sizeY>>=1; + } + else if ((a0>>14) & 2) + { + if (sizeX>8) + sizeX>>=1; + if (sizeY<32) + sizeY<<=1; + } + +#ifdef SPRITE_DEBUG + int maskX = sizeX-1; + int maskY = sizeY-1; +#endif + + int sy = (a0 & 255); + int sx = (a1 & 0x1FF); + + // computes ticks used by OBJ-WIN if OBJWIN is enabled + if (((a0 & 0x0c00) == 0x0800) && (layerEnable & 0x8000)) + { + if ((a0 & 0x0300) == 0x0300) + { + sizeX<<=1; + sizeY<<=1; + } + if((sy+sizeY) > 256) + sy -= 256; + if ((sx+sizeX)> 512) + sx-=512; + if (sx<0) + { + sizeX+=sx; + sx = 0; + } + else if ((sx+sizeX)>240) + sizeX=240-sx; + if ((VCOUNT>=sy) && (VCOUNT 256) + sy -= 256; + int t = VCOUNT - sy; + if((t >= 0) && (t < fieldY)) { + int startpix = 0; + if ((sx+fieldX)> 512) + { + startpix=512-sx; + } + if (lineOBJpix>0) + if((sx < 240) || startpix) { + lineOBJpix-=8; + // int t2 = t - (fieldY >> 1); + int rot = (a1 >> 9) & 0x1F; + u16 *OAM = (u16 *)oam; + int dx = READ16LE(&OAM[3 + (rot << 4)]); + if(dx & 0x8000) + dx |= 0xFFFF8000; + int dmx = READ16LE(&OAM[7 + (rot << 4)]); + if(dmx & 0x8000) + dmx |= 0xFFFF8000; + int dy = READ16LE(&OAM[11 + (rot << 4)]); + if(dy & 0x8000) + dy |= 0xFFFF8000; + int dmy = READ16LE(&OAM[15 + (rot << 4)]); + if(dmy & 0x8000) + dmy |= 0xFFFF8000; + + if(a0 & 0x1000) { + t -= (t % mosaicY); + } + + int realX = ((sizeX) << 7) - (fieldX >> 1)*dx - (fieldY>>1)*dmx + + t * dmx; + int realY = ((sizeY) << 7) - (fieldX >> 1)*dy - (fieldY>>1)*dmy + + t * dmy; + + u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); + + if(a0 & 0x2000) { + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + int inc = 32; + if(DISPCNT & 0x40) + inc = sizeX >> 2; + else + c &= 0x3FE; + for(int x = 0; x < fieldX; x++) { + if (x >= startpix) + lineOBJpix-=2; + if (lineOBJpix<0) + continue; + int xxx = realX >> 8; + int yyy = realY >> 8; + + if(xxx < 0 || xxx >= sizeX || + yyy < 0 || yyy >= sizeY || + sx >= 240); + else { + u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) + + ((yyy & 7)<<3) + ((xxx >> 3)<<6) + + (xxx & 7))&0x7FFF)]; + if ((color==0) && (((prio >> 25)&3) < + ((lineOBJ[sx]>>25)&3))) { + lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { + lineOBJ[sx] = READ16LE(&spritePalette[color]) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } + + if (a0 & 0x1000) { + m++; + if (m==mosaicX) + m=0; + } +#ifdef SPRITE_DEBUG + if(t == 0 || t == maskY || x == 0 || x == maskX) + lineOBJ[sx] = 0x001F; +#endif + } + sx = (sx+1)&511; + realX += dx; + realY += dy; + } + } else { + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + + int inc = 32; + if(DISPCNT & 0x40) + inc = sizeX >> 3; + int palette = (a2 >> 8) & 0xF0; + for(int x = 0; x < fieldX; x++) { + if (x >= startpix) + lineOBJpix-=2; + if (lineOBJpix<0) + continue; + int xxx = realX >> 8; + int yyy = realY >> 8; + if(xxx < 0 || xxx >= sizeX || + yyy < 0 || yyy >= sizeY || + sx >= 240); + else { + u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) + + ((yyy & 7)<<2) + ((xxx >> 3)<<5) + + ((xxx & 7)>>1))&0x7FFF)]; + if(xxx & 1) + color >>= 4; + else + color &= 0x0F; + + if ((color==0) && (((prio >> 25)&3) < + ((lineOBJ[sx]>>25)&3))) { + lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { + lineOBJ[sx] = READ16LE(&spritePalette[palette+color]) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } + } + if((a0 & 0x1000) && m) { + m++; + if (m==mosaicX) + m=0; + } + +#ifdef SPRITE_DEBUG + if(t == 0 || t == maskY || x == 0 || x == maskX) + lineOBJ[sx] = 0x001F; +#endif + sx = (sx+1)&511; + realX += dx; + realY += dy; + + } + } + } + } + } else { + if(sy+sizeY > 256) + sy -= 256; + int t = VCOUNT - sy; + if((t >= 0) && (t < sizeY)) { + int startpix = 0; + if ((sx+sizeX)> 512) + { + startpix=512-sx; + } + if((sx < 240) || startpix) { + lineOBJpix+=2; + if(a0 & 0x2000) { + if(a1 & 0x2000) + t = sizeY - t - 1; + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + + int inc = 32; + if(DISPCNT & 0x40) { + inc = sizeX >> 2; + } else { + c &= 0x3FE; + } + int xxx = 0; + if(a1 & 0x1000) + xxx = sizeX-1; + + if(a0 & 0x1000) { + t -= (t % mosaicY); + } + + int address = 0x10000 + ((((c+ (t>>3) * inc) << 5) + + ((t & 7) << 3) + ((xxx>>3)<<6) + (xxx & 7)) & 0x7FFF); + + if(a1 & 0x1000) + xxx = 7; + u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); + + for(int xx = 0; xx < sizeX; xx++) { + if (xx >= startpix) + lineOBJpix--; + if (lineOBJpix<0) + continue; + if(sx < 240) { + u8 color = vram[address]; + if ((color==0) && (((prio >> 25)&3) < + ((lineOBJ[sx]>>25)&3))) { + lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { + lineOBJ[sx] = READ16LE(&spritePalette[color]) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } + + if (a0 & 0x1000) { + m++; + if (m==mosaicX) + m=0; + } + +#ifdef SPRITE_DEBUG + if(t == 0 || t == maskY || xx == 0 || xx == maskX) + lineOBJ[sx] = 0x001F; +#endif + } + + sx = (sx+1) & 511; + if(a1 & 0x1000) { + xxx--; + address--; + if(xxx == -1) { + address -= 56; + xxx = 7; + } + if(address < 0x10000) + address += 0x8000; + } else { + xxx++; + address++; + if(xxx == 8) { + address += 56; + xxx = 0; + } + if(address > 0x17fff) + address -= 0x8000; + } + } + } else { + if(a1 & 0x2000) + t = sizeY - t - 1; + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + + int inc = 32; + if(DISPCNT & 0x40) { + inc = sizeX >> 3; + } + int xxx = 0; + if(a1 & 0x1000) + xxx = sizeX - 1; + + if(a0 & 0x1000) { + t -= (t % mosaicY); + } + + int address = 0x10000 + ((((c + (t>>3) * inc)<<5) + + ((t & 7)<<2) + ((xxx>>3)<<5) + ((xxx & 7) >> 1))&0x7FFF); + u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); + int palette = (a2 >> 8) & 0xF0; + if(a1 & 0x1000) { + xxx = 7; + for(int xx = sizeX - 1; xx >= 0; xx--) { + if (xx >= startpix) + lineOBJpix--; + if (lineOBJpix<0) + continue; + if(sx < 240) { + u8 color = vram[address]; + if(xx & 1) { + color = (color >> 4); + } else + color &= 0x0F; + + if ((color==0) && (((prio >> 25)&3) < + ((lineOBJ[sx]>>25)&3))) { + lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { + lineOBJ[sx] = READ16LE(&spritePalette[palette + color]) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } + } + if (a0 & 0x1000) { + m++; + if (m==mosaicX) + m=0; + } +#ifdef SPRITE_DEBUG + if(t == 0 || t == maskY || xx == 0 || xx == maskX) + lineOBJ[sx] = 0x001F; +#endif + sx = (sx+1) & 511; + xxx--; + if(!(xx & 1)) + address--; + if(xxx == -1) { + xxx = 7; + address -= 28; + } + if(address < 0x10000) + address += 0x8000; + } + } else { + for(int xx = 0; xx < sizeX; xx++) { + if (xx >= startpix) + lineOBJpix--; + if (lineOBJpix<0) + continue; + if(sx < 240) { + u8 color = vram[address]; + if(xx & 1) { + color = (color >> 4); + } else + color &= 0x0F; + + if ((color==0) && (((prio >> 25)&3) < + ((lineOBJ[sx]>>25)&3))) { + lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { + lineOBJ[sx] = READ16LE(&spritePalette[palette + color]) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + + } + } + if (a0 & 0x1000) { + m++; + if (m==mosaicX) + m=0; + } +#ifdef SPRITE_DEBUG + if(t == 0 || t == maskY || xx == 0 || xx == maskX) + lineOBJ[sx] = 0x001F; +#endif + sx = (sx+1) & 511; + xxx++; + if(xx & 1) + address++; + if(xxx == 8) { + address += 28; + xxx = 0; + } + if(address > 0x17fff) + address -= 0x8000; + } + } + } + } + } + } + } + } +} + +static inline void gfxDrawOBJWin(u32 *lineOBJWin) +{ + gfxClearArray(lineOBJWin); + if((layerEnable & 0x9000) == 0x9000) { + u16 *sprites = (u16 *)oam; + // u16 *spritePalette = &((u16 *)paletteRAM)[256]; + for(int x = 0; x < 128 ; x++) { + int lineOBJpix = lineOBJpixleft[x]; + u16 a0 = READ16LE(sprites++); + u16 a1 = READ16LE(sprites++); + u16 a2 = READ16LE(sprites++); + sprites++; + + if (lineOBJpix<=0) + continue; + + // ignores non OBJ-WIN and disabled OBJ-WIN + if(((a0 & 0x0c00) != 0x0800) || ((a0 & 0x0300) == 0x0200)) + continue; + + if ((a0 & 0x0c00) == 0x0c00) + a0 &=0xF3FF; + + if ((a0>>14) == 3) + { + a0 &= 0x3FFF; + a1 &= 0x3FFF; + } + + int sizeX = 8<<(a1>>14); + int sizeY = sizeX; + + if ((a0>>14) & 1) + { + if (sizeX<32) + sizeX<<=1; + if (sizeY>8) + sizeY>>=1; + } + else if ((a0>>14) & 2) + { + if (sizeX>8) + sizeX>>=1; + if (sizeY<32) + sizeY<<=1; + } + + int sy = (a0 & 255); + + if(a0 & 0x0100) { + int fieldX = sizeX; + int fieldY = sizeY; + if(a0 & 0x0200) { + fieldX <<= 1; + fieldY <<= 1; + } + if((sy+fieldY) > 256) + sy -= 256; + int t = VCOUNT - sy; + if((t >= 0) && (t < fieldY)) { + int sx = (a1 & 0x1FF); + int startpix = 0; + if ((sx+fieldX)> 512) + { + startpix=512-sx; + } + if((sx < 240) || startpix) { + lineOBJpix-=8; + // int t2 = t - (fieldY >> 1); + int rot = (a1 >> 9) & 0x1F; + u16 *OAM = (u16 *)oam; + int dx = READ16LE(&OAM[3 + (rot << 4)]); + if(dx & 0x8000) + dx |= 0xFFFF8000; + int dmx = READ16LE(&OAM[7 + (rot << 4)]); + if(dmx & 0x8000) + dmx |= 0xFFFF8000; + int dy = READ16LE(&OAM[11 + (rot << 4)]); + if(dy & 0x8000) + dy |= 0xFFFF8000; + int dmy = READ16LE(&OAM[15 + (rot << 4)]); + if(dmy & 0x8000) + dmy |= 0xFFFF8000; + + int realX = ((sizeX) << 7) - (fieldX >> 1)*dx - (fieldY>>1)*dmx + + t * dmx; + int realY = ((sizeY) << 7) - (fieldX >> 1)*dy - (fieldY>>1)*dmy + + t * dmy; + + // u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); + + if(a0 & 0x2000) { + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + int inc = 32; + if(DISPCNT & 0x40) + inc = sizeX >> 2; + else + c &= 0x3FE; + for(int x = 0; x < fieldX; x++) { + if (x >= startpix) + lineOBJpix-=2; + if (lineOBJpix<0) + continue; + int xxx = realX >> 8; + int yyy = realY >> 8; + + if(xxx < 0 || xxx >= sizeX || + yyy < 0 || yyy >= sizeY || + sx >= 240) { + } else { + u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) + + ((yyy & 7)<<3) + ((xxx >> 3)<<6) + + (xxx & 7))&0x7fff)]; + if(color) { + lineOBJWin[sx] = 1; + } + } + sx = (sx+1)&511; + realX += dx; + realY += dy; + } + } else { + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + + int inc = 32; + if(DISPCNT & 0x40) + inc = sizeX >> 3; + // int palette = (a2 >> 8) & 0xF0; + for(int x = 0; x < fieldX; x++) { + if (x >= startpix) + lineOBJpix-=2; + if (lineOBJpix<0) + continue; + int xxx = realX >> 8; + int yyy = realY >> 8; + + // if(x == 0 || x == (sizeX-1) || + // t == 0 || t == (sizeY-1)) { + // lineOBJ[sx] = 0x001F | prio; + // } else { + if(xxx < 0 || xxx >= sizeX || + yyy < 0 || yyy >= sizeY || + sx >= 240) { + } else { + u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) + + ((yyy & 7)<<2) + ((xxx >> 3)<<5) + + ((xxx & 7)>>1))&0x7fff)]; + if(xxx & 1) + color >>= 4; + else + color &= 0x0F; + + if(color) { + lineOBJWin[sx] = 1; + } + } + // } + sx = (sx+1)&511; + realX += dx; + realY += dy; + } + } + } + } + } else { + if((sy+sizeY) > 256) + sy -= 256; + int t = VCOUNT - sy; + if((t >= 0) && (t < sizeY)) { + int sx = (a1 & 0x1FF); + int startpix = 0; + if ((sx+sizeX)> 512) + { + startpix=512-sx; + } + if((sx < 240) || startpix) { + lineOBJpix+=2; + if(a0 & 0x2000) { + if(a1 & 0x2000) + t = sizeY - t - 1; + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + + int inc = 32; + if(DISPCNT & 0x40) { + inc = sizeX >> 2; + } else { + c &= 0x3FE; + } + int xxx = 0; + if(a1 & 0x1000) + xxx = sizeX-1; + int address = 0x10000 + ((((c+ (t>>3) * inc) << 5) + + ((t & 7) << 3) + ((xxx>>3)<<6) + (xxx & 7))&0x7fff); + if(a1 & 0x1000) + xxx = 7; + // u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); + for(int xx = 0; xx < sizeX; xx++) { + if (xx >= startpix) + lineOBJpix--; + if (lineOBJpix<0) + continue; + if(sx < 240) { + u8 color = vram[address]; + if(color) { + lineOBJWin[sx] = 1; + } + } + + sx = (sx+1) & 511; + if(a1 & 0x1000) { + xxx--; + address--; + if(xxx == -1) { + address -= 56; + xxx = 7; + } + if(address < 0x10000) + address += 0x8000; + } else { + xxx++; + address++; + if(xxx == 8) { + address += 56; + xxx = 0; + } + if(address > 0x17fff) + address -= 0x8000; + } + } + } else { + if(a1 & 0x2000) + t = sizeY - t - 1; + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + + int inc = 32; + if(DISPCNT & 0x40) { + inc = sizeX >> 3; + } + int xxx = 0; + if(a1 & 0x1000) + xxx = sizeX - 1; + int address = 0x10000 + ((((c + (t>>3) * inc)<<5) + + ((t & 7)<<2) + ((xxx>>3)<<5) + ((xxx & 7) >> 1))&0x7fff); + // u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); + // int palette = (a2 >> 8) & 0xF0; + if(a1 & 0x1000) { + xxx = 7; + for(int xx = sizeX - 1; xx >= 0; xx--) { + if (xx >= startpix) + lineOBJpix--; + if (lineOBJpix<0) + continue; + if(sx < 240) { + u8 color = vram[address]; + if(xx & 1) { + color = (color >> 4); + } else + color &= 0x0F; + + if(color) { + lineOBJWin[sx] = 1; + } + } + sx = (sx+1) & 511; + xxx--; + if(!(xx & 1)) + address--; + if(xxx == -1) { + xxx = 7; + address -= 28; + } + if(address < 0x10000) + address += 0x8000; + } + } else { + for(int xx = 0; xx < sizeX; xx++) { + if (xx >= startpix) + lineOBJpix--; + if (lineOBJpix<0) + continue; + if(sx < 240) { + u8 color = vram[address]; + if(xx & 1) { + color = (color >> 4); + } else + color &= 0x0F; + + if(color) { + lineOBJWin[sx] = 1; + } + } + sx = (sx+1) & 511; + xxx++; + if(xx & 1) + address++; + if(xxx == 8) { + address += 28; + xxx = 0; + } + if(address > 0x17fff) + address -= 0x8000; + } + } + } + } + } + } + } + } +} + +static inline u32 gfxIncreaseBrightness(u32 color, int coeff) +{ + color &= 0xffff; + color = ((color << 16) | color) & 0x3E07C1F; + + color = color + (((0x3E07C1F - color) * coeff) >> 4); + color &= 0x3E07C1F; + + return (color >> 16) | color; +} + +static inline void gfxIncreaseBrightness(u32 *line, int coeff) +{ + for(int x = 0; x < 240; x++) { + u32 color = *line; + int r = (color & 0x1F); + int g = ((color >> 5) & 0x1F); + int b = ((color >> 10) & 0x1F); + + r = r + (((31 - r) * coeff) >> 4); + g = g + (((31 - g) * coeff) >> 4); + b = b + (((31 - b) * coeff) >> 4); + if(r > 31) + r = 31; + if(g > 31) + g = 31; + if(b > 31) + b = 31; + *line++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; + } +} + +static inline u32 gfxDecreaseBrightness(u32 color, int coeff) +{ + color &= 0xffff; + color = ((color << 16) | color) & 0x3E07C1F; + + color = color - (((color * coeff) >> 4) & 0x3E07C1F); + + return (color >> 16) | color; +} + +static inline void gfxDecreaseBrightness(u32 *line, int coeff) +{ + for(int x = 0; x < 240; x++) { + u32 color = *line; + int r = (color & 0x1F); + int g = ((color >> 5) & 0x1F); + int b = ((color >> 10) & 0x1F); + + r = r - ((r * coeff) >> 4); + g = g - ((g * coeff) >> 4); + b = b - ((b * coeff) >> 4); + if(r < 0) + r = 0; + if(g < 0) + g = 0; + if(b < 0) + b = 0; + *line++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; + } +} + +static inline u32 gfxAlphaBlend(u32 color, u32 color2, int ca, int cb) +{ + if(color < 0x80000000) { + color&=0xffff; + color2&=0xffff; + + color = ((color << 16) | color) & 0x03E07C1F; + color2 = ((color2 << 16) | color2) & 0x03E07C1F; + color = ((color * ca) + (color2 * cb)) >> 4; + + if ((ca + cb)>16) + { + if (color & 0x20) + color |= 0x1f; + if (color & 0x8000) + color |= 0x7C00; + if (color & 0x4000000) + color |= 0x03E00000; + } + + color &= 0x03E07C1F; + color = (color >> 16) | color; + } + return color; +} + +static inline void gfxAlphaBlend(u32 *ta, u32 *tb, int ca, int cb) +{ + for(int x = 0; x < 240; x++) { + u32 color = *ta; + if(color < 0x80000000) { + int r = (color & 0x1F); + int g = ((color >> 5) & 0x1F); + int b = ((color >> 10) & 0x1F); + u32 color2 = (*tb++); + int r0 = (color2 & 0x1F); + int g0 = ((color2 >> 5) & 0x1F); + int b0 = ((color2 >> 10) & 0x1F); + + r = ((r * ca) + (r0 * cb)) >> 4; + g = ((g * ca) + (g0 * cb)) >> 4; + b = ((b * ca) + (b0 * cb)) >> 4; + + if(r > 31) + r = 31; + if(g > 31) + g = 31; + if(b > 31) + b = 31; + + *ta++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; + } else { + ta++; + tb++; + } + } +} + +#endif // VBA_GFX_H diff --git a/src/agb/GBALink.cpp b/src/agb/GBALink.cpp index 78317bbc..fa5479d5 100644 --- a/src/agb/GBALink.cpp +++ b/src/agb/GBALink.cpp @@ -1,1083 +1,1083 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team -// This file was written by denopqrihg - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -// Link.cpp : Emulation of GBA link accessories -// - -#include "GBA.h" -#include -#include "../win32/stdafx.h" -#include "../port.h" -#include "GBALink.h" -#include "../win32/vba.h" -#include "../win32/MainWnd.h" -#include "../win32/LinkOptions.h" -#include "../win32/Reg.h" - -#define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]),value) -#define GBLINK_READY 8 - -int linktime = 0; -u8 tspeed=3; -u8 transfer=0; -LINKDATA *linkmem=NULL; -int linkid = 0, vbaid = 0; -HANDLE linksync[4]; -int savedlinktime=0; -HANDLE mmf=NULL; -char linkevent[] = "VBA link event "; -static int i, j; -int linktimeout = 1000; -int linklog = 0; -FILE *linklogfile = NULL; -LANLINKDATA lanlink; -u16 linkdata[4]; -int lspeed = 0; -lserver ls; -lclient lc; -bool oncewait = false, after = false; -bool adapter = false; -bool linkenable = false; -u8 rfu_cmd, rfu_qsend, rfu_qrecv; -int rfu_state, rfu_polarity, linktime2, counter, rfu_masterq; -int transferend, numtransfers = 0; -u32 rfu_masterdata[32]; - -extern unsigned char *gbMemory; -extern int gbInterrupt; - -int trtimedata[4][4] = {{34080, 8520, 5680, 2840}, {65536, 16384, 10923, 5461}, {99609, 24903, 16602, 8301}, {133692, 33423, 22282, 11141}}; -int trtimeend[3][4] = {{72527, 18132, 12088, 6044}, {106608, 26652, 17768, 8884}, {133692, 33423, 22282, 11141}}; -int gbtime = 1024; - -DWORD WINAPI LinkClientThread(void *); -DWORD WINAPI LinkServerThread(void *); -int StartServer(void); -int GetSioMode(u16, u16); -u16 StartRFU(u16); - -char *MakeInstanceFilename(const char *Input) -{ - if (vbaid == 0) - return (char *)Input; - - static char *result=NULL; - if (result!=NULL) - free(result); - - result = (char *)malloc(strlen(Input)+3); - char *p = strrchr((char *)Input, '.'); - sprintf(result, "%.*s-%d.%s", (int)(p-Input), Input, vbaid+1, p+1); - return result; -} - - -void StartLink(WORD value){ - if(ioMem==NULL) return; - if(adapter){ - UPDATE_REG(0x128, StartRFU(value)); - return; - } - switch(GetSioMode(value, READ16LE(&ioMem[0x134]))){ - case MULTIPLAYER: - if(value & 0x80){ - if(!linkid){ - if(!transfer){ - if(lanlink.active){ - if(lanlink.connected){ - linkdata[0] = READ16LE(&ioMem[0x12a]); - savedlinktime = linktime; - tspeed = value & 3; - ls.Send(); - transfer = 1; - linktime = 0; - UPDATE_REG(0x120, linkdata[0]); - UPDATE_REG(0x122, 0xffff); - WRITE32LE(&ioMem[0x124], 0xffffffff); - if(lanlink.speed&&oncewait==false) ls.howmanytimes++; - after = false; - } - } else if(linkmem->numgbas>1){ - ResetEvent(linksync[0]); - linkmem->linkcmd[0] = ('M'<<8)+(value&3); - linkmem->linkdata[0] = READ16LE(&ioMem[0x12a]); - if(linkmem->numtransfers!=0) linkmem->lastlinktime = linktime; - else linkmem->lastlinktime = 0; - if((++linkmem->numtransfers)==0) linkmem->numtransfers=2; - transfer = 1; - linktime = 0; - tspeed = value & 3; - WRITE32LE(&ioMem[0x120], 0xffffffff); - WRITE32LE(&ioMem[0x124], 0xffffffff); - } - } - } - value &= 0xff7f; - value |= (transfer!=0)<<7; - } - value &= 0xff8b; - value |= (linkid ? 0xc : 8); - value |= linkid<<4; - UPDATE_REG(0x128, value); - if(linkid) UPDATE_REG(0x134, 7); - else UPDATE_REG(0x134, 3); - break; - case NORMAL8: - if(linklog) fprintf(linklogfile, "Attempt to use 8-bit Normal mode %04x\n", value); - UPDATE_REG(0x128, value); - break; - case NORMAL32: - if(linklog) fprintf(linklogfile, "Attempt to use 32-bit Normal mode %04x %x%x\n", value, READ16LE(&ioMem[0x122]), READ16LE(&ioMem[0x120])); - UPDATE_REG(0x128, value); - break; - case UART: - if(linklog) fprintf(linklogfile, "Attempt to use UART mode %04x\n", value); - UPDATE_REG(0x128, value); - break; - default: - UPDATE_REG(0x128, value); - break; - } -} - -void StartGPLink(u16 value){ - if(!value){ - UPDATE_REG(0x134, 0); - return; - } - switch(GetSioMode(READ16LE(&ioMem[0x128]), value)){ - case MULTIPLAYER: - value &= 0xc0f0; - value |= 3; - if(linkid) value |= 4; - UPDATE_REG(0x134, value); - UPDATE_REG(0x128, ((READ16LE(&ioMem[0x128])&0xff8b)|(linkid ? 0xc : 8)|(linkid<<4))); - return; - break; - case GP: - if(linklog){ - if(value==0x8000) fprintf(linklogfile, "Circuit reset\n"); - else if(!adapter) fprintf(linklogfile, "Attempt to use General-purpose mode %04x\n", value); - } - if(adapter) rfu_state = RFU_INIT; - // This was not there, but sonic games won't start if it's not here. - UPDATE_REG(0x134, value); - break; - case JOYBUS: - UPDATE_REG(0x134, value); - break; - default: - UPDATE_REG(0x134, value); - break; - } - return; -} - -void StartJOYLink(u16 value){ - if(!value){ - UPDATE_REG(0x140, 0); - return; - } - if(GetSioMode(READ16LE(&ioMem[0x128]), READ16LE(&ioMem[0x134]))==JOYBUS&&linklog) fprintf(linklogfile, "Attempt to use JOY-BUS mode %04x\n", value); - return; -} - -void LinkUpdate(int ticks){ - linktime += ticks; - if(adapter){ - linktime2 += ticks; - transferend -= ticks; - if(transfer&&transferend<=0){ - transfer = 0; - if(READ16LE(&ioMem[0x128])&0x4000){ - IF |= 0x80; - UPDATE_REG(0x202, IF); - } - UPDATE_REG(0x128, READ16LE(&ioMem[0x128]) & 0xff7f); - } - return; - } - - if(lanlink.active){ - if(lanlink.connected){ - if(after){ - if(linkid&&linktime>6044){ - lc.Recv(); - oncewait = true; - } else return; - } - if(linkid&&!transfer&&lc.numtransfers>0&&linktime>=savedlinktime){ - linkdata[linkid] = READ16LE(&ioMem[0x12a]); - if(!lc.oncesend) lc.Send(); - lc.oncesend = false; - UPDATE_REG(0x120, linkdata[0]); - UPDATE_REG(0x128, READ16LE(&ioMem[0x128]) | 0x80); - transfer = 1; - if(lc.numtransfers==1) linktime = 0; - else linktime -= savedlinktime; - } - if(transfer&&linktime>=trtimeend[lanlink.numgbas-1][tspeed]){ - if(READ16LE(&ioMem[0x128]) & 0x4000){ - IF |= 0x80; - UPDATE_REG(0x202, IF); - } - UPDATE_REG(0x128, (READ16LE(&ioMem[0x128]) & 0xff0f) | (linkid << 4)); - transfer = 0; - linktime -= trtimeend[lanlink.numgbas-1][tspeed]; - oncewait = false; - if(!lanlink.speed){ - if(linkid) lc.Recv(); - else ls.Recv(); - UPDATE_REG(0x122, linkdata[1]); - UPDATE_REG(0x124, linkdata[2]); - UPDATE_REG(0x126, linkdata[3]); - if(linklog) fprintf(linklogfile, "%04x %04x %04x %04x %10u\n", linkdata[0], linkdata[1], linkdata[2], linkdata[3], savedlinktime); - oncewait = true; - } else { - after = true; - if(lanlink.numgbas==1){ - UPDATE_REG(0x122, linkdata[1]); - UPDATE_REG(0x124, linkdata[2]); - UPDATE_REG(0x126, linkdata[3]); - if(linklog) fprintf(linklogfile, "%04x %04x %04x %04x %10u\n", linkdata[0], linkdata[1], linkdata[2], linkdata[3], savedlinktime); - } - - } - } - } - return; - } - // ** CRASH ** linkmem is NULL, todo investigate why, added null check - if(linkid&&!transfer&&linkmem&&linktime>=linkmem->lastlinktime&&linkmem->numtransfers){ - linkmem->linkdata[linkid] = READ16LE(&ioMem[0x12a]); - - if(linkmem->numtransfers==1){ - linktime = 0; - if(WaitForSingleObject(linksync[linkid], linktimeout)==WAIT_TIMEOUT) linkmem->numtransfers=0; - } else linktime -= linkmem->lastlinktime; - - switch((linkmem->linkcmd[0])>>8){ - case 'M': - tspeed = (linkmem->linkcmd[0]) & 3; - transfer = 1; - WRITE32LE(&ioMem[0x120], 0xffffffff); - WRITE32LE(&ioMem[0x124], 0xffffffff); - UPDATE_REG(0x128, READ16LE(&ioMem[0x128]) | 0x80); - break; - } - } - - if(!transfer) return; - - if(transfer&&linktime>=trtimedata[transfer-1][tspeed]&&transfer<=linkmem->numgbas){ - if(transfer-linkid==2){ - SetEvent(linksync[linkid+1]); - if(WaitForSingleObject(linksync[linkid], linktimeout)==WAIT_TIMEOUT) - linkmem->numtransfers=0; - ResetEvent(linksync[linkid]); - if(linklog) fprintf(linklogfile, "%04x %04x %04x %04x %10u\n", - linkmem->linkdata[0], linkmem->linkdata[1], linkmem->linkdata[2], linkmem->linkdata[3], linkmem->lastlinktime); - } - - - UPDATE_REG(0x11e + (transfer<<1), linkmem->linkdata[transfer-1]); - transfer++; - } - - if(transfer&&linktime>=trtimeend[linkmem->numgbas-2][tspeed]){ - if(linkid==linkmem->numgbas-1){ - SetEvent(linksync[0]); - if(WaitForSingleObject(linksync[linkid], linktimeout)==WAIT_TIMEOUT) - linkmem->numtransfers=0; - ResetEvent(linksync[linkid]); - if(linklog) fprintf(linklogfile, "%04x %04x %04x %04x %10u\n", - linkmem->linkdata[0], linkmem->linkdata[1], linkmem->linkdata[2], linkmem->linkdata[3], linkmem->lastlinktime); - } - transfer = 0; - linktime -= trtimeend[0][tspeed]; - if(READ16LE(&ioMem[0x128]) & 0x4000){ - IF |= 0x80; - UPDATE_REG(0x202, IF); - } - UPDATE_REG(0x128, (READ16LE(&ioMem[0x128]) & 0xff0f) | (linkid << 4)); - linkmem->linkdata[linkid] = 0xffff; - } - - return; -} - -inline int GetSioMode(u16 reg1, u16 reg2){ - if(!(reg2&0x8000)){ - switch(reg1&0x3000){ - case 0x0000: - return NORMAL8; - case 0x1000: - return NORMAL32; - case 0x2000: - return MULTIPLAYER; - case 0x3000: - return UART; - } - } - if(reg2&0x4000) return JOYBUS; - return GP; -} - -u16 StartRFU(u16 value){ - switch(GetSioMode(value, READ16LE(&ioMem[0x134]))){ - case NORMAL8: - rfu_polarity = 0; - return value; - break; - case NORMAL32: - if(value&8) value &= 0xfffb; // A kind of acknowledge procedure - else value |= 4; - if(value&0x80){ - if((value&3)==1) transferend = 2048; - else transferend = 256; - u16 a = READ16LE(&ioMem[0x122]); - switch(rfu_state){ - case RFU_INIT: - if(READ32LE(&ioMem[0x120])==0xb0bb8001){ - rfu_state = RFU_COMM; // end of startup - } - UPDATE_REG(0x122, READ16LE(&ioMem[0x120])); - UPDATE_REG(0x120, a); - break; - case RFU_COMM: - if(a==0x9966){ - rfu_cmd = ioMem[0x120]; - if((rfu_qsend=ioMem[0x121])!=0){ - rfu_state = RFU_SEND; - counter = 0; - } - if(rfu_cmd==0x25||rfu_cmd==0x24){ - linkmem->rfu_q[vbaid] = rfu_qsend; - } - UPDATE_REG(0x120, 0); - UPDATE_REG(0x122, 0x8000); - } else if(a==0x8000){ - switch(rfu_cmd){ - case 0x1a: // check if someone joined - if(linkmem->rfu_request[vbaid]!=0){ - rfu_state = RFU_RECV; - rfu_qrecv = 1; - } - linkid = -1; - rfu_cmd |= 0x80; - break; - case 0x1e: // receive broadcast data - case 0x1d: // no visible difference - rfu_polarity = 0; - rfu_state = RFU_RECV; - rfu_qrecv = 7; - counter = 0; - rfu_cmd |= 0x80; - break; - case 0x30: - linkmem->rfu_request[vbaid] = 0; - linkmem->rfu_q[vbaid] = 0; - linkid = 0; - numtransfers = 0; - rfu_cmd |= 0x80; - if(linkmem->numgbas==2) SetEvent(linksync[1-vbaid]); - break; - case 0x11: // ? always receives 0xff - I suspect it's something for 3+ players - case 0x13: // unknown - case 0x20: // this has something to do with 0x1f - case 0x21: // this too - rfu_cmd |= 0x80; - rfu_polarity = 0; - rfu_state = 3; - rfu_qrecv = 1; - break; - case 0x26: - if(linkid>0){ - rfu_qrecv = rfu_masterq; - } - if((rfu_qrecv=linkmem->rfu_q[1-vbaid])!=0){ - rfu_state = RFU_RECV; - counter = 0; - } - rfu_cmd |= 0x80; - break; - case 0x24: // send data - if((numtransfers++)==0) linktime = 1; - linkmem->rfu_linktime[vbaid] = linktime; - if(linkmem->numgbas==2){ - SetEvent(linksync[1-vbaid]); - WaitForSingleObject(linksync[vbaid], linktimeout); - ResetEvent(linksync[vbaid]); - } - rfu_cmd |= 0x80; - linktime = 0; - linkid = -1; - break; - case 0x25: // send & wait for data - case 0x1f: // pick a server - case 0x10: // init - case 0x16: // send broadcast data - case 0x17: // setup or something ? - case 0x27: // wait for data ? - case 0x3d: // init - default: - rfu_cmd |= 0x80; - break; - case 0xa5: // 2nd part of send&wait function 0x25 - case 0xa7: // 2nd part of wait function 0x27 - if(linkid==-1){ - linkid++; - linkmem->rfu_linktime[vbaid] = 0; - } - if(linkid&&linkmem->rfu_request[1-vbaid]==0){ - linkmem->rfu_q[1-vbaid] = 0; - transferend = 256; - rfu_polarity = 1; - rfu_cmd = 0x29; - linktime = 0; - break; - } - if((numtransfers++)==0) linktime = 0; - linkmem->rfu_linktime[vbaid] = linktime; - if(linkmem->numgbas==2){ - if(!linkid||(linkid&&numtransfers)) SetEvent(linksync[1-vbaid]); - WaitForSingleObject(linksync[vbaid], linktimeout); - ResetEvent(linksync[vbaid]); - } - if(linkid>0){ - memcpy(rfu_masterdata, linkmem->rfu_data[1-vbaid], 128); - rfu_masterq = linkmem->rfu_q[1-vbaid]; - } - transferend = linkmem->rfu_linktime[1-vbaid] - linktime + 256; - if(transferend<256) transferend = 256; - linktime = -transferend; - rfu_polarity = 1; - rfu_cmd = 0x28; - break; - } - UPDATE_REG(0x122, 0x9966); - UPDATE_REG(0x120, (rfu_qrecv<<8) | rfu_cmd); - } else { - UPDATE_REG(0x120, 0); - UPDATE_REG(0x122, 0x8000); - } - break; - case RFU_SEND: - if(--rfu_qsend==0) rfu_state = RFU_COMM; - switch(rfu_cmd){ - case 0x16: - linkmem->rfu_bdata[vbaid][counter++] = READ32LE(&ioMem[0x120]); - break; - case 0x17: - linkid = 1; - break; - case 0x1f: - linkmem->rfu_request[1-vbaid] = 1; - break; - case 0x24: - case 0x25: - linkmem->rfu_data[vbaid][counter++] = READ32LE(&ioMem[0x120]); - break; - } - UPDATE_REG(0x120, 0); - UPDATE_REG(0x122, 0x8000); - break; - case RFU_RECV: - if(--rfu_qrecv==0) rfu_state = RFU_COMM; - switch(rfu_cmd){ - case 0x9d: - case 0x9e: - if(counter==0){ - UPDATE_REG(0x120, 0x61f1); - UPDATE_REG(0x122, 0); - counter++; - break; - } - UPDATE_REG(0x120, linkmem->rfu_bdata[1-vbaid][counter-1]&0xffff); - UPDATE_REG(0x122, linkmem->rfu_bdata[1-vbaid][counter-1]>>16); - counter++; - break; - case 0xa6: - if(linkid>0){ - UPDATE_REG(0x120, rfu_masterdata[counter]&0xffff); - UPDATE_REG(0x122, rfu_masterdata[counter++]>>16); - } else { - UPDATE_REG(0x120, linkmem->rfu_data[1-vbaid][counter]&0xffff); - UPDATE_REG(0x122, linkmem->rfu_data[1-vbaid][counter++]>>16); - } - break; - case 0x93: // it seems like the game doesn't care about this value - UPDATE_REG(0x120, 0x1234); // put anything in here - UPDATE_REG(0x122, 0x0200); // also here, but it should be 0200 - break; - case 0xa0: - case 0xa1: - UPDATE_REG(0x120, 0x641b); - UPDATE_REG(0x122, 0x0000); - break; - case 0x9a: - UPDATE_REG(0x120, 0x61f9); - UPDATE_REG(0x122, 0); - break; - case 0x91: - UPDATE_REG(0x120, 0x00ff); - UPDATE_REG(0x122, 0x0000); - break; - default: - UPDATE_REG(0x120, 0x0173); - UPDATE_REG(0x122, 0x0000); - break; - } - break; - } - transfer = 1; - } - if(rfu_polarity) value ^= 4; // sometimes it's the other way around - default: - return value; - } -} - -void gbLinkStart(u8 value){ -// Not in this version :-) -} - - -void gbLinkUpdate(void){ -} - -int InitLink(void){ - WSADATA wsadata; - BOOL disable = true; - - linkid = 0; - - if(WSAStartup(MAKEWORD(1,1), &wsadata)!=0){ - WSACleanup(); - return 0; - } - - if((lanlink.tcpsocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET){ - MessageBox(NULL, "Couldn't create socket.", "Error!", MB_OK); - WSACleanup(); - return 0; - } - - setsockopt(lanlink.tcpsocket, IPPROTO_TCP, TCP_NODELAY, (char*)&disable, sizeof(BOOL)); - - if((mmf=CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(LINKDATA), "VBA link memory"))==NULL){ - closesocket(lanlink.tcpsocket); - WSACleanup(); - MessageBox(NULL, "Error creating file mapping", "Error", MB_OK|MB_ICONEXCLAMATION); - return 0; - } - - if(GetLastError() == ERROR_ALREADY_EXISTS) - vbaid = 1; - else - vbaid = 0; - - if((linkmem=(LINKDATA *)MapViewOfFile(mmf, FILE_MAP_WRITE, 0, 0, sizeof(LINKDATA)))==NULL){ - closesocket(lanlink.tcpsocket); - WSACleanup(); - CloseHandle(mmf); - MessageBox(NULL, "Error mapping file", "Error", MB_OK|MB_ICONEXCLAMATION); - return 0; - } - - if(linkmem->linkflags&LINK_PARENTLOST) - vbaid = 0; - - if(vbaid==0){ - linkid = 0; - if(linkmem->linkflags&LINK_PARENTLOST){ - linkmem->numgbas++; - linkmem->linkflags &= ~LINK_PARENTLOST; - } - else - linkmem->numgbas=1; - - for(i=0;i<4;i++){ - linkevent[15]=(char)i+'1'; - if((linksync[i]=CreateEvent(NULL, true, false, linkevent))==NULL){ - closesocket(lanlink.tcpsocket); - WSACleanup(); - UnmapViewOfFile(linkmem); - CloseHandle(mmf); - for(j=0;jnumgbas; - linkid = vbaid; - linkmem->numgbas++; - - linklog = 0; - if(linkmem->numgbas>4){ - linkmem->numgbas=4; - closesocket(lanlink.tcpsocket); - WSACleanup(); - MessageBox(NULL, "5 or more GBAs not supported.", "Error!", MB_OK|MB_ICONEXCLAMATION); - UnmapViewOfFile(linkmem); - CloseHandle(mmf); - return 0; - } - for(i=0;i<4;i++){ - linkevent[15]=(char)i+'1'; - if((linksync[i]=OpenEvent(EVENT_ALL_ACCESS, false, linkevent))==NULL){ - closesocket(lanlink.tcpsocket); - WSACleanup(); - CloseHandle(mmf); - UnmapViewOfFile(linkmem); - for(j=0;jlastlinktime=0xffffffff; - linkmem->numtransfers=0; - linkmem->linkflags=0; - lanlink.connected = false; - lanlink.thread = NULL; - lanlink.speed = false; - for(i=0;i<4;i++){ - linkmem->linkdata[i] = 0xffff; - linkdata[i] = 0xffff; - } -return 1; -} - -int openLinkLog(void){ - char filename[20]; - if(linklog){ - sprintf(filename, "vbalog%1d.txt", vbaid+1); - if((linklogfile=fopen(filename, "at"))==NULL){ - linklog=false; - return 0; - } - fprintf(linklogfile, "----- Log opened -----\n"); - } - return 1; -} - -void closeLinkLog() -{ - if(linklogfile) - { - fclose(linklogfile); - linklogfile=NULL; - } -} - -void CloseLink(void){ - if(lanlink.connected){ - if(linkid){ - char outbuffer[4]; - outbuffer[0] = 4; - outbuffer[1] = -32; - if(lanlink.type==0) send(lanlink.tcpsocket, outbuffer, 4, 0); - } else { - char outbuffer[12]; - int i; - outbuffer[0] = 12; - outbuffer[1] = -32; - for(i=1;i<=lanlink.numgbas;i++){ - if(lanlink.type==0){ - send(ls.tcpsocket[i], outbuffer, 12, 0); - } - closesocket(ls.tcpsocket[i]); - } - } - } - linkmem->numgbas--; - if(!linkid&&linkmem->numgbas!=0) - linkmem->linkflags|=LINK_PARENTLOST; - CloseHandle(mmf); - UnmapViewOfFile(linkmem); - - for(i=0;i<4;i++){ - if(linksync[i]!=NULL){ - PulseEvent(linksync[i]); - CloseHandle(linksync[i]); - } - } - regSetDwordValue("LAN", lanlink.active); - if(linklog) closeLinkLog(); - closesocket(lanlink.tcpsocket); - WSACleanup(); -return; -} - -lserver::lserver(void){ - intinbuffer = (int*)inbuffer; - u16inbuffer = (u16*)inbuffer; - intoutbuffer = (int*)outbuffer; - u16outbuffer = (u16*)outbuffer; - oncewait = false; -} - -int lserver::Init(void *serverdlg){ - SOCKADDR_IN info; - DWORD nothing; - char str[100]; - - info.sin_family = AF_INET; - info.sin_addr.S_un.S_addr = INADDR_ANY; - info.sin_port = htons(5738); - - if(bind(lanlink.tcpsocket, (LPSOCKADDR)&info, sizeof(SOCKADDR_IN))==SOCKET_ERROR){ - closesocket(lanlink.tcpsocket); - if((lanlink.tcpsocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET) - return WSAGetLastError(); - if(bind(lanlink.tcpsocket, (LPSOCKADDR)&info, sizeof(SOCKADDR_IN))==SOCKET_ERROR) - return WSAGetLastError(); - } - - if(listen(lanlink.tcpsocket, lanlink.numgbas)==SOCKET_ERROR) - return WSAGetLastError(); - - if(lanlink.thread!=NULL){ - lanlink.terminate = true; - WaitForSingleObject(linksync[vbaid], 500); - lanlink.thread = NULL; - } - lanlink.terminate = false; - linkid = 0; - - gethostname(str, 100); - ((ServerWait*)serverdlg)->m_serveraddress.Format("Server IP address is: %s", inet_ntoa(*(LPIN_ADDR)(gethostbyname(str)->h_addr_list[0]))); - - lanlink.thread = CreateThread(NULL, 0, LinkServerThread, serverdlg, 0, ¬hing); - - return 0; - -} - -DWORD WINAPI LinkServerThread(void *serverdlg){ - fd_set fdset; - timeval wsocktimeout; - char inbuffer[256], outbuffer[256]; - int *intinbuffer = (int*)inbuffer; - u16 *u16inbuffer = (u16*)inbuffer; - int *intoutbuffer = (int*)outbuffer; - u16 *u16outbuffer = (u16*)outbuffer; - BOOL disable = true; - - wsocktimeout.tv_sec = 1; - wsocktimeout.tv_usec = 0; - i = 0; - - while(im_plconn[i].Format("Player %d connected", i+1); - ((ServerWait*)serverdlg)->UpdateData(false); - i++; - } - } - ((ServerWait*)serverdlg)->m_prgctrl.StepIt(); - } - MessageBox(NULL, "All players connected", "Link", MB_OK); - ((ServerWait*)serverdlg)->SendMessage(WM_CLOSE, 0, 0); - - for(i=1;i<=lanlink.numgbas;i++){ - outbuffer[0] = 4; - send(ls.tcpsocket[i], outbuffer, 4, 0); - } - - lanlink.connected = true; - - return 0; -} - -void lserver::Send(void){ - if(lanlink.type==0){ // TCP - if(savedlinktime==-1){ - outbuffer[0] = 4; - outbuffer[1] = -32; //0xe0 - for(i=1;i<=lanlink.numgbas;i++){ - send(tcpsocket[i], outbuffer, 4, 0); - recv(tcpsocket[i], inbuffer, 4, 0); - } - } - outbuffer[1] = tspeed; - u16outbuffer[1] = linkdata[0]; - intoutbuffer[1] = savedlinktime; - if(lanlink.numgbas==1){ - if(lanlink.type==0){ - outbuffer[0] = 8; - send(tcpsocket[1], outbuffer, 8, 0); - } - } - else if(lanlink.numgbas==2){ - u16outbuffer[4] = linkdata[2]; - if(lanlink.type==0){ - outbuffer[0] = 10; - send(tcpsocket[1], outbuffer, 10, 0); - u16outbuffer[4] = linkdata[1]; - send(tcpsocket[2], outbuffer, 10, 0); - } - } else { - if(lanlink.type==0){ - outbuffer[0] = 12; - u16outbuffer[4] = linkdata[2]; - u16outbuffer[5] = linkdata[3]; - send(tcpsocket[1], outbuffer, 12, 0); - u16outbuffer[4] = linkdata[1]; - send(tcpsocket[2], outbuffer, 12, 0); - u16outbuffer[5] = linkdata[2]; - send(tcpsocket[3], outbuffer, 12, 0); - } - } - } - return; -} - -void lserver::Recv(void){ - int numbytes; - if(lanlink.type==0){ // TCP - wsocktimeout.tv_usec = 0; - wsocktimeout.tv_sec = linktimeout / 1000; - fdset.fd_count = lanlink.numgbas; - for(i=0;i1) memcpy(inbuffer, inbuffer+inbuffer[0]*(howmanytimes-1), inbuffer[0]); - if(inbuffer[1]==-32){ - char message[30]; - lanlink.connected = false; - sprintf(message, "Player %d disconnected.", i+2); - MessageBox(NULL, message, "Link", MB_OK); - outbuffer[0] = 4; - outbuffer[1] = -32; - for(i=1;ih_addr_list); - - if(ioctlsocket(lanlink.tcpsocket, FIONBIO, ¬block)==SOCKET_ERROR) - return WSAGetLastError(); - - if(lanlink.thread!=NULL){ - lanlink.terminate = true; - WaitForSingleObject(linksync[vbaid], 500); - lanlink.thread = NULL; - } - - ((ServerWait*)waitdlg)->SetWindowText("Connecting..."); - lanlink.terminate = false; - lanlink.thread = CreateThread(NULL, 0, LinkClientThread, waitdlg, 0, ¬hing); - return 0; -} - -DWORD WINAPI LinkClientThread(void *waitdlg){ - fd_set fdset; - timeval wsocktimeout; - int numbytes; - char inbuffer[16]; - u16 *u16inbuffer = (u16*)inbuffer; - unsigned long block = 0; - - if(connect(lanlink.tcpsocket, (LPSOCKADDR)&lc.serverinfo, sizeof(SOCKADDR_IN))==SOCKET_ERROR){ - if(WSAGetLastError()!=WSAEWOULDBLOCK){ - MessageBox(NULL, "Couldn't connect to server.", "Link", MB_OK); - return 1; - } - wsocktimeout.tv_sec = 1; - wsocktimeout.tv_usec = 0; - do{ - if(lanlink.terminate) return 0; - fdset.fd_count = 1; - fdset.fd_array[0] = lanlink.tcpsocket; - ((ServerWait*)waitdlg)->m_prgctrl.StepIt(); - } while(select(0, NULL, &fdset, NULL, &wsocktimeout)!=1&&connect(lanlink.tcpsocket, (LPSOCKADDR)&lc.serverinfo, sizeof(SOCKADDR_IN))!=0); - } - - ioctlsocket(lanlink.tcpsocket, FIONBIO, &block); - - numbytes = 0; - while(numbytes<4) - numbytes += recv(lanlink.tcpsocket, inbuffer+numbytes, 16, 0); - linkid = (int)u16inbuffer[0]; - lanlink.numgbas = (int)u16inbuffer[1]; - - ((ServerWait*)waitdlg)->m_serveraddress.Format("Connected as #%d", linkid+1); - if(lanlink.numgbas!=linkid) ((ServerWait*)waitdlg)->m_plconn[0].Format("Waiting for %d players to join", lanlink.numgbas-linkid); - else ((ServerWait*)waitdlg)->m_plconn[0].Format("All players joined."); - - numbytes = 0; - inbuffer[0] = 1; - while(numbytesSendMessage(WM_CLOSE, 0, 0); - - block = 1; - - ioctlsocket(lanlink.tcpsocket, FIONBIO, &block); - - lanlink.connected = true; - return 0; -} - -void lclient::CheckConn(void){ - if((numbytes=recv(lanlink.tcpsocket, inbuffer, 256, 0))>0){ - while(numbytes +#include "../win32/stdafx.h" +#include "../port.h" +#include "GBALink.h" +#include "../win32/vba.h" +#include "../win32/MainWnd.h" +#include "../win32/LinkOptions.h" +#include "../win32/Reg.h" + +#define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]),value) +#define GBLINK_READY 8 + +int linktime = 0; +u8 tspeed=3; +u8 transfer=0; +LINKDATA *linkmem=NULL; +int linkid = 0, vbaid = 0; +HANDLE linksync[4]; +int savedlinktime=0; +HANDLE mmf=NULL; +char linkevent[] = "VBA link event "; +static int i, j; +int linktimeout = 1000; +int linklog = 0; +FILE *linklogfile = NULL; +LANLINKDATA lanlink; +u16 linkdata[4]; +int lspeed = 0; +lserver ls; +lclient lc; +bool oncewait = false, after = false; +bool adapter = false; +bool linkenable = false; +u8 rfu_cmd, rfu_qsend, rfu_qrecv; +int rfu_state, rfu_polarity, linktime2, counter, rfu_masterq; +int transferend, numtransfers = 0; +u32 rfu_masterdata[32]; + +extern unsigned char *gbMemory; +extern int gbInterrupt; + +int trtimedata[4][4] = {{34080, 8520, 5680, 2840}, {65536, 16384, 10923, 5461}, {99609, 24903, 16602, 8301}, {133692, 33423, 22282, 11141}}; +int trtimeend[3][4] = {{72527, 18132, 12088, 6044}, {106608, 26652, 17768, 8884}, {133692, 33423, 22282, 11141}}; +int gbtime = 1024; + +DWORD WINAPI LinkClientThread(void *); +DWORD WINAPI LinkServerThread(void *); +int StartServer(void); +int GetSioMode(u16, u16); +u16 StartRFU(u16); + +char *MakeInstanceFilename(const char *Input) +{ + if (vbaid == 0) + return (char *)Input; + + static char *result=NULL; + if (result!=NULL) + free(result); + + result = (char *)malloc(strlen(Input)+3); + char *p = strrchr((char *)Input, '.'); + sprintf(result, "%.*s-%d.%s", (int)(p-Input), Input, vbaid+1, p+1); + return result; +} + + +void StartLink(WORD value){ + if(ioMem==NULL) return; + if(adapter){ + UPDATE_REG(0x128, StartRFU(value)); + return; + } + switch(GetSioMode(value, READ16LE(&ioMem[0x134]))){ + case MULTIPLAYER: + if(value & 0x80){ + if(!linkid){ + if(!transfer){ + if(lanlink.active){ + if(lanlink.connected){ + linkdata[0] = READ16LE(&ioMem[0x12a]); + savedlinktime = linktime; + tspeed = value & 3; + ls.Send(); + transfer = 1; + linktime = 0; + UPDATE_REG(0x120, linkdata[0]); + UPDATE_REG(0x122, 0xffff); + WRITE32LE(&ioMem[0x124], 0xffffffff); + if(lanlink.speed&&oncewait==false) ls.howmanytimes++; + after = false; + } + } else if(linkmem->numgbas>1){ + ResetEvent(linksync[0]); + linkmem->linkcmd[0] = ('M'<<8)+(value&3); + linkmem->linkdata[0] = READ16LE(&ioMem[0x12a]); + if(linkmem->numtransfers!=0) linkmem->lastlinktime = linktime; + else linkmem->lastlinktime = 0; + if((++linkmem->numtransfers)==0) linkmem->numtransfers=2; + transfer = 1; + linktime = 0; + tspeed = value & 3; + WRITE32LE(&ioMem[0x120], 0xffffffff); + WRITE32LE(&ioMem[0x124], 0xffffffff); + } + } + } + value &= 0xff7f; + value |= (transfer!=0)<<7; + } + value &= 0xff8b; + value |= (linkid ? 0xc : 8); + value |= linkid<<4; + UPDATE_REG(0x128, value); + if(linkid) UPDATE_REG(0x134, 7); + else UPDATE_REG(0x134, 3); + break; + case NORMAL8: + if(linklog) fprintf(linklogfile, "Attempt to use 8-bit Normal mode %04x\n", value); + UPDATE_REG(0x128, value); + break; + case NORMAL32: + if(linklog) fprintf(linklogfile, "Attempt to use 32-bit Normal mode %04x %x%x\n", value, READ16LE(&ioMem[0x122]), READ16LE(&ioMem[0x120])); + UPDATE_REG(0x128, value); + break; + case UART: + if(linklog) fprintf(linklogfile, "Attempt to use UART mode %04x\n", value); + UPDATE_REG(0x128, value); + break; + default: + UPDATE_REG(0x128, value); + break; + } +} + +void StartGPLink(u16 value){ + if(!value){ + UPDATE_REG(0x134, 0); + return; + } + switch(GetSioMode(READ16LE(&ioMem[0x128]), value)){ + case MULTIPLAYER: + value &= 0xc0f0; + value |= 3; + if(linkid) value |= 4; + UPDATE_REG(0x134, value); + UPDATE_REG(0x128, ((READ16LE(&ioMem[0x128])&0xff8b)|(linkid ? 0xc : 8)|(linkid<<4))); + return; + break; + case GP: + if(linklog){ + if(value==0x8000) fprintf(linklogfile, "Circuit reset\n"); + else if(!adapter) fprintf(linklogfile, "Attempt to use General-purpose mode %04x\n", value); + } + if(adapter) rfu_state = RFU_INIT; + // This was not there, but sonic games won't start if it's not here. + UPDATE_REG(0x134, value); + break; + case JOYBUS: + UPDATE_REG(0x134, value); + break; + default: + UPDATE_REG(0x134, value); + break; + } + return; +} + +void StartJOYLink(u16 value){ + if(!value){ + UPDATE_REG(0x140, 0); + return; + } + if(GetSioMode(READ16LE(&ioMem[0x128]), READ16LE(&ioMem[0x134]))==JOYBUS&&linklog) fprintf(linklogfile, "Attempt to use JOY-BUS mode %04x\n", value); + return; +} + +void LinkUpdate(int ticks){ + linktime += ticks; + if(adapter){ + linktime2 += ticks; + transferend -= ticks; + if(transfer&&transferend<=0){ + transfer = 0; + if(READ16LE(&ioMem[0x128])&0x4000){ + IF |= 0x80; + UPDATE_REG(0x202, IF); + } + UPDATE_REG(0x128, READ16LE(&ioMem[0x128]) & 0xff7f); + } + return; + } + + if(lanlink.active){ + if(lanlink.connected){ + if(after){ + if(linkid&&linktime>6044){ + lc.Recv(); + oncewait = true; + } else return; + } + if(linkid&&!transfer&&lc.numtransfers>0&&linktime>=savedlinktime){ + linkdata[linkid] = READ16LE(&ioMem[0x12a]); + if(!lc.oncesend) lc.Send(); + lc.oncesend = false; + UPDATE_REG(0x120, linkdata[0]); + UPDATE_REG(0x128, READ16LE(&ioMem[0x128]) | 0x80); + transfer = 1; + if(lc.numtransfers==1) linktime = 0; + else linktime -= savedlinktime; + } + if(transfer&&linktime>=trtimeend[lanlink.numgbas-1][tspeed]){ + if(READ16LE(&ioMem[0x128]) & 0x4000){ + IF |= 0x80; + UPDATE_REG(0x202, IF); + } + UPDATE_REG(0x128, (READ16LE(&ioMem[0x128]) & 0xff0f) | (linkid << 4)); + transfer = 0; + linktime -= trtimeend[lanlink.numgbas-1][tspeed]; + oncewait = false; + if(!lanlink.speed){ + if(linkid) lc.Recv(); + else ls.Recv(); + UPDATE_REG(0x122, linkdata[1]); + UPDATE_REG(0x124, linkdata[2]); + UPDATE_REG(0x126, linkdata[3]); + if(linklog) fprintf(linklogfile, "%04x %04x %04x %04x %10u\n", linkdata[0], linkdata[1], linkdata[2], linkdata[3], savedlinktime); + oncewait = true; + } else { + after = true; + if(lanlink.numgbas==1){ + UPDATE_REG(0x122, linkdata[1]); + UPDATE_REG(0x124, linkdata[2]); + UPDATE_REG(0x126, linkdata[3]); + if(linklog) fprintf(linklogfile, "%04x %04x %04x %04x %10u\n", linkdata[0], linkdata[1], linkdata[2], linkdata[3], savedlinktime); + } + + } + } + } + return; + } + // ** CRASH ** linkmem is NULL, todo investigate why, added null check + if(linkid&&!transfer&&linkmem&&linktime>=linkmem->lastlinktime&&linkmem->numtransfers){ + linkmem->linkdata[linkid] = READ16LE(&ioMem[0x12a]); + + if(linkmem->numtransfers==1){ + linktime = 0; + if(WaitForSingleObject(linksync[linkid], linktimeout)==WAIT_TIMEOUT) linkmem->numtransfers=0; + } else linktime -= linkmem->lastlinktime; + + switch((linkmem->linkcmd[0])>>8){ + case 'M': + tspeed = (linkmem->linkcmd[0]) & 3; + transfer = 1; + WRITE32LE(&ioMem[0x120], 0xffffffff); + WRITE32LE(&ioMem[0x124], 0xffffffff); + UPDATE_REG(0x128, READ16LE(&ioMem[0x128]) | 0x80); + break; + } + } + + if(!transfer) return; + + if(transfer&&linktime>=trtimedata[transfer-1][tspeed]&&transfer<=linkmem->numgbas){ + if(transfer-linkid==2){ + SetEvent(linksync[linkid+1]); + if(WaitForSingleObject(linksync[linkid], linktimeout)==WAIT_TIMEOUT) + linkmem->numtransfers=0; + ResetEvent(linksync[linkid]); + if(linklog) fprintf(linklogfile, "%04x %04x %04x %04x %10u\n", + linkmem->linkdata[0], linkmem->linkdata[1], linkmem->linkdata[2], linkmem->linkdata[3], linkmem->lastlinktime); + } + + + UPDATE_REG(0x11e + (transfer<<1), linkmem->linkdata[transfer-1]); + transfer++; + } + + if(transfer&&linktime>=trtimeend[linkmem->numgbas-2][tspeed]){ + if(linkid==linkmem->numgbas-1){ + SetEvent(linksync[0]); + if(WaitForSingleObject(linksync[linkid], linktimeout)==WAIT_TIMEOUT) + linkmem->numtransfers=0; + ResetEvent(linksync[linkid]); + if(linklog) fprintf(linklogfile, "%04x %04x %04x %04x %10u\n", + linkmem->linkdata[0], linkmem->linkdata[1], linkmem->linkdata[2], linkmem->linkdata[3], linkmem->lastlinktime); + } + transfer = 0; + linktime -= trtimeend[0][tspeed]; + if(READ16LE(&ioMem[0x128]) & 0x4000){ + IF |= 0x80; + UPDATE_REG(0x202, IF); + } + UPDATE_REG(0x128, (READ16LE(&ioMem[0x128]) & 0xff0f) | (linkid << 4)); + linkmem->linkdata[linkid] = 0xffff; + } + + return; +} + +inline int GetSioMode(u16 reg1, u16 reg2){ + if(!(reg2&0x8000)){ + switch(reg1&0x3000){ + case 0x0000: + return NORMAL8; + case 0x1000: + return NORMAL32; + case 0x2000: + return MULTIPLAYER; + case 0x3000: + return UART; + } + } + if(reg2&0x4000) return JOYBUS; + return GP; +} + +u16 StartRFU(u16 value){ + switch(GetSioMode(value, READ16LE(&ioMem[0x134]))){ + case NORMAL8: + rfu_polarity = 0; + return value; + break; + case NORMAL32: + if(value&8) value &= 0xfffb; // A kind of acknowledge procedure + else value |= 4; + if(value&0x80){ + if((value&3)==1) transferend = 2048; + else transferend = 256; + u16 a = READ16LE(&ioMem[0x122]); + switch(rfu_state){ + case RFU_INIT: + if(READ32LE(&ioMem[0x120])==0xb0bb8001){ + rfu_state = RFU_COMM; // end of startup + } + UPDATE_REG(0x122, READ16LE(&ioMem[0x120])); + UPDATE_REG(0x120, a); + break; + case RFU_COMM: + if(a==0x9966){ + rfu_cmd = ioMem[0x120]; + if((rfu_qsend=ioMem[0x121])!=0){ + rfu_state = RFU_SEND; + counter = 0; + } + if(rfu_cmd==0x25||rfu_cmd==0x24){ + linkmem->rfu_q[vbaid] = rfu_qsend; + } + UPDATE_REG(0x120, 0); + UPDATE_REG(0x122, 0x8000); + } else if(a==0x8000){ + switch(rfu_cmd){ + case 0x1a: // check if someone joined + if(linkmem->rfu_request[vbaid]!=0){ + rfu_state = RFU_RECV; + rfu_qrecv = 1; + } + linkid = -1; + rfu_cmd |= 0x80; + break; + case 0x1e: // receive broadcast data + case 0x1d: // no visible difference + rfu_polarity = 0; + rfu_state = RFU_RECV; + rfu_qrecv = 7; + counter = 0; + rfu_cmd |= 0x80; + break; + case 0x30: + linkmem->rfu_request[vbaid] = 0; + linkmem->rfu_q[vbaid] = 0; + linkid = 0; + numtransfers = 0; + rfu_cmd |= 0x80; + if(linkmem->numgbas==2) SetEvent(linksync[1-vbaid]); + break; + case 0x11: // ? always receives 0xff - I suspect it's something for 3+ players + case 0x13: // unknown + case 0x20: // this has something to do with 0x1f + case 0x21: // this too + rfu_cmd |= 0x80; + rfu_polarity = 0; + rfu_state = 3; + rfu_qrecv = 1; + break; + case 0x26: + if(linkid>0){ + rfu_qrecv = rfu_masterq; + } + if((rfu_qrecv=linkmem->rfu_q[1-vbaid])!=0){ + rfu_state = RFU_RECV; + counter = 0; + } + rfu_cmd |= 0x80; + break; + case 0x24: // send data + if((numtransfers++)==0) linktime = 1; + linkmem->rfu_linktime[vbaid] = linktime; + if(linkmem->numgbas==2){ + SetEvent(linksync[1-vbaid]); + WaitForSingleObject(linksync[vbaid], linktimeout); + ResetEvent(linksync[vbaid]); + } + rfu_cmd |= 0x80; + linktime = 0; + linkid = -1; + break; + case 0x25: // send & wait for data + case 0x1f: // pick a server + case 0x10: // init + case 0x16: // send broadcast data + case 0x17: // setup or something ? + case 0x27: // wait for data ? + case 0x3d: // init + default: + rfu_cmd |= 0x80; + break; + case 0xa5: // 2nd part of send&wait function 0x25 + case 0xa7: // 2nd part of wait function 0x27 + if(linkid==-1){ + linkid++; + linkmem->rfu_linktime[vbaid] = 0; + } + if(linkid&&linkmem->rfu_request[1-vbaid]==0){ + linkmem->rfu_q[1-vbaid] = 0; + transferend = 256; + rfu_polarity = 1; + rfu_cmd = 0x29; + linktime = 0; + break; + } + if((numtransfers++)==0) linktime = 0; + linkmem->rfu_linktime[vbaid] = linktime; + if(linkmem->numgbas==2){ + if(!linkid||(linkid&&numtransfers)) SetEvent(linksync[1-vbaid]); + WaitForSingleObject(linksync[vbaid], linktimeout); + ResetEvent(linksync[vbaid]); + } + if(linkid>0){ + memcpy(rfu_masterdata, linkmem->rfu_data[1-vbaid], 128); + rfu_masterq = linkmem->rfu_q[1-vbaid]; + } + transferend = linkmem->rfu_linktime[1-vbaid] - linktime + 256; + if(transferend<256) transferend = 256; + linktime = -transferend; + rfu_polarity = 1; + rfu_cmd = 0x28; + break; + } + UPDATE_REG(0x122, 0x9966); + UPDATE_REG(0x120, (rfu_qrecv<<8) | rfu_cmd); + } else { + UPDATE_REG(0x120, 0); + UPDATE_REG(0x122, 0x8000); + } + break; + case RFU_SEND: + if(--rfu_qsend==0) rfu_state = RFU_COMM; + switch(rfu_cmd){ + case 0x16: + linkmem->rfu_bdata[vbaid][counter++] = READ32LE(&ioMem[0x120]); + break; + case 0x17: + linkid = 1; + break; + case 0x1f: + linkmem->rfu_request[1-vbaid] = 1; + break; + case 0x24: + case 0x25: + linkmem->rfu_data[vbaid][counter++] = READ32LE(&ioMem[0x120]); + break; + } + UPDATE_REG(0x120, 0); + UPDATE_REG(0x122, 0x8000); + break; + case RFU_RECV: + if(--rfu_qrecv==0) rfu_state = RFU_COMM; + switch(rfu_cmd){ + case 0x9d: + case 0x9e: + if(counter==0){ + UPDATE_REG(0x120, 0x61f1); + UPDATE_REG(0x122, 0); + counter++; + break; + } + UPDATE_REG(0x120, linkmem->rfu_bdata[1-vbaid][counter-1]&0xffff); + UPDATE_REG(0x122, linkmem->rfu_bdata[1-vbaid][counter-1]>>16); + counter++; + break; + case 0xa6: + if(linkid>0){ + UPDATE_REG(0x120, rfu_masterdata[counter]&0xffff); + UPDATE_REG(0x122, rfu_masterdata[counter++]>>16); + } else { + UPDATE_REG(0x120, linkmem->rfu_data[1-vbaid][counter]&0xffff); + UPDATE_REG(0x122, linkmem->rfu_data[1-vbaid][counter++]>>16); + } + break; + case 0x93: // it seems like the game doesn't care about this value + UPDATE_REG(0x120, 0x1234); // put anything in here + UPDATE_REG(0x122, 0x0200); // also here, but it should be 0200 + break; + case 0xa0: + case 0xa1: + UPDATE_REG(0x120, 0x641b); + UPDATE_REG(0x122, 0x0000); + break; + case 0x9a: + UPDATE_REG(0x120, 0x61f9); + UPDATE_REG(0x122, 0); + break; + case 0x91: + UPDATE_REG(0x120, 0x00ff); + UPDATE_REG(0x122, 0x0000); + break; + default: + UPDATE_REG(0x120, 0x0173); + UPDATE_REG(0x122, 0x0000); + break; + } + break; + } + transfer = 1; + } + if(rfu_polarity) value ^= 4; // sometimes it's the other way around + default: + return value; + } +} + +void gbLinkStart(u8 value){ +// Not in this version :-) +} + + +void gbLinkUpdate(void){ +} + +int InitLink(void){ + WSADATA wsadata; + BOOL disable = true; + + linkid = 0; + + if(WSAStartup(MAKEWORD(1,1), &wsadata)!=0){ + WSACleanup(); + return 0; + } + + if((lanlink.tcpsocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET){ + MessageBox(NULL, "Couldn't create socket.", "Error!", MB_OK); + WSACleanup(); + return 0; + } + + setsockopt(lanlink.tcpsocket, IPPROTO_TCP, TCP_NODELAY, (char*)&disable, sizeof(BOOL)); + + if((mmf=CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(LINKDATA), "VBA link memory"))==NULL){ + closesocket(lanlink.tcpsocket); + WSACleanup(); + MessageBox(NULL, "Error creating file mapping", "Error", MB_OK|MB_ICONEXCLAMATION); + return 0; + } + + if(GetLastError() == ERROR_ALREADY_EXISTS) + vbaid = 1; + else + vbaid = 0; + + if((linkmem=(LINKDATA *)MapViewOfFile(mmf, FILE_MAP_WRITE, 0, 0, sizeof(LINKDATA)))==NULL){ + closesocket(lanlink.tcpsocket); + WSACleanup(); + CloseHandle(mmf); + MessageBox(NULL, "Error mapping file", "Error", MB_OK|MB_ICONEXCLAMATION); + return 0; + } + + if(linkmem->linkflags&LINK_PARENTLOST) + vbaid = 0; + + if(vbaid==0){ + linkid = 0; + if(linkmem->linkflags&LINK_PARENTLOST){ + linkmem->numgbas++; + linkmem->linkflags &= ~LINK_PARENTLOST; + } + else + linkmem->numgbas=1; + + for(i=0;i<4;i++){ + linkevent[15]=(char)i+'1'; + if((linksync[i]=CreateEvent(NULL, true, false, linkevent))==NULL){ + closesocket(lanlink.tcpsocket); + WSACleanup(); + UnmapViewOfFile(linkmem); + CloseHandle(mmf); + for(j=0;jnumgbas; + linkid = vbaid; + linkmem->numgbas++; + + linklog = 0; + if(linkmem->numgbas>4){ + linkmem->numgbas=4; + closesocket(lanlink.tcpsocket); + WSACleanup(); + MessageBox(NULL, "5 or more GBAs not supported.", "Error!", MB_OK|MB_ICONEXCLAMATION); + UnmapViewOfFile(linkmem); + CloseHandle(mmf); + return 0; + } + for(i=0;i<4;i++){ + linkevent[15]=(char)i+'1'; + if((linksync[i]=OpenEvent(EVENT_ALL_ACCESS, false, linkevent))==NULL){ + closesocket(lanlink.tcpsocket); + WSACleanup(); + CloseHandle(mmf); + UnmapViewOfFile(linkmem); + for(j=0;jlastlinktime=0xffffffff; + linkmem->numtransfers=0; + linkmem->linkflags=0; + lanlink.connected = false; + lanlink.thread = NULL; + lanlink.speed = false; + for(i=0;i<4;i++){ + linkmem->linkdata[i] = 0xffff; + linkdata[i] = 0xffff; + } +return 1; +} + +int openLinkLog(void){ + char filename[20]; + if(linklog){ + sprintf(filename, "vbalog%1d.txt", vbaid+1); + if((linklogfile=fopen(filename, "at"))==NULL){ + linklog=false; + return 0; + } + fprintf(linklogfile, "----- Log opened -----\n"); + } + return 1; +} + +void closeLinkLog() +{ + if(linklogfile) + { + fclose(linklogfile); + linklogfile=NULL; + } +} + +void CloseLink(void){ + if(lanlink.connected){ + if(linkid){ + char outbuffer[4]; + outbuffer[0] = 4; + outbuffer[1] = -32; + if(lanlink.type==0) send(lanlink.tcpsocket, outbuffer, 4, 0); + } else { + char outbuffer[12]; + int i; + outbuffer[0] = 12; + outbuffer[1] = -32; + for(i=1;i<=lanlink.numgbas;i++){ + if(lanlink.type==0){ + send(ls.tcpsocket[i], outbuffer, 12, 0); + } + closesocket(ls.tcpsocket[i]); + } + } + } + linkmem->numgbas--; + if(!linkid&&linkmem->numgbas!=0) + linkmem->linkflags|=LINK_PARENTLOST; + CloseHandle(mmf); + UnmapViewOfFile(linkmem); + + for(i=0;i<4;i++){ + if(linksync[i]!=NULL){ + PulseEvent(linksync[i]); + CloseHandle(linksync[i]); + } + } + regSetDwordValue("LAN", lanlink.active); + if(linklog) closeLinkLog(); + closesocket(lanlink.tcpsocket); + WSACleanup(); +return; +} + +lserver::lserver(void){ + intinbuffer = (int*)inbuffer; + u16inbuffer = (u16*)inbuffer; + intoutbuffer = (int*)outbuffer; + u16outbuffer = (u16*)outbuffer; + oncewait = false; +} + +int lserver::Init(void *serverdlg){ + SOCKADDR_IN info; + DWORD nothing; + char str[100]; + + info.sin_family = AF_INET; + info.sin_addr.S_un.S_addr = INADDR_ANY; + info.sin_port = htons(5738); + + if(bind(lanlink.tcpsocket, (LPSOCKADDR)&info, sizeof(SOCKADDR_IN))==SOCKET_ERROR){ + closesocket(lanlink.tcpsocket); + if((lanlink.tcpsocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET) + return WSAGetLastError(); + if(bind(lanlink.tcpsocket, (LPSOCKADDR)&info, sizeof(SOCKADDR_IN))==SOCKET_ERROR) + return WSAGetLastError(); + } + + if(listen(lanlink.tcpsocket, lanlink.numgbas)==SOCKET_ERROR) + return WSAGetLastError(); + + if(lanlink.thread!=NULL){ + lanlink.terminate = true; + WaitForSingleObject(linksync[vbaid], 500); + lanlink.thread = NULL; + } + lanlink.terminate = false; + linkid = 0; + + gethostname(str, 100); + ((ServerWait*)serverdlg)->m_serveraddress.Format("Server IP address is: %s", inet_ntoa(*(LPIN_ADDR)(gethostbyname(str)->h_addr_list[0]))); + + lanlink.thread = CreateThread(NULL, 0, LinkServerThread, serverdlg, 0, ¬hing); + + return 0; + +} + +DWORD WINAPI LinkServerThread(void *serverdlg){ + fd_set fdset; + timeval wsocktimeout; + char inbuffer[256], outbuffer[256]; + int *intinbuffer = (int*)inbuffer; + u16 *u16inbuffer = (u16*)inbuffer; + int *intoutbuffer = (int*)outbuffer; + u16 *u16outbuffer = (u16*)outbuffer; + BOOL disable = true; + + wsocktimeout.tv_sec = 1; + wsocktimeout.tv_usec = 0; + i = 0; + + while(im_plconn[i].Format("Player %d connected", i+1); + ((ServerWait*)serverdlg)->UpdateData(false); + i++; + } + } + ((ServerWait*)serverdlg)->m_prgctrl.StepIt(); + } + MessageBox(NULL, "All players connected", "Link", MB_OK); + ((ServerWait*)serverdlg)->SendMessage(WM_CLOSE, 0, 0); + + for(i=1;i<=lanlink.numgbas;i++){ + outbuffer[0] = 4; + send(ls.tcpsocket[i], outbuffer, 4, 0); + } + + lanlink.connected = true; + + return 0; +} + +void lserver::Send(void){ + if(lanlink.type==0){ // TCP + if(savedlinktime==-1){ + outbuffer[0] = 4; + outbuffer[1] = -32; //0xe0 + for(i=1;i<=lanlink.numgbas;i++){ + send(tcpsocket[i], outbuffer, 4, 0); + recv(tcpsocket[i], inbuffer, 4, 0); + } + } + outbuffer[1] = tspeed; + u16outbuffer[1] = linkdata[0]; + intoutbuffer[1] = savedlinktime; + if(lanlink.numgbas==1){ + if(lanlink.type==0){ + outbuffer[0] = 8; + send(tcpsocket[1], outbuffer, 8, 0); + } + } + else if(lanlink.numgbas==2){ + u16outbuffer[4] = linkdata[2]; + if(lanlink.type==0){ + outbuffer[0] = 10; + send(tcpsocket[1], outbuffer, 10, 0); + u16outbuffer[4] = linkdata[1]; + send(tcpsocket[2], outbuffer, 10, 0); + } + } else { + if(lanlink.type==0){ + outbuffer[0] = 12; + u16outbuffer[4] = linkdata[2]; + u16outbuffer[5] = linkdata[3]; + send(tcpsocket[1], outbuffer, 12, 0); + u16outbuffer[4] = linkdata[1]; + send(tcpsocket[2], outbuffer, 12, 0); + u16outbuffer[5] = linkdata[2]; + send(tcpsocket[3], outbuffer, 12, 0); + } + } + } + return; +} + +void lserver::Recv(void){ + int numbytes; + if(lanlink.type==0){ // TCP + wsocktimeout.tv_usec = 0; + wsocktimeout.tv_sec = linktimeout / 1000; + fdset.fd_count = lanlink.numgbas; + for(i=0;i1) memcpy(inbuffer, inbuffer+inbuffer[0]*(howmanytimes-1), inbuffer[0]); + if(inbuffer[1]==-32){ + char message[30]; + lanlink.connected = false; + sprintf(message, "Player %d disconnected.", i+2); + MessageBox(NULL, message, "Link", MB_OK); + outbuffer[0] = 4; + outbuffer[1] = -32; + for(i=1;ih_addr_list); + + if(ioctlsocket(lanlink.tcpsocket, FIONBIO, ¬block)==SOCKET_ERROR) + return WSAGetLastError(); + + if(lanlink.thread!=NULL){ + lanlink.terminate = true; + WaitForSingleObject(linksync[vbaid], 500); + lanlink.thread = NULL; + } + + ((ServerWait*)waitdlg)->SetWindowText("Connecting..."); + lanlink.terminate = false; + lanlink.thread = CreateThread(NULL, 0, LinkClientThread, waitdlg, 0, ¬hing); + return 0; +} + +DWORD WINAPI LinkClientThread(void *waitdlg){ + fd_set fdset; + timeval wsocktimeout; + int numbytes; + char inbuffer[16]; + u16 *u16inbuffer = (u16*)inbuffer; + unsigned long block = 0; + + if(connect(lanlink.tcpsocket, (LPSOCKADDR)&lc.serverinfo, sizeof(SOCKADDR_IN))==SOCKET_ERROR){ + if(WSAGetLastError()!=WSAEWOULDBLOCK){ + MessageBox(NULL, "Couldn't connect to server.", "Link", MB_OK); + return 1; + } + wsocktimeout.tv_sec = 1; + wsocktimeout.tv_usec = 0; + do{ + if(lanlink.terminate) return 0; + fdset.fd_count = 1; + fdset.fd_array[0] = lanlink.tcpsocket; + ((ServerWait*)waitdlg)->m_prgctrl.StepIt(); + } while(select(0, NULL, &fdset, NULL, &wsocktimeout)!=1&&connect(lanlink.tcpsocket, (LPSOCKADDR)&lc.serverinfo, sizeof(SOCKADDR_IN))!=0); + } + + ioctlsocket(lanlink.tcpsocket, FIONBIO, &block); + + numbytes = 0; + while(numbytes<4) + numbytes += recv(lanlink.tcpsocket, inbuffer+numbytes, 16, 0); + linkid = (int)u16inbuffer[0]; + lanlink.numgbas = (int)u16inbuffer[1]; + + ((ServerWait*)waitdlg)->m_serveraddress.Format("Connected as #%d", linkid+1); + if(lanlink.numgbas!=linkid) ((ServerWait*)waitdlg)->m_plconn[0].Format("Waiting for %d players to join", lanlink.numgbas-linkid); + else ((ServerWait*)waitdlg)->m_plconn[0].Format("All players joined."); + + numbytes = 0; + inbuffer[0] = 1; + while(numbytesSendMessage(WM_CLOSE, 0, 0); + + block = 1; + + ioctlsocket(lanlink.tcpsocket, FIONBIO, &block); + + lanlink.connected = true; + return 0; +} + +void lclient::CheckConn(void){ + if((numbytes=recv(lanlink.tcpsocket, inbuffer, 256, 0))>0){ + while(numbytes - -#ifndef LINKH -#define LINKH -#define LINK_PARENTLOST 0x80 -#define UNSUPPORTED -1 -#define MULTIPLAYER 0 -#define NORMAL8 1 -#define NORMAL32 2 -#define UART 3 -#define JOYBUS 4 -#define GP 5 -#define RFU_INIT 0 -#define RFU_COMM 1 -#define RFU_SEND 2 -#define RFU_RECV 3 - -typedef struct { - WORD linkdata[4]; - WORD linkcmd[4]; - WORD numtransfers; - int lastlinktime; - unsigned char numgbas; - unsigned char linkflags; - int rfu_q[4]; - u8 rfu_request[4]; - int rfu_linktime[4]; - u32 rfu_bdata[4][7]; - u32 rfu_data[4][32]; -} LINKDATA; - -class lserver{ - int numbytes; - fd_set fdset; - timeval wsocktimeout; - //timeval udptimeout; - char inbuffer[256], outbuffer[256]; - int *intinbuffer; - u16 *u16inbuffer; - int *intoutbuffer; - u16 *u16outbuffer; - int counter; - int done; -public: - int howmanytimes; - SOCKET tcpsocket[4]; - SOCKADDR_IN udpaddr[4]; - lserver(void); - int Init(void*); - void Send(void); - void Recv(void); -}; - -class lclient{ - fd_set fdset; - timeval wsocktimeout; - char inbuffer[256], outbuffer[256]; - int *intinbuffer; - u16 *u16inbuffer; - int *intoutbuffer; - u16 *u16outbuffer; - int numbytes; -public: - bool oncesend; - SOCKADDR_IN serverinfo; - SOCKET noblock; - int numtransfers; - lclient(void); - int Init(LPHOSTENT, void*); - void Send(void); - void Recv(void); - void CheckConn(void); -}; - -typedef struct { - SOCKET tcpsocket; - //SOCKET udpsocket; - int numgbas; - HANDLE thread; - u8 type; - u8 server; - bool terminate; - bool connected; - bool speed; - bool active; -} LANLINKDATA; - -extern void LinkUpdate(void); -extern void LinkChildStop(void); -extern void LinkChildSend(u16); -extern int openLinkLog(void); -extern void closeLinkLog(); -extern void CloseLanLink(void); -extern char *MakeInstanceFilename(const char *Input); - -extern LANLINKDATA lanlink; -extern FILE *linklogfile; -extern int vbaid; -extern int linklog; -extern bool adapter; -extern bool linkenable; -extern int linktimeout; -extern lclient lc; -extern int linkid; - -#endif +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include + +#ifndef LINKH +#define LINKH +#define LINK_PARENTLOST 0x80 +#define UNSUPPORTED -1 +#define MULTIPLAYER 0 +#define NORMAL8 1 +#define NORMAL32 2 +#define UART 3 +#define JOYBUS 4 +#define GP 5 +#define RFU_INIT 0 +#define RFU_COMM 1 +#define RFU_SEND 2 +#define RFU_RECV 3 + +typedef struct { + WORD linkdata[4]; + WORD linkcmd[4]; + WORD numtransfers; + int lastlinktime; + unsigned char numgbas; + unsigned char linkflags; + int rfu_q[4]; + u8 rfu_request[4]; + int rfu_linktime[4]; + u32 rfu_bdata[4][7]; + u32 rfu_data[4][32]; +} LINKDATA; + +class lserver{ + int numbytes; + fd_set fdset; + timeval wsocktimeout; + //timeval udptimeout; + char inbuffer[256], outbuffer[256]; + int *intinbuffer; + u16 *u16inbuffer; + int *intoutbuffer; + u16 *u16outbuffer; + int counter; + int done; +public: + int howmanytimes; + SOCKET tcpsocket[4]; + SOCKADDR_IN udpaddr[4]; + lserver(void); + int Init(void*); + void Send(void); + void Recv(void); +}; + +class lclient{ + fd_set fdset; + timeval wsocktimeout; + char inbuffer[256], outbuffer[256]; + int *intinbuffer; + u16 *u16inbuffer; + int *intoutbuffer; + u16 *u16outbuffer; + int numbytes; +public: + bool oncesend; + SOCKADDR_IN serverinfo; + SOCKET noblock; + int numtransfers; + lclient(void); + int Init(LPHOSTENT, void*); + void Send(void); + void Recv(void); + void CheckConn(void); +}; + +typedef struct { + SOCKET tcpsocket; + //SOCKET udpsocket; + int numgbas; + HANDLE thread; + u8 type; + u8 server; + bool terminate; + bool connected; + bool speed; + bool active; +} LANLINKDATA; + +extern void LinkUpdate(void); +extern void LinkChildStop(void); +extern void LinkChildSend(u16); +extern int openLinkLog(void); +extern void closeLinkLog(); +extern void CloseLanLink(void); +extern char *MakeInstanceFilename(const char *Input); + +extern LANLINKDATA lanlink; +extern FILE *linklogfile; +extern int vbaid; +extern int linklog; +extern bool adapter; +extern bool linkenable; +extern int linktimeout; +extern lclient lc; +extern int linkid; + +#endif diff --git a/src/agb/GBAcpu.h b/src/agb/GBAcpu.h index c617b140..53384e9d 100644 --- a/src/agb/GBAcpu.h +++ b/src/agb/GBAcpu.h @@ -1,302 +1,302 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef VBA_GBAcpu_H -#define VBA_GBAcpu_H - -extern int armExecute(); -extern int thumbExecute(); - -#ifdef __GNUC__ -# define INSN_REGPARM __attribute__((regparm(1))) -# define LIKELY(x) __builtin_expect(!!(x),1) -# define UNLIKELY(x) __builtin_expect(!!(x),0) -#else -# define INSN_REGPARM /*nothing*/ -# define LIKELY(x) (x) -# define UNLIKELY(x) (x) -#endif - -#define UPDATE_REG(address, value)\ - {\ - WRITE16LE(((u16 *)&ioMem[address]),value);\ - }\ - -#define ARM_PREFETCH \ - {\ - cpuPrefetch[0] = CPUReadMemoryQuick(armNextPC);\ - cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);\ - } - -#define THUMB_PREFETCH \ - {\ - cpuPrefetch[0] = CPUReadHalfWordQuick(armNextPC);\ - cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);\ - } - -#define ARM_PREFETCH_NEXT \ - cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4); - -#define THUMB_PREFETCH_NEXT\ - cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2); - - -extern int SWITicks; -extern u32 mastercode; -extern bool busPrefetch; -extern bool busPrefetchEnable; -extern u32 busPrefetchCount; -extern int cpuNextEvent; -extern bool holdState; -extern u32 cpuPrefetch[2]; -extern int cpuTotalTicks; -extern u8 memoryWait[16]; -extern u8 memoryWait32[16]; -extern u8 memoryWaitSeq[16]; -extern u8 memoryWaitSeq32[16]; -extern u8 cpuBitsSet[256]; -extern u8 cpuLowestBitSet[256]; -extern void CPUSwitchMode(int mode, bool saveState, bool breakLoop); -extern void CPUSwitchMode(int mode, bool saveState); -extern void CPUUpdateCPSR(); -extern void CPUUpdateFlags(bool breakLoop); -extern void CPUUpdateFlags(); -extern void CPUUndefinedException(); -extern void CPUSoftwareInterrupt(); -extern void CPUSoftwareInterrupt(int comment); - - -// Waitstates when accessing data -inline int dataTicksAccess16(u32 address) // DATA 8/16bits NON SEQ -{ - int addr = (address>>24)&15; - int value = memoryWait[addr]; - - if ((addr>=0x08) || (addr < 0x02)) - { - busPrefetchCount=0; - busPrefetch=false; - } - else if (busPrefetch) - { - int waitState = value; - if (!waitState) - waitState = 1; - busPrefetchCount = ((busPrefetchCount+1)<>24)&15; - int value = memoryWait32[addr]; - - if ((addr>=0x08) || (addr < 0x02)) - { - busPrefetchCount=0; - busPrefetch=false; - } - else if (busPrefetch) - { - int waitState = value; - if (!waitState) - waitState = 1; - busPrefetchCount = ((busPrefetchCount+1)<>24)&15; - int value = memoryWaitSeq[addr]; - - if ((addr>=0x08) || (addr < 0x02)) - { - busPrefetchCount=0; - busPrefetch=false; - } - else if (busPrefetch) - { - int waitState = value; - if (!waitState) - waitState = 1; - busPrefetchCount = ((busPrefetchCount+1)<>24)&15; - int value = memoryWaitSeq32[addr]; - - if ((addr>=0x08) || (addr < 0x02)) - { - busPrefetchCount=0; - busPrefetch=false; - } - else if (busPrefetch) - { - int waitState = value; - if (!waitState) - waitState = 1; - busPrefetchCount = ((busPrefetchCount+1)<>24)&15; - - if ((addr>=0x08) && (addr<=0x0D)) - { - if (busPrefetchCount&0x1) - { - if (busPrefetchCount&0x2) - { - busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00); - return 0; - } - busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00); - return memoryWaitSeq[addr]-1; - } - else - { - busPrefetchCount=0; - return memoryWait[addr]; - } - } - else - { - busPrefetchCount = 0; - return memoryWait[addr]; - } -} - -inline int codeTicksAccess32(u32 address) // ARM NON SEQ -{ - int addr = (address>>24)&15; - - if ((addr>=0x08) && (addr<=0x0D)) - { - if (busPrefetchCount&0x1) - { - if (busPrefetchCount&0x2) - { - busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00); - return 0; - } - busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00); - return memoryWaitSeq[addr] - 1; - } - else - { - busPrefetchCount = 0; - return memoryWait32[addr]; - } - } - else - { - busPrefetchCount = 0; - return memoryWait32[addr]; - } -} - -inline int codeTicksAccessSeq16(u32 address) // THUMB SEQ -{ - int addr = (address>>24)&15; - - if ((addr>=0x08) && (addr<=0x0D)) - { - if (busPrefetchCount&0x1) - { - busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00); - return 0; - } - else - if (busPrefetchCount>0xFF) - { - busPrefetchCount=0; - return memoryWait[addr]; - } - else - return memoryWaitSeq[addr]; - } - else - { - busPrefetchCount = 0; - return memoryWaitSeq[addr]; - } -} - -inline int codeTicksAccessSeq32(u32 address) // ARM SEQ -{ - int addr = (address>>24)&15; - - if ((addr>=0x08) && (addr<=0x0D)) - { - if (busPrefetchCount&0x1) - { - if (busPrefetchCount&0x2) - { - busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00); - return 0; - } - busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00); - return memoryWaitSeq[addr]; - } - else - if (busPrefetchCount>0xFF) - { - busPrefetchCount=0; - return memoryWait32[addr]; - } - else - return memoryWaitSeq32[addr]; - } - else - { - return memoryWaitSeq32[addr]; - } -} - - -// Emulates the Cheat System (m) code -inline void cpuMasterCodeCheck() -{ - if((mastercode) && (mastercode == armNextPC)) - { - u32 joy = 0; - if(systemReadJoypads()) - joy = systemReadJoypad(-1); - u32 ext = (joy >> 10); - cpuTotalTicks += cheatsCheckKeys(P1^0x3FF, ext); - } -} - -#endif //VBA_GBAcpu_H +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef VBA_GBAcpu_H +#define VBA_GBAcpu_H + +extern int armExecute(); +extern int thumbExecute(); + +#ifdef __GNUC__ +# define INSN_REGPARM __attribute__((regparm(1))) +# define LIKELY(x) __builtin_expect(!!(x),1) +# define UNLIKELY(x) __builtin_expect(!!(x),0) +#else +# define INSN_REGPARM /*nothing*/ +# define LIKELY(x) (x) +# define UNLIKELY(x) (x) +#endif + +#define UPDATE_REG(address, value)\ + {\ + WRITE16LE(((u16 *)&ioMem[address]),value);\ + }\ + +#define ARM_PREFETCH \ + {\ + cpuPrefetch[0] = CPUReadMemoryQuick(armNextPC);\ + cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);\ + } + +#define THUMB_PREFETCH \ + {\ + cpuPrefetch[0] = CPUReadHalfWordQuick(armNextPC);\ + cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);\ + } + +#define ARM_PREFETCH_NEXT \ + cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4); + +#define THUMB_PREFETCH_NEXT\ + cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2); + + +extern int SWITicks; +extern u32 mastercode; +extern bool busPrefetch; +extern bool busPrefetchEnable; +extern u32 busPrefetchCount; +extern int cpuNextEvent; +extern bool holdState; +extern u32 cpuPrefetch[2]; +extern int cpuTotalTicks; +extern u8 memoryWait[16]; +extern u8 memoryWait32[16]; +extern u8 memoryWaitSeq[16]; +extern u8 memoryWaitSeq32[16]; +extern u8 cpuBitsSet[256]; +extern u8 cpuLowestBitSet[256]; +extern void CPUSwitchMode(int mode, bool saveState, bool breakLoop); +extern void CPUSwitchMode(int mode, bool saveState); +extern void CPUUpdateCPSR(); +extern void CPUUpdateFlags(bool breakLoop); +extern void CPUUpdateFlags(); +extern void CPUUndefinedException(); +extern void CPUSoftwareInterrupt(); +extern void CPUSoftwareInterrupt(int comment); + + +// Waitstates when accessing data +inline int dataTicksAccess16(u32 address) // DATA 8/16bits NON SEQ +{ + int addr = (address>>24)&15; + int value = memoryWait[addr]; + + if ((addr>=0x08) || (addr < 0x02)) + { + busPrefetchCount=0; + busPrefetch=false; + } + else if (busPrefetch) + { + int waitState = value; + if (!waitState) + waitState = 1; + busPrefetchCount = ((busPrefetchCount+1)<>24)&15; + int value = memoryWait32[addr]; + + if ((addr>=0x08) || (addr < 0x02)) + { + busPrefetchCount=0; + busPrefetch=false; + } + else if (busPrefetch) + { + int waitState = value; + if (!waitState) + waitState = 1; + busPrefetchCount = ((busPrefetchCount+1)<>24)&15; + int value = memoryWaitSeq[addr]; + + if ((addr>=0x08) || (addr < 0x02)) + { + busPrefetchCount=0; + busPrefetch=false; + } + else if (busPrefetch) + { + int waitState = value; + if (!waitState) + waitState = 1; + busPrefetchCount = ((busPrefetchCount+1)<>24)&15; + int value = memoryWaitSeq32[addr]; + + if ((addr>=0x08) || (addr < 0x02)) + { + busPrefetchCount=0; + busPrefetch=false; + } + else if (busPrefetch) + { + int waitState = value; + if (!waitState) + waitState = 1; + busPrefetchCount = ((busPrefetchCount+1)<>24)&15; + + if ((addr>=0x08) && (addr<=0x0D)) + { + if (busPrefetchCount&0x1) + { + if (busPrefetchCount&0x2) + { + busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00); + return 0; + } + busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00); + return memoryWaitSeq[addr]-1; + } + else + { + busPrefetchCount=0; + return memoryWait[addr]; + } + } + else + { + busPrefetchCount = 0; + return memoryWait[addr]; + } +} + +inline int codeTicksAccess32(u32 address) // ARM NON SEQ +{ + int addr = (address>>24)&15; + + if ((addr>=0x08) && (addr<=0x0D)) + { + if (busPrefetchCount&0x1) + { + if (busPrefetchCount&0x2) + { + busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00); + return 0; + } + busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00); + return memoryWaitSeq[addr] - 1; + } + else + { + busPrefetchCount = 0; + return memoryWait32[addr]; + } + } + else + { + busPrefetchCount = 0; + return memoryWait32[addr]; + } +} + +inline int codeTicksAccessSeq16(u32 address) // THUMB SEQ +{ + int addr = (address>>24)&15; + + if ((addr>=0x08) && (addr<=0x0D)) + { + if (busPrefetchCount&0x1) + { + busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00); + return 0; + } + else + if (busPrefetchCount>0xFF) + { + busPrefetchCount=0; + return memoryWait[addr]; + } + else + return memoryWaitSeq[addr]; + } + else + { + busPrefetchCount = 0; + return memoryWaitSeq[addr]; + } +} + +inline int codeTicksAccessSeq32(u32 address) // ARM SEQ +{ + int addr = (address>>24)&15; + + if ((addr>=0x08) && (addr<=0x0D)) + { + if (busPrefetchCount&0x1) + { + if (busPrefetchCount&0x2) + { + busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00); + return 0; + } + busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00); + return memoryWaitSeq[addr]; + } + else + if (busPrefetchCount>0xFF) + { + busPrefetchCount=0; + return memoryWait32[addr]; + } + else + return memoryWaitSeq32[addr]; + } + else + { + return memoryWaitSeq32[addr]; + } +} + + +// Emulates the Cheat System (m) code +inline void cpuMasterCodeCheck() +{ + if((mastercode) && (mastercode == armNextPC)) + { + u32 joy = 0; + if(systemReadJoypads()) + joy = systemReadJoypad(-1); + u32 ext = (joy >> 10); + cpuTotalTicks += cheatsCheckKeys(P1^0x3FF, ext); + } +} + +#endif //VBA_GBAcpu_H diff --git a/src/agb/GBAinline.h b/src/agb/GBAinline.h index 1b48a63f..ebd9770e 100644 --- a/src/agb/GBAinline.h +++ b/src/agb/GBAinline.h @@ -1,739 +1,739 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef VBA_GBAinline_H -#define VBA_GBAinline_H - -#include "../System.h" -#include "../Port.h" -#include "../RTC.h" -#include "../Sound.h" -#include "agbprint.h" - -extern const u32 objTilesAddress[3]; - -extern bool stopState; -extern bool holdState; -extern int holdType; -extern int cpuNextEvent; -extern bool cpuSramEnabled; -extern bool cpuFlashEnabled; -extern bool cpuEEPROMEnabled; -extern bool cpuEEPROMSensorEnabled; -extern bool cpuDmaHack; -extern u32 cpuDmaLast; -extern bool timer0On; -extern int timer0Ticks; -extern int timer0ClockReload; -extern bool timer1On; -extern int timer1Ticks; -extern int timer1ClockReload; -extern bool timer2On; -extern int timer2Ticks; -extern int timer2ClockReload; -extern bool timer3On; -extern int timer3Ticks; -extern int timer3ClockReload; -extern int cpuTotalTicks; - -#define CPUReadByteQuick(addr) \ - map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] - -#define CPUReadHalfWordQuick(addr) \ - READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) - -#define CPUReadMemoryQuick(addr) \ - READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) - -static inline u32 CPUReadMemory(u32 address) -{ - -#ifdef GBA_LOGGING - if(address & 3) { - if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) { - log("Unaligned word read: %08x at %08x\n", address, armMode ? - armNextPC - 4 : armNextPC - 2); - } - } -#endif - - u32 value; - switch(address >> 24) { - case 0: - if(reg[15].I >> 24) { - if(address < 0x4000) { -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_ILLEGAL_READ) { - log("Illegal word read: %08x at %08x\n", address, armMode ? - armNextPC - 4 : armNextPC - 2); - } -#endif - - value = READ32LE(((u32 *)&biosProtected)); - } - else goto unreadable; - } else - value = READ32LE(((u32 *)&bios[address & 0x3FFC])); - break; - case 2: - value = READ32LE(((u32 *)&workRAM[address & 0x3FFFC])); - break; - case 3: - value = READ32LE(((u32 *)&internalRAM[address & 0x7ffC])); - break; - case 4: - if((address < 0x4000400) && ioReadable[address & 0x3fc]) { - if(ioReadable[(address & 0x3fc) + 2]) - value = READ32LE(((u32 *)&ioMem[address & 0x3fC])); - else - value = READ16LE(((u16 *)&ioMem[address & 0x3fc])); - } else goto unreadable; - break; - case 5: - value = READ32LE(((u32 *)&paletteRAM[address & 0x3fC])); - break; - case 6: - address = (address & 0x1fffc); - if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) - { - value = 0; - break; - } - if ((address & 0x18000) == 0x18000) - address &= 0x17fff; - value = READ32LE(((u32 *)&vram[address])); - break; - case 7: - value = READ32LE(((u32 *)&oam[address & 0x3FC])); - break; - case 8: - case 9: - case 10: - case 11: - case 12: - value = READ32LE(((u32 *)&rom[address&0x1FFFFFC])); - break; - case 13: - if(cpuEEPROMEnabled) - // no need to swap this - return eepromRead(address); - goto unreadable; - case 14: - if(cpuFlashEnabled | cpuSramEnabled) - // no need to swap this - return flashRead(address); - // default - default: - unreadable: -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_ILLEGAL_READ) { - log("Illegal word read: %08x at %08x\n", address, armMode ? - armNextPC - 4 : armNextPC - 2); - } -#endif - - if(cpuDmaHack) { - value = cpuDmaLast; - } else { - if(armState) { - value = CPUReadMemoryQuick(reg[15].I); - } else { - value = CPUReadHalfWordQuick(reg[15].I) | - CPUReadHalfWordQuick(reg[15].I) << 16; - } - } - } - - if(address & 3) { -#ifdef C_CORE - int shift = (address & 3) << 3; - value = (value >> shift) | (value << (32 - shift)); -#else -#ifdef __GNUC__ - asm("and $3, %%ecx;" - "shl $3 ,%%ecx;" - "ror %%cl, %0" - : "=r" (value) - : "r" (value), "c" (address)); -#else - __asm { - mov ecx, address; - and ecx, 3; - shl ecx, 3; - ror [dword ptr value], cl; - } -#endif -#endif - } - return value; -} - -extern u32 myROM[]; - -static inline u32 CPUReadHalfWord(u32 address) -{ -#ifdef GBA_LOGGING - if(address & 1) { - if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) { - log("Unaligned halfword read: %08x at %08x\n", address, armMode ? - armNextPC - 4 : armNextPC - 2); - } - } -#endif - - u32 value; - - switch(address >> 24) { - case 0: - if (reg[15].I >> 24) { - if(address < 0x4000) { -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_ILLEGAL_READ) { - log("Illegal halfword read: %08x at %08x\n", address, armMode ? - armNextPC - 4 : armNextPC - 2); - } -#endif - value = READ16LE(((u16 *)&biosProtected[address&2])); - } else goto unreadable; - } else - value = READ16LE(((u16 *)&bios[address & 0x3FFE])); - break; - case 2: - value = READ16LE(((u16 *)&workRAM[address & 0x3FFFE])); - break; - case 3: - value = READ16LE(((u16 *)&internalRAM[address & 0x7ffe])); - break; - case 4: - if((address < 0x4000400) && ioReadable[address & 0x3fe]) - { - value = READ16LE(((u16 *)&ioMem[address & 0x3fe])); - if (((address & 0x3fe)>0xFF) && ((address & 0x3fe)<0x10E)) - { - if (((address & 0x3fe) == 0x100) && timer0On) - value = 0xFFFF - ((timer0Ticks-cpuTotalTicks) >> timer0ClockReload); - else - if (((address & 0x3fe) == 0x104) && timer1On && !(TM1CNT & 4)) - value = 0xFFFF - ((timer1Ticks-cpuTotalTicks) >> timer1ClockReload); - else - if (((address & 0x3fe) == 0x108) && timer2On && !(TM2CNT & 4)) - value = 0xFFFF - ((timer2Ticks-cpuTotalTicks) >> timer2ClockReload); - else - if (((address & 0x3fe) == 0x10C) && timer3On && !(TM3CNT & 4)) - value = 0xFFFF - ((timer3Ticks-cpuTotalTicks) >> timer3ClockReload); - } - } - else goto unreadable; - break; - case 5: - value = READ16LE(((u16 *)&paletteRAM[address & 0x3fe])); - break; - case 6: - address = (address & 0x1fffe); - if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) - { - value = 0; - break; - } - if ((address & 0x18000) == 0x18000) - address &= 0x17fff; - value = READ16LE(((u16 *)&vram[address])); - break; - case 7: - value = READ16LE(((u16 *)&oam[address & 0x3fe])); - break; - case 8: - case 9: - case 10: - case 11: - case 12: - if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) - value = rtcRead(address); - else - value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE])); - break; - case 13: - if(cpuEEPROMEnabled) - // no need to swap this - return eepromRead(address); - goto unreadable; - case 14: - if(cpuFlashEnabled | cpuSramEnabled) - // no need to swap this - return flashRead(address); - // default - default: - unreadable: -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_ILLEGAL_READ) { - log("Illegal halfword read: %08x at %08x\n", address, armMode ? - armNextPC - 4 : armNextPC - 2); - } -#endif - if(cpuDmaHack) { - value = cpuDmaLast & 0xFFFF; - } else { - if(armState) { - value = CPUReadHalfWordQuick(reg[15].I + (address & 2)); - } else { - value = CPUReadHalfWordQuick(reg[15].I); - } - } - break; - } - - if(address & 1) { - value = (value >> 8) | (value << 24); - } - - return value; -} - -static inline u16 CPUReadHalfWordSigned(u32 address) -{ - u16 value = CPUReadHalfWord(address); - if((address & 1)) - value = (s8)value; - return value; -} - -static inline u8 CPUReadByte(u32 address) -{ - switch(address >> 24) { - case 0: - if (reg[15].I >> 24) { - if(address < 0x4000) { -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_ILLEGAL_READ) { - log("Illegal byte read: %08x at %08x\n", address, armMode ? - armNextPC - 4 : armNextPC - 2); - } -#endif - return biosProtected[address & 3]; - } else goto unreadable; - } - return bios[address & 0x3FFF]; - case 2: - return workRAM[address & 0x3FFFF]; - case 3: - return internalRAM[address & 0x7fff]; - case 4: - if((address < 0x4000400) && ioReadable[address & 0x3ff]) - return ioMem[address & 0x3ff]; - else goto unreadable; - case 5: - return paletteRAM[address & 0x3ff]; - case 6: - address = (address & 0x1ffff); - if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) - return 0; - if ((address & 0x18000) == 0x18000) - address &= 0x17fff; - return vram[address]; - case 7: - return oam[address & 0x3ff]; - case 8: - case 9: - case 10: - case 11: - case 12: - return rom[address & 0x1FFFFFF]; - case 13: - if(cpuEEPROMEnabled) - return eepromRead(address); - goto unreadable; - case 14: - if(cpuSramEnabled | cpuFlashEnabled) - return flashRead(address); - if(cpuEEPROMSensorEnabled) { - switch(address & 0x00008f00) { - case 0x8200: - return systemGetSensorX() & 255; - case 0x8300: - return (systemGetSensorX() >> 8)|0x80; - case 0x8400: - return systemGetSensorY() & 255; - case 0x8500: - return systemGetSensorY() >> 8; - } - } - // default - default: - unreadable: -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_ILLEGAL_READ) { - log("Illegal byte read: %08x at %08x\n", address, armMode ? - armNextPC - 4 : armNextPC - 2); - } -#endif - if(cpuDmaHack) { - return cpuDmaLast & 0xFF; - } else { - if(armState) { - return CPUReadByteQuick(reg[15].I+(address & 3)); - } else { - return CPUReadByteQuick(reg[15].I+(address & 1)); - } - } - break; - } -} - -static inline void CPUWriteMemory(u32 address, u32 value) -{ - -#ifdef GBA_LOGGING - if(address & 3) { - if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) { - log("Unaligned word write: %08x to %08x from %08x\n", - value, - address, - armMode ? armNextPC - 4 : armNextPC - 2); - } - } -#endif - - switch(address >> 24) { - case 0x02: -#ifdef BKPT_SUPPORT - if(*((u32 *)&freezeWorkRAM[address & 0x3FFFC])) - cheatsWriteMemory(address & 0x203FFFC, - value); - else -#endif - WRITE32LE(((u32 *)&workRAM[address & 0x3FFFC]), value); - break; - case 0x03: -#ifdef BKPT_SUPPORT - if(*((u32 *)&freezeInternalRAM[address & 0x7ffc])) - cheatsWriteMemory(address & 0x3007FFC, - value); - else -#endif - WRITE32LE(((u32 *)&internalRAM[address & 0x7ffC]), value); - break; - case 0x04: - if(address < 0x4000400) { - CPUUpdateRegister((address & 0x3FC), value & 0xFFFF); - CPUUpdateRegister((address & 0x3FC) + 2, (value >> 16)); - } else goto unwritable; - break; - case 0x05: -#ifdef BKPT_SUPPORT - if(*((u32 *)&freezePRAM[address & 0x3fc])) - cheatsWriteMemory(address & 0x70003FC, - value); - else -#endif - WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value); - break; - case 0x06: - address = (address & 0x1fffc); - if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) - return; - if ((address & 0x18000) == 0x18000) - address &= 0x17fff; - -#ifdef BKPT_SUPPORT - if(*((u32 *)&freezeVRAM[address])) - cheatsWriteMemory(address + 0x06000000, value); - else -#endif - - WRITE32LE(((u32 *)&vram[address]), value); - break; - case 0x07: -#ifdef BKPT_SUPPORT - if(*((u32 *)&freezeOAM[address & 0x3fc])) - cheatsWriteMemory(address & 0x70003FC, - value); - else -#endif - WRITE32LE(((u32 *)&oam[address & 0x3fc]), value); - break; - case 0x0D: - if(cpuEEPROMEnabled) { - eepromWrite(address, value); - break; - } - goto unwritable; - case 0x0E: - if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) { - (*cpuSaveGameFunc)(address, (u8)value); - break; - } - // default - default: - unwritable: -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_ILLEGAL_WRITE) { - log("Illegal word write: %08x to %08x from %08x\n", - value, - address, - armMode ? armNextPC - 4 : armNextPC - 2); - } -#endif - break; - } -} - -static inline void CPUWriteHalfWord(u32 address, u16 value) -{ -#ifdef GBA_LOGGING - if(address & 1) { - if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) { - log("Unaligned halfword write: %04x to %08x from %08x\n", - value, - address, - armMode ? armNextPC - 4 : armNextPC - 2); - } - } -#endif - - switch(address >> 24) { - case 2: -#ifdef BKPT_SUPPORT - if(*((u16 *)&freezeWorkRAM[address & 0x3FFFE])) - cheatsWriteHalfWord(address & 0x203FFFE, - value); - else -#endif - WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]),value); - break; - case 3: -#ifdef BKPT_SUPPORT - if(*((u16 *)&freezeInternalRAM[address & 0x7ffe])) - cheatsWriteHalfWord(address & 0x3007ffe, - value); - else -#endif - WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value); - break; - case 4: - if(address < 0x4000400) - CPUUpdateRegister(address & 0x3fe, value); - else goto unwritable; - break; - case 5: -#ifdef BKPT_SUPPORT - if(*((u16 *)&freezePRAM[address & 0x03fe])) - cheatsWriteHalfWord(address & 0x70003fe, - value); - else -#endif - WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value); - break; - case 6: - address = (address & 0x1fffe); - if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) - return; - if ((address & 0x18000) == 0x18000) - address &= 0x17fff; -#ifdef BKPT_SUPPORT - if(*((u16 *)&freezeVRAM[address])) - cheatsWriteHalfWord(address + 0x06000000, - value); - else -#endif - WRITE16LE(((u16 *)&vram[address]), value); - break; - case 7: -#ifdef BKPT_SUPPORT - if(*((u16 *)&freezeOAM[address & 0x03fe])) - cheatsWriteHalfWord(address & 0x70003fe, - value); - else -#endif - WRITE16LE(((u16 *)&oam[address & 0x3fe]), value); - break; - case 8: - case 9: - if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) { - if(!rtcWrite(address, value)) - goto unwritable; - } else if(!agbPrintWrite(address, value)) goto unwritable; - break; - case 13: - if(cpuEEPROMEnabled) { - eepromWrite(address, (u8)value); - break; - } - goto unwritable; - case 14: - if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) { - (*cpuSaveGameFunc)(address, (u8)value); - break; - } - goto unwritable; - default: - unwritable: -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_ILLEGAL_WRITE) { - log("Illegal halfword write: %04x to %08x from %08x\n", - value, - address, - armMode ? armNextPC - 4 : armNextPC - 2); - } -#endif - break; - } -} - -static inline void CPUWriteByte(u32 address, u8 b) -{ - switch(address >> 24) { - case 2: -#ifdef BKPT_SUPPORT - if(freezeWorkRAM[address & 0x3FFFF]) - cheatsWriteByte(address & 0x203FFFF, b); - else -#endif - workRAM[address & 0x3FFFF] = b; - break; - case 3: -#ifdef BKPT_SUPPORT - if(freezeInternalRAM[address & 0x7fff]) - cheatsWriteByte(address & 0x3007fff, b); - else -#endif - internalRAM[address & 0x7fff] = b; - break; - case 4: - if(address < 0x4000400) { - switch(address & 0x3FF) { - case 0x301: - if(b == 0x80) - stopState = true; - holdState = 1; - holdType = -1; - cpuNextEvent = cpuTotalTicks; - break; - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x68: - case 0x69: - case 0x6c: - case 0x6d: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x78: - case 0x79: - case 0x7c: - case 0x7d: - case 0x80: - case 0x81: - case 0x84: - case 0x85: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9a: - case 0x9b: - case 0x9c: - case 0x9d: - case 0x9e: - case 0x9f: - soundEvent(address&0xFF, b); - break; - default: - if(address & 1) - CPUUpdateRegister(address & 0x3fe, - ((READ16LE(((u16 *)&ioMem[address & 0x3fe]))) - & 0x00FF) | - b<<8); - else - CPUUpdateRegister(address & 0x3fe, - ((READ16LE(((u16 *)&ioMem[address & 0x3fe])) & 0xFF00) | b)); - } - break; - } else goto unwritable; - break; - case 5: - // no need to switch - *((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b; - break; - case 6: - address = (address & 0x1fffe); - if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) - return; - if ((address & 0x18000) == 0x18000) - address &= 0x17fff; - - // no need to switch - // byte writes to OBJ VRAM are ignored - if ((address) < objTilesAddress[((DISPCNT&7)+1)>>2]) - { -#ifdef BKPT_SUPPORT - if(freezeVRAM[address]) - cheatsWriteByte(address + 0x06000000, b); - else -#endif - *((u16 *)&vram[address]) = (b << 8) | b; - } - break; - case 7: - // no need to switch - // byte writes to OAM are ignored - // *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b; - break; - case 13: - if(cpuEEPROMEnabled) { - eepromWrite(address, b); - break; - } - goto unwritable; - case 14: - if (!(saveType == 5) && (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)) { - - //if(!cpuEEPROMEnabled && (cpuSramEnabled | cpuFlashEnabled)) { - - (*cpuSaveGameFunc)(address, b); - break; - } - // default - default: - unwritable: -#ifdef GBA_LOGGING - if(systemVerbose & VERBOSE_ILLEGAL_WRITE) { - log("Illegal byte write: %02x to %08x from %08x\n", - b, - address, - armMode ? armNextPC - 4 : armNextPC -2 ); - } -#endif - break; - } -} - -#endif //VBA_GBAinline_H +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef VBA_GBAinline_H +#define VBA_GBAinline_H + +#include "../System.h" +#include "../Port.h" +#include "../RTC.h" +#include "../Sound.h" +#include "agbprint.h" + +extern const u32 objTilesAddress[3]; + +extern bool stopState; +extern bool holdState; +extern int holdType; +extern int cpuNextEvent; +extern bool cpuSramEnabled; +extern bool cpuFlashEnabled; +extern bool cpuEEPROMEnabled; +extern bool cpuEEPROMSensorEnabled; +extern bool cpuDmaHack; +extern u32 cpuDmaLast; +extern bool timer0On; +extern int timer0Ticks; +extern int timer0ClockReload; +extern bool timer1On; +extern int timer1Ticks; +extern int timer1ClockReload; +extern bool timer2On; +extern int timer2Ticks; +extern int timer2ClockReload; +extern bool timer3On; +extern int timer3Ticks; +extern int timer3ClockReload; +extern int cpuTotalTicks; + +#define CPUReadByteQuick(addr) \ + map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] + +#define CPUReadHalfWordQuick(addr) \ + READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) + +#define CPUReadMemoryQuick(addr) \ + READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) + +static inline u32 CPUReadMemory(u32 address) +{ + +#ifdef GBA_LOGGING + if(address & 3) { + if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) { + log("Unaligned word read: %08x at %08x\n", address, armMode ? + armNextPC - 4 : armNextPC - 2); + } + } +#endif + + u32 value; + switch(address >> 24) { + case 0: + if(reg[15].I >> 24) { + if(address < 0x4000) { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_ILLEGAL_READ) { + log("Illegal word read: %08x at %08x\n", address, armMode ? + armNextPC - 4 : armNextPC - 2); + } +#endif + + value = READ32LE(((u32 *)&biosProtected)); + } + else goto unreadable; + } else + value = READ32LE(((u32 *)&bios[address & 0x3FFC])); + break; + case 2: + value = READ32LE(((u32 *)&workRAM[address & 0x3FFFC])); + break; + case 3: + value = READ32LE(((u32 *)&internalRAM[address & 0x7ffC])); + break; + case 4: + if((address < 0x4000400) && ioReadable[address & 0x3fc]) { + if(ioReadable[(address & 0x3fc) + 2]) + value = READ32LE(((u32 *)&ioMem[address & 0x3fC])); + else + value = READ16LE(((u16 *)&ioMem[address & 0x3fc])); + } else goto unreadable; + break; + case 5: + value = READ32LE(((u32 *)&paletteRAM[address & 0x3fC])); + break; + case 6: + address = (address & 0x1fffc); + if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) + { + value = 0; + break; + } + if ((address & 0x18000) == 0x18000) + address &= 0x17fff; + value = READ32LE(((u32 *)&vram[address])); + break; + case 7: + value = READ32LE(((u32 *)&oam[address & 0x3FC])); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + value = READ32LE(((u32 *)&rom[address&0x1FFFFFC])); + break; + case 13: + if(cpuEEPROMEnabled) + // no need to swap this + return eepromRead(address); + goto unreadable; + case 14: + if(cpuFlashEnabled | cpuSramEnabled) + // no need to swap this + return flashRead(address); + // default + default: + unreadable: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_ILLEGAL_READ) { + log("Illegal word read: %08x at %08x\n", address, armMode ? + armNextPC - 4 : armNextPC - 2); + } +#endif + + if(cpuDmaHack) { + value = cpuDmaLast; + } else { + if(armState) { + value = CPUReadMemoryQuick(reg[15].I); + } else { + value = CPUReadHalfWordQuick(reg[15].I) | + CPUReadHalfWordQuick(reg[15].I) << 16; + } + } + } + + if(address & 3) { +#ifdef C_CORE + int shift = (address & 3) << 3; + value = (value >> shift) | (value << (32 - shift)); +#else +#ifdef __GNUC__ + asm("and $3, %%ecx;" + "shl $3 ,%%ecx;" + "ror %%cl, %0" + : "=r" (value) + : "r" (value), "c" (address)); +#else + __asm { + mov ecx, address; + and ecx, 3; + shl ecx, 3; + ror [dword ptr value], cl; + } +#endif +#endif + } + return value; +} + +extern u32 myROM[]; + +static inline u32 CPUReadHalfWord(u32 address) +{ +#ifdef GBA_LOGGING + if(address & 1) { + if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) { + log("Unaligned halfword read: %08x at %08x\n", address, armMode ? + armNextPC - 4 : armNextPC - 2); + } + } +#endif + + u32 value; + + switch(address >> 24) { + case 0: + if (reg[15].I >> 24) { + if(address < 0x4000) { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_ILLEGAL_READ) { + log("Illegal halfword read: %08x at %08x\n", address, armMode ? + armNextPC - 4 : armNextPC - 2); + } +#endif + value = READ16LE(((u16 *)&biosProtected[address&2])); + } else goto unreadable; + } else + value = READ16LE(((u16 *)&bios[address & 0x3FFE])); + break; + case 2: + value = READ16LE(((u16 *)&workRAM[address & 0x3FFFE])); + break; + case 3: + value = READ16LE(((u16 *)&internalRAM[address & 0x7ffe])); + break; + case 4: + if((address < 0x4000400) && ioReadable[address & 0x3fe]) + { + value = READ16LE(((u16 *)&ioMem[address & 0x3fe])); + if (((address & 0x3fe)>0xFF) && ((address & 0x3fe)<0x10E)) + { + if (((address & 0x3fe) == 0x100) && timer0On) + value = 0xFFFF - ((timer0Ticks-cpuTotalTicks) >> timer0ClockReload); + else + if (((address & 0x3fe) == 0x104) && timer1On && !(TM1CNT & 4)) + value = 0xFFFF - ((timer1Ticks-cpuTotalTicks) >> timer1ClockReload); + else + if (((address & 0x3fe) == 0x108) && timer2On && !(TM2CNT & 4)) + value = 0xFFFF - ((timer2Ticks-cpuTotalTicks) >> timer2ClockReload); + else + if (((address & 0x3fe) == 0x10C) && timer3On && !(TM3CNT & 4)) + value = 0xFFFF - ((timer3Ticks-cpuTotalTicks) >> timer3ClockReload); + } + } + else goto unreadable; + break; + case 5: + value = READ16LE(((u16 *)&paletteRAM[address & 0x3fe])); + break; + case 6: + address = (address & 0x1fffe); + if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) + { + value = 0; + break; + } + if ((address & 0x18000) == 0x18000) + address &= 0x17fff; + value = READ16LE(((u16 *)&vram[address])); + break; + case 7: + value = READ16LE(((u16 *)&oam[address & 0x3fe])); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) + value = rtcRead(address); + else + value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE])); + break; + case 13: + if(cpuEEPROMEnabled) + // no need to swap this + return eepromRead(address); + goto unreadable; + case 14: + if(cpuFlashEnabled | cpuSramEnabled) + // no need to swap this + return flashRead(address); + // default + default: + unreadable: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_ILLEGAL_READ) { + log("Illegal halfword read: %08x at %08x\n", address, armMode ? + armNextPC - 4 : armNextPC - 2); + } +#endif + if(cpuDmaHack) { + value = cpuDmaLast & 0xFFFF; + } else { + if(armState) { + value = CPUReadHalfWordQuick(reg[15].I + (address & 2)); + } else { + value = CPUReadHalfWordQuick(reg[15].I); + } + } + break; + } + + if(address & 1) { + value = (value >> 8) | (value << 24); + } + + return value; +} + +static inline u16 CPUReadHalfWordSigned(u32 address) +{ + u16 value = CPUReadHalfWord(address); + if((address & 1)) + value = (s8)value; + return value; +} + +static inline u8 CPUReadByte(u32 address) +{ + switch(address >> 24) { + case 0: + if (reg[15].I >> 24) { + if(address < 0x4000) { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_ILLEGAL_READ) { + log("Illegal byte read: %08x at %08x\n", address, armMode ? + armNextPC - 4 : armNextPC - 2); + } +#endif + return biosProtected[address & 3]; + } else goto unreadable; + } + return bios[address & 0x3FFF]; + case 2: + return workRAM[address & 0x3FFFF]; + case 3: + return internalRAM[address & 0x7fff]; + case 4: + if((address < 0x4000400) && ioReadable[address & 0x3ff]) + return ioMem[address & 0x3ff]; + else goto unreadable; + case 5: + return paletteRAM[address & 0x3ff]; + case 6: + address = (address & 0x1ffff); + if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) + return 0; + if ((address & 0x18000) == 0x18000) + address &= 0x17fff; + return vram[address]; + case 7: + return oam[address & 0x3ff]; + case 8: + case 9: + case 10: + case 11: + case 12: + return rom[address & 0x1FFFFFF]; + case 13: + if(cpuEEPROMEnabled) + return eepromRead(address); + goto unreadable; + case 14: + if(cpuSramEnabled | cpuFlashEnabled) + return flashRead(address); + if(cpuEEPROMSensorEnabled) { + switch(address & 0x00008f00) { + case 0x8200: + return systemGetSensorX() & 255; + case 0x8300: + return (systemGetSensorX() >> 8)|0x80; + case 0x8400: + return systemGetSensorY() & 255; + case 0x8500: + return systemGetSensorY() >> 8; + } + } + // default + default: + unreadable: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_ILLEGAL_READ) { + log("Illegal byte read: %08x at %08x\n", address, armMode ? + armNextPC - 4 : armNextPC - 2); + } +#endif + if(cpuDmaHack) { + return cpuDmaLast & 0xFF; + } else { + if(armState) { + return CPUReadByteQuick(reg[15].I+(address & 3)); + } else { + return CPUReadByteQuick(reg[15].I+(address & 1)); + } + } + break; + } +} + +static inline void CPUWriteMemory(u32 address, u32 value) +{ + +#ifdef GBA_LOGGING + if(address & 3) { + if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) { + log("Unaligned word write: %08x to %08x from %08x\n", + value, + address, + armMode ? armNextPC - 4 : armNextPC - 2); + } + } +#endif + + switch(address >> 24) { + case 0x02: +#ifdef BKPT_SUPPORT + if(*((u32 *)&freezeWorkRAM[address & 0x3FFFC])) + cheatsWriteMemory(address & 0x203FFFC, + value); + else +#endif + WRITE32LE(((u32 *)&workRAM[address & 0x3FFFC]), value); + break; + case 0x03: +#ifdef BKPT_SUPPORT + if(*((u32 *)&freezeInternalRAM[address & 0x7ffc])) + cheatsWriteMemory(address & 0x3007FFC, + value); + else +#endif + WRITE32LE(((u32 *)&internalRAM[address & 0x7ffC]), value); + break; + case 0x04: + if(address < 0x4000400) { + CPUUpdateRegister((address & 0x3FC), value & 0xFFFF); + CPUUpdateRegister((address & 0x3FC) + 2, (value >> 16)); + } else goto unwritable; + break; + case 0x05: +#ifdef BKPT_SUPPORT + if(*((u32 *)&freezePRAM[address & 0x3fc])) + cheatsWriteMemory(address & 0x70003FC, + value); + else +#endif + WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value); + break; + case 0x06: + address = (address & 0x1fffc); + if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) + return; + if ((address & 0x18000) == 0x18000) + address &= 0x17fff; + +#ifdef BKPT_SUPPORT + if(*((u32 *)&freezeVRAM[address])) + cheatsWriteMemory(address + 0x06000000, value); + else +#endif + + WRITE32LE(((u32 *)&vram[address]), value); + break; + case 0x07: +#ifdef BKPT_SUPPORT + if(*((u32 *)&freezeOAM[address & 0x3fc])) + cheatsWriteMemory(address & 0x70003FC, + value); + else +#endif + WRITE32LE(((u32 *)&oam[address & 0x3fc]), value); + break; + case 0x0D: + if(cpuEEPROMEnabled) { + eepromWrite(address, value); + break; + } + goto unwritable; + case 0x0E: + if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) { + (*cpuSaveGameFunc)(address, (u8)value); + break; + } + // default + default: + unwritable: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_ILLEGAL_WRITE) { + log("Illegal word write: %08x to %08x from %08x\n", + value, + address, + armMode ? armNextPC - 4 : armNextPC - 2); + } +#endif + break; + } +} + +static inline void CPUWriteHalfWord(u32 address, u16 value) +{ +#ifdef GBA_LOGGING + if(address & 1) { + if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) { + log("Unaligned halfword write: %04x to %08x from %08x\n", + value, + address, + armMode ? armNextPC - 4 : armNextPC - 2); + } + } +#endif + + switch(address >> 24) { + case 2: +#ifdef BKPT_SUPPORT + if(*((u16 *)&freezeWorkRAM[address & 0x3FFFE])) + cheatsWriteHalfWord(address & 0x203FFFE, + value); + else +#endif + WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]),value); + break; + case 3: +#ifdef BKPT_SUPPORT + if(*((u16 *)&freezeInternalRAM[address & 0x7ffe])) + cheatsWriteHalfWord(address & 0x3007ffe, + value); + else +#endif + WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value); + break; + case 4: + if(address < 0x4000400) + CPUUpdateRegister(address & 0x3fe, value); + else goto unwritable; + break; + case 5: +#ifdef BKPT_SUPPORT + if(*((u16 *)&freezePRAM[address & 0x03fe])) + cheatsWriteHalfWord(address & 0x70003fe, + value); + else +#endif + WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value); + break; + case 6: + address = (address & 0x1fffe); + if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) + return; + if ((address & 0x18000) == 0x18000) + address &= 0x17fff; +#ifdef BKPT_SUPPORT + if(*((u16 *)&freezeVRAM[address])) + cheatsWriteHalfWord(address + 0x06000000, + value); + else +#endif + WRITE16LE(((u16 *)&vram[address]), value); + break; + case 7: +#ifdef BKPT_SUPPORT + if(*((u16 *)&freezeOAM[address & 0x03fe])) + cheatsWriteHalfWord(address & 0x70003fe, + value); + else +#endif + WRITE16LE(((u16 *)&oam[address & 0x3fe]), value); + break; + case 8: + case 9: + if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) { + if(!rtcWrite(address, value)) + goto unwritable; + } else if(!agbPrintWrite(address, value)) goto unwritable; + break; + case 13: + if(cpuEEPROMEnabled) { + eepromWrite(address, (u8)value); + break; + } + goto unwritable; + case 14: + if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) { + (*cpuSaveGameFunc)(address, (u8)value); + break; + } + goto unwritable; + default: + unwritable: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_ILLEGAL_WRITE) { + log("Illegal halfword write: %04x to %08x from %08x\n", + value, + address, + armMode ? armNextPC - 4 : armNextPC - 2); + } +#endif + break; + } +} + +static inline void CPUWriteByte(u32 address, u8 b) +{ + switch(address >> 24) { + case 2: +#ifdef BKPT_SUPPORT + if(freezeWorkRAM[address & 0x3FFFF]) + cheatsWriteByte(address & 0x203FFFF, b); + else +#endif + workRAM[address & 0x3FFFF] = b; + break; + case 3: +#ifdef BKPT_SUPPORT + if(freezeInternalRAM[address & 0x7fff]) + cheatsWriteByte(address & 0x3007fff, b); + else +#endif + internalRAM[address & 0x7fff] = b; + break; + case 4: + if(address < 0x4000400) { + switch(address & 0x3FF) { + case 0x301: + if(b == 0x80) + stopState = true; + holdState = 1; + holdType = -1; + cpuNextEvent = cpuTotalTicks; + break; + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x68: + case 0x69: + case 0x6c: + case 0x6d: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x78: + case 0x79: + case 0x7c: + case 0x7d: + case 0x80: + case 0x81: + case 0x84: + case 0x85: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9a: + case 0x9b: + case 0x9c: + case 0x9d: + case 0x9e: + case 0x9f: + soundEvent(address&0xFF, b); + break; + default: + if(address & 1) + CPUUpdateRegister(address & 0x3fe, + ((READ16LE(((u16 *)&ioMem[address & 0x3fe]))) + & 0x00FF) | + b<<8); + else + CPUUpdateRegister(address & 0x3fe, + ((READ16LE(((u16 *)&ioMem[address & 0x3fe])) & 0xFF00) | b)); + } + break; + } else goto unwritable; + break; + case 5: + // no need to switch + *((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b; + break; + case 6: + address = (address & 0x1fffe); + if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) + return; + if ((address & 0x18000) == 0x18000) + address &= 0x17fff; + + // no need to switch + // byte writes to OBJ VRAM are ignored + if ((address) < objTilesAddress[((DISPCNT&7)+1)>>2]) + { +#ifdef BKPT_SUPPORT + if(freezeVRAM[address]) + cheatsWriteByte(address + 0x06000000, b); + else +#endif + *((u16 *)&vram[address]) = (b << 8) | b; + } + break; + case 7: + // no need to switch + // byte writes to OAM are ignored + // *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b; + break; + case 13: + if(cpuEEPROMEnabled) { + eepromWrite(address, b); + break; + } + goto unwritable; + case 14: + if (!(saveType == 5) && (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)) { + + //if(!cpuEEPROMEnabled && (cpuSramEnabled | cpuFlashEnabled)) { + + (*cpuSaveGameFunc)(address, b); + break; + } + // default + default: + unwritable: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_ILLEGAL_WRITE) { + log("Illegal byte write: %02x to %08x from %08x\n", + b, + address, + armMode ? armNextPC - 4 : armNextPC -2 ); + } +#endif + break; + } +} + +#endif //VBA_GBAinline_H diff --git a/src/agb/agbprint.cpp b/src/agb/agbprint.cpp index a1371a98..db61d1f2 100644 --- a/src/agb/agbprint.cpp +++ b/src/agb/agbprint.cpp @@ -1,98 +1,98 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include -#include - -#include "GBA.h" -#include "../Globals.h" -#include "../Port.h" -#include "../System.h" - -#define debuggerWriteHalfWord(addr, value) \ - WRITE16LE((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask], (value)) - -#define debuggerReadHalfWord(addr) \ - READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) - -static bool agbPrintEnabled = false; -static bool agbPrintProtect = false; - -bool agbPrintWrite(u32 address, u16 value) -{ - if(agbPrintEnabled) { - if(address == 0x9fe2ffe) { // protect - agbPrintProtect = (value != 0); - debuggerWriteHalfWord(address, value); - return true; - } else { - if(agbPrintProtect && - ((address >= 0x9fe20f8 && address <= 0x9fe20ff) // control structure - || (address >= 0x8fd0000 && address <= 0x8fdffff) - || (address >= 0x9fd0000 && address <= 0x9fdffff))) { - debuggerWriteHalfWord(address, value); - return true; - } - } - } - return false; -} - -void agbPrintReset() -{ - agbPrintProtect = false; -} - -void agbPrintEnable(bool enable) -{ - agbPrintEnabled = enable; -} - -bool agbPrintIsEnabled() -{ - return agbPrintEnabled; -} - -void agbPrintFlush() -{ - u16 get = debuggerReadHalfWord(0x9fe20fc); - u16 put = debuggerReadHalfWord(0x9fe20fe); - - u32 address = (debuggerReadHalfWord(0x9fe20fa) << 16); - if(address != 0xfd0000 && address != 0x1fd0000) { - dbgOutput("Did you forget to call AGBPrintInit?\n", 0); - // get rid of the text otherwise we will continue to be called - debuggerWriteHalfWord(0x9fe20fc, put); - return; - } - - u8 *data = &rom[address]; - - while(get != put) { - char c = data[get++]; - char s[2]; - s[0] = c; - s[1] = 0; - - if(systemVerbose & VERBOSE_AGBPRINT) - dbgOutput(s, 0); - if(c == '\n') - break; - } - debuggerWriteHalfWord(0x9fe20fc, get); -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include + +#include "GBA.h" +#include "../Globals.h" +#include "../Port.h" +#include "../System.h" + +#define debuggerWriteHalfWord(addr, value) \ + WRITE16LE((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask], (value)) + +#define debuggerReadHalfWord(addr) \ + READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) + +static bool agbPrintEnabled = false; +static bool agbPrintProtect = false; + +bool agbPrintWrite(u32 address, u16 value) +{ + if(agbPrintEnabled) { + if(address == 0x9fe2ffe) { // protect + agbPrintProtect = (value != 0); + debuggerWriteHalfWord(address, value); + return true; + } else { + if(agbPrintProtect && + ((address >= 0x9fe20f8 && address <= 0x9fe20ff) // control structure + || (address >= 0x8fd0000 && address <= 0x8fdffff) + || (address >= 0x9fd0000 && address <= 0x9fdffff))) { + debuggerWriteHalfWord(address, value); + return true; + } + } + } + return false; +} + +void agbPrintReset() +{ + agbPrintProtect = false; +} + +void agbPrintEnable(bool enable) +{ + agbPrintEnabled = enable; +} + +bool agbPrintIsEnabled() +{ + return agbPrintEnabled; +} + +void agbPrintFlush() +{ + u16 get = debuggerReadHalfWord(0x9fe20fc); + u16 put = debuggerReadHalfWord(0x9fe20fe); + + u32 address = (debuggerReadHalfWord(0x9fe20fa) << 16); + if(address != 0xfd0000 && address != 0x1fd0000) { + dbgOutput("Did you forget to call AGBPrintInit?\n", 0); + // get rid of the text otherwise we will continue to be called + debuggerWriteHalfWord(0x9fe20fc, put); + return; + } + + u8 *data = &rom[address]; + + while(get != put) { + char c = data[get++]; + char s[2]; + s[0] = c; + s[1] = 0; + + if(systemVerbose & VERBOSE_AGBPRINT) + dbgOutput(s, 0); + if(c == '\n') + break; + } + debuggerWriteHalfWord(0x9fe20fc, get); +} diff --git a/src/agb/agbprint.h b/src/agb/agbprint.h index 7f63fa6b..d7742dee 100644 --- a/src/agb/agbprint.h +++ b/src/agb/agbprint.h @@ -1,27 +1,27 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef VBA_AGBPRINT_H -#define VBA_AGBPRINT_H -extern void agbPrintEnable(bool); -extern bool agbPrintIsEnabled(); -extern void agbPrintReset(); -extern bool agbPrintWrite(u32, u16); -extern void agbPrintFlush(); -#endif +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef VBA_AGBPRINT_H +#define VBA_AGBPRINT_H +extern void agbPrintEnable(bool); +extern bool agbPrintIsEnabled(); +extern void agbPrintReset(); +extern bool agbPrintWrite(u32, u16); +extern void agbPrintFlush(); +#endif diff --git a/src/agb/gbafilter.cpp b/src/agb/gbafilter.cpp index 7aef6f51..1b5aee99 100644 --- a/src/agb/gbafilter.cpp +++ b/src/agb/gbafilter.cpp @@ -1,227 +1,227 @@ -#include "gbafilter.h" - -#include - -extern int systemColorDepth; -extern int systemRedShift; -extern int systemGreenShift; -extern int systemBlueShift; - -extern u16 systemColorMap16[0x10000]; -extern u32 systemColorMap32[0x10000]; - -static const unsigned char curve[32] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x10, 0x12, - 0x14, 0x16, 0x18, 0x1c, 0x20, 0x28, 0x30, 0x38, - 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x80, - 0x88, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0}; - -// output R G B -static const unsigned char influence[3 * 3] = { 16, 4, 4, // red - 8, 16, 8, // green - 0, 8, 16};// blue - -inline void swap(short & a, short & b) -{ - short temp = a; - a = b; - b = temp; -} - -void gbafilter_pal(u16 * buf, int count) -{ - short temp[3 * 3], s; - unsigned pix; - u8 red, green, blue; - - while (count--) - { - pix = *buf; - - s = curve[(pix >> systemGreenShift) & 0x1f]; - temp[3] = s * influence[3]; - temp[4] = s * influence[4]; - temp[5] = s * influence[5]; - - s = curve[(pix >> systemRedShift) & 0x1f]; - temp[0] = s * influence[0]; - temp[1] = s * influence[1]; - temp[2] = s * influence[2]; - - s = curve[(pix >> systemBlueShift) & 0x1f]; - temp[6] = s * influence[6]; - temp[7] = s * influence[7]; - temp[8] = s * influence[8]; - - if (temp[0] < temp[3]) swap(temp[0], temp[3]); - if (temp[0] < temp[6]) swap(temp[0], temp[6]); - if (temp[3] < temp[6]) swap(temp[3], temp[6]); - temp[3] <<= 1; - temp[0] <<= 2; - temp[0] += temp[3] + temp[6]; - - red = ((int(temp[0]) * 160) >> 17) + 4; - if (red > 31) red = 31; - - if (temp[2] < temp[5]) swap(temp[2], temp[5]); - if (temp[2] < temp[8]) swap(temp[2], temp[8]); - if (temp[5] < temp[8]) swap(temp[5], temp[8]); - temp[5] <<= 1; - temp[2] <<= 2; - temp[2] += temp[5] + temp[8]; - - blue = ((int(temp[2]) * 160) >> 17) + 4; - if (blue > 31) blue = 31; - - if (temp[1] < temp[4]) swap(temp[1], temp[4]); - if (temp[1] < temp[7]) swap(temp[1], temp[7]); - if (temp[4] < temp[7]) swap(temp[4], temp[7]); - temp[4] <<= 1; - temp[1] <<= 2; - temp[1] += temp[4] + temp[7]; - - green = ((int(temp[1]) * 160) >> 17) + 4; - if (green > 31) green = 31; - - pix = red << systemRedShift; - pix += green << systemGreenShift; - pix += blue << systemBlueShift; - - *buf++ = pix; - } -} - -void gbafilter_pal32(u32 * buf, int count) -{ - short temp[3 * 3], s; - unsigned pix; - u8 red, green, blue; - - while (count--) - { - pix = *buf; - - s = curve[(pix >> systemGreenShift) & 0x1f]; - temp[3] = s * influence[3]; - temp[4] = s * influence[4]; - temp[5] = s * influence[5]; - - s = curve[(pix >> systemRedShift) & 0x1f]; - temp[0] = s * influence[0]; - temp[1] = s * influence[1]; - temp[2] = s * influence[2]; - - s = curve[(pix >> systemBlueShift) & 0x1f]; - temp[6] = s * influence[6]; - temp[7] = s * influence[7]; - temp[8] = s * influence[8]; - - if (temp[0] < temp[3]) swap(temp[0], temp[3]); - if (temp[0] < temp[6]) swap(temp[0], temp[6]); - if (temp[3] < temp[6]) swap(temp[3], temp[6]); - temp[3] <<= 1; - temp[0] <<= 2; - temp[0] += temp[3] + temp[6]; - - //red = ((int(temp[0]) * 160) >> 17) + 4; - red = ((int(temp[0]) * 160) >> 14) + 32; - - if (temp[2] < temp[5]) swap(temp[2], temp[5]); - if (temp[2] < temp[8]) swap(temp[2], temp[8]); - if (temp[5] < temp[8]) swap(temp[5], temp[8]); - temp[5] <<= 1; - temp[2] <<= 2; - temp[2] += temp[5] + temp[8]; - - //blue = ((int(temp[2]) * 160) >> 17) + 4; - blue = ((int(temp[2]) * 160) >> 14) + 32; - - if (temp[1] < temp[4]) swap(temp[1], temp[4]); - if (temp[1] < temp[7]) swap(temp[1], temp[7]); - if (temp[4] < temp[7]) swap(temp[4], temp[7]); - temp[4] <<= 1; - temp[1] <<= 2; - temp[1] += temp[4] + temp[7]; - - //green = ((int(temp[1]) * 160) >> 17) + 4; - green = ((int(temp[1]) * 160) >> 14) + 32; - - //pix = red << redshift; - //pix += green << greenshift; - //pix += blue << blueshift; - - pix = red << (systemRedShift - 3); - pix += green << (systemGreenShift - 3); - pix += blue << (systemBlueShift - 3); - - *buf++ = pix; - } -} - -// for palette mode to work with the three spoony filters in 32bpp depth - -void gbafilter_pad(u8 * buf, int count) -{ - union - { - struct - { - u8 r; - u8 g; - u8 b; - u8 a; - } part; - unsigned whole; - } - mask; - - mask.whole = 0x1f << systemRedShift; - mask.whole += 0x1f << systemGreenShift; - mask.whole += 0x1f << systemBlueShift; - - switch (systemColorDepth) - { - case 24: - while (count--) - { - *buf++ &= mask.part.r; - *buf++ &= mask.part.g; - *buf++ &= mask.part.b; - } - break; - case 32: - while (count--) - { - *((u32*)buf) &= mask.whole; - buf += 4; - } - } -} - -/* -void UpdateSystemColorMaps(int lcd) -{ - switch(systemColorDepth) { - case 16: - { - for(int i = 0; i < 0x10000; i++) { - systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | - (((i & 0x3e0) >> 5) << systemGreenShift) | - (((i & 0x7c00) >> 10) << systemBlueShift); - } - if (lcd == 1) gbafilter_pal(systemColorMap16, 0x10000); - } - break; - case 24: - case 32: - { - for(int i = 0; i < 0x10000; i++) { - systemColorMap32[i] = ((i & 0x1f) << systemRedShift) | - (((i & 0x3e0) >> 5) << systemGreenShift) | - (((i & 0x7c00) >> 10) << systemBlueShift); - } - if (lcd == 1) gbafilter_pal32(systemColorMap32, 0x10000); - } - break; - } -} -*/ +#include "gbafilter.h" + +#include + +extern int systemColorDepth; +extern int systemRedShift; +extern int systemGreenShift; +extern int systemBlueShift; + +extern u16 systemColorMap16[0x10000]; +extern u32 systemColorMap32[0x10000]; + +static const unsigned char curve[32] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x10, 0x12, + 0x14, 0x16, 0x18, 0x1c, 0x20, 0x28, 0x30, 0x38, + 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x80, + 0x88, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0}; + +// output R G B +static const unsigned char influence[3 * 3] = { 16, 4, 4, // red + 8, 16, 8, // green + 0, 8, 16};// blue + +inline void swap(short & a, short & b) +{ + short temp = a; + a = b; + b = temp; +} + +void gbafilter_pal(u16 * buf, int count) +{ + short temp[3 * 3], s; + unsigned pix; + u8 red, green, blue; + + while (count--) + { + pix = *buf; + + s = curve[(pix >> systemGreenShift) & 0x1f]; + temp[3] = s * influence[3]; + temp[4] = s * influence[4]; + temp[5] = s * influence[5]; + + s = curve[(pix >> systemRedShift) & 0x1f]; + temp[0] = s * influence[0]; + temp[1] = s * influence[1]; + temp[2] = s * influence[2]; + + s = curve[(pix >> systemBlueShift) & 0x1f]; + temp[6] = s * influence[6]; + temp[7] = s * influence[7]; + temp[8] = s * influence[8]; + + if (temp[0] < temp[3]) swap(temp[0], temp[3]); + if (temp[0] < temp[6]) swap(temp[0], temp[6]); + if (temp[3] < temp[6]) swap(temp[3], temp[6]); + temp[3] <<= 1; + temp[0] <<= 2; + temp[0] += temp[3] + temp[6]; + + red = ((int(temp[0]) * 160) >> 17) + 4; + if (red > 31) red = 31; + + if (temp[2] < temp[5]) swap(temp[2], temp[5]); + if (temp[2] < temp[8]) swap(temp[2], temp[8]); + if (temp[5] < temp[8]) swap(temp[5], temp[8]); + temp[5] <<= 1; + temp[2] <<= 2; + temp[2] += temp[5] + temp[8]; + + blue = ((int(temp[2]) * 160) >> 17) + 4; + if (blue > 31) blue = 31; + + if (temp[1] < temp[4]) swap(temp[1], temp[4]); + if (temp[1] < temp[7]) swap(temp[1], temp[7]); + if (temp[4] < temp[7]) swap(temp[4], temp[7]); + temp[4] <<= 1; + temp[1] <<= 2; + temp[1] += temp[4] + temp[7]; + + green = ((int(temp[1]) * 160) >> 17) + 4; + if (green > 31) green = 31; + + pix = red << systemRedShift; + pix += green << systemGreenShift; + pix += blue << systemBlueShift; + + *buf++ = pix; + } +} + +void gbafilter_pal32(u32 * buf, int count) +{ + short temp[3 * 3], s; + unsigned pix; + u8 red, green, blue; + + while (count--) + { + pix = *buf; + + s = curve[(pix >> systemGreenShift) & 0x1f]; + temp[3] = s * influence[3]; + temp[4] = s * influence[4]; + temp[5] = s * influence[5]; + + s = curve[(pix >> systemRedShift) & 0x1f]; + temp[0] = s * influence[0]; + temp[1] = s * influence[1]; + temp[2] = s * influence[2]; + + s = curve[(pix >> systemBlueShift) & 0x1f]; + temp[6] = s * influence[6]; + temp[7] = s * influence[7]; + temp[8] = s * influence[8]; + + if (temp[0] < temp[3]) swap(temp[0], temp[3]); + if (temp[0] < temp[6]) swap(temp[0], temp[6]); + if (temp[3] < temp[6]) swap(temp[3], temp[6]); + temp[3] <<= 1; + temp[0] <<= 2; + temp[0] += temp[3] + temp[6]; + + //red = ((int(temp[0]) * 160) >> 17) + 4; + red = ((int(temp[0]) * 160) >> 14) + 32; + + if (temp[2] < temp[5]) swap(temp[2], temp[5]); + if (temp[2] < temp[8]) swap(temp[2], temp[8]); + if (temp[5] < temp[8]) swap(temp[5], temp[8]); + temp[5] <<= 1; + temp[2] <<= 2; + temp[2] += temp[5] + temp[8]; + + //blue = ((int(temp[2]) * 160) >> 17) + 4; + blue = ((int(temp[2]) * 160) >> 14) + 32; + + if (temp[1] < temp[4]) swap(temp[1], temp[4]); + if (temp[1] < temp[7]) swap(temp[1], temp[7]); + if (temp[4] < temp[7]) swap(temp[4], temp[7]); + temp[4] <<= 1; + temp[1] <<= 2; + temp[1] += temp[4] + temp[7]; + + //green = ((int(temp[1]) * 160) >> 17) + 4; + green = ((int(temp[1]) * 160) >> 14) + 32; + + //pix = red << redshift; + //pix += green << greenshift; + //pix += blue << blueshift; + + pix = red << (systemRedShift - 3); + pix += green << (systemGreenShift - 3); + pix += blue << (systemBlueShift - 3); + + *buf++ = pix; + } +} + +// for palette mode to work with the three spoony filters in 32bpp depth + +void gbafilter_pad(u8 * buf, int count) +{ + union + { + struct + { + u8 r; + u8 g; + u8 b; + u8 a; + } part; + unsigned whole; + } + mask; + + mask.whole = 0x1f << systemRedShift; + mask.whole += 0x1f << systemGreenShift; + mask.whole += 0x1f << systemBlueShift; + + switch (systemColorDepth) + { + case 24: + while (count--) + { + *buf++ &= mask.part.r; + *buf++ &= mask.part.g; + *buf++ &= mask.part.b; + } + break; + case 32: + while (count--) + { + *((u32*)buf) &= mask.whole; + buf += 4; + } + } +} + +/* +void UpdateSystemColorMaps(int lcd) +{ + switch(systemColorDepth) { + case 16: + { + for(int i = 0; i < 0x10000; i++) { + systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | + (((i & 0x3e0) >> 5) << systemGreenShift) | + (((i & 0x7c00) >> 10) << systemBlueShift); + } + if (lcd == 1) gbafilter_pal(systemColorMap16, 0x10000); + } + break; + case 24: + case 32: + { + for(int i = 0; i < 0x10000; i++) { + systemColorMap32[i] = ((i & 0x1f) << systemRedShift) | + (((i & 0x3e0) >> 5) << systemGreenShift) | + (((i & 0x7c00) >> 10) << systemBlueShift); + } + if (lcd == 1) gbafilter_pal32(systemColorMap32, 0x10000); + } + break; + } +} +*/ diff --git a/src/agb/gbafilter.h b/src/agb/gbafilter.h index 17dfa3cb..18ff53d3 100644 --- a/src/agb/gbafilter.h +++ b/src/agb/gbafilter.h @@ -1,5 +1,5 @@ -#include "../System.h" - -void gbafilter_pal(u16 * buf, int count); -void gbafilter_pal32(u32 * buf, int count); -void gbafilter_pad(u8 * buf, int count); +#include "../System.h" + +void gbafilter_pal(u16 * buf, int count); +void gbafilter_pal32(u32 * buf, int count); +void gbafilter_pad(u8 * buf, int count); diff --git a/src/dmg/GB.cpp b/src/dmg/GB.cpp index 44584892..110bd315 100644 --- a/src/dmg/GB.cpp +++ b/src/dmg/GB.cpp @@ -1,5449 +1,5449 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005-2006 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include -#include -#include -#include - -#include "../System.h" -#include "../NLS.h" -#include "gb.h" -#include "gbCheats.h" -#include "gbGlobals.h" -#include "gbMemory.h" -#include "gbSGB.h" -#include "gbSound.h" -#include "../Util.h" - -#ifdef __GNUC__ -#define _stricmp strcasecmp -#endif - -extern u8 *pix; -extern bool speedup; - -bool gbUpdateSizes(); -bool inBios = false; - -// debugging -bool memorydebug = false; -char gbBuffer[2048]; - -extern u16 gbLineMix[160]; - -// mappers -void (*mapper)(u16,u8) = NULL; -void (*mapperRAM)(u16,u8) = NULL; -u8 (*mapperReadRAM)(u16) = NULL; -void (*mapperUpdateClock)() = NULL; - -// registers -gbRegister PC; -gbRegister SP; -gbRegister AF; -gbRegister BC; -gbRegister DE; -gbRegister HL; -u16 IFF = 0; -// 0xff04 -u8 register_DIV = 0; -// 0xff05 -u8 register_TIMA = 0; -// 0xff06 -u8 register_TMA = 0; -// 0xff07 -u8 register_TAC = 0; -// 0xff0f -u8 register_IF = 0; -// 0xff40 -u8 register_LCDC = 0; -// 0xff41 -u8 register_STAT = 0; -// 0xff42 -u8 register_SCY = 0; -// 0xff43 -u8 register_SCX = 0; -// 0xff44 -u8 register_LY = 0; -// 0xff45 -u8 register_LYC = 0; -// 0xff46 -u8 register_DMA = 0; -// 0xff4a -u8 register_WY = 0; -// 0xff4b -u8 register_WX = 0; -// 0xff4f -u8 register_VBK = 0; -// 0xff51 -u8 register_HDMA1 = 0; -// 0xff52 -u8 register_HDMA2 = 0; -// 0xff53 -u8 register_HDMA3 = 0; -// 0xff54 -u8 register_HDMA4 = 0; -// 0xff55 -u8 register_HDMA5 = 0; -// 0xff70 -u8 register_SVBK = 0; -// 0xffff -u8 register_IE = 0; - -// ticks definition -int GBDIV_CLOCK_TICKS = 64; -int GBLCD_MODE_0_CLOCK_TICKS = 51; -int GBLCD_MODE_1_CLOCK_TICKS = 1140; -int GBLCD_MODE_2_CLOCK_TICKS = 20; -int GBLCD_MODE_3_CLOCK_TICKS = 43; -int GBLY_INCREMENT_CLOCK_TICKS = 114; -int GBTIMER_MODE_0_CLOCK_TICKS = 256; -int GBTIMER_MODE_1_CLOCK_TICKS = 4; -int GBTIMER_MODE_2_CLOCK_TICKS = 16; -int GBTIMER_MODE_3_CLOCK_TICKS = 64; -int GBSERIAL_CLOCK_TICKS = 128; -int GBSYNCHRONIZE_CLOCK_TICKS = 52920; - -// state variables - -// general -int clockTicks = 0; -bool gbSystemMessage = false; -int gbGBCColorType = 0; -int gbHardware = 0; -int gbRomType = 0; -int gbRemainingClockTicks = 0; -int gbOldClockTicks = 0; -int gbIntBreak = 0; -int gbInterruptLaunched = 0; -u8 gbCheatingDevice = 0; // 1 = GS, 2 = GG -// breakpoint -bool breakpoint = false; -// interrupt -int gbInt48Signal = 0; -int gbInterruptWait = 0; -// serial -int gbSerialOn = 0; -int gbSerialTicks = 0; -int gbSerialBits = 0; -// timer -bool gbTimerOn = false; -int gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS; -int gbTimerClockTicks = GBTIMER_MODE_0_CLOCK_TICKS; -int gbTimerMode = 0; -bool gbIncreased = false; -// The internal timer is always active, and it is -// not reset by writing to register_TIMA/TMA, but by -// writing to register_DIV... -int gbInternalTimer = 0x55; -const u8 gbTimerMask [4] = {0xff, 0x3, 0xf, 0x3f}; -const u8 gbTimerBug [8] = {0x80, 0x80, 0x02, 0x02, 0x0, 0xff, 0x0, 0xff}; -bool gbTimerModeChange = false; -bool gbTimerOnChange = false; -// lcd -bool gbScreenOn = true; -int gbLcdMode = 2; -int gbLcdModeDelayed = 2; -int gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS-1; -int gbLcdTicksDelayed = GBLCD_MODE_2_CLOCK_TICKS; -int gbLcdLYIncrementTicks = 114; -int gbLcdLYIncrementTicksDelayed = 115; -int gbScreenTicks = 0; -u8 gbSCYLine[300]; -u8 gbSCXLine[300]; -u8 gbBgpLine[300]; -u8 gbObp0Line [300]; -u8 gbObp1Line [300]; -u8 gbSpritesTicks [300]; -u8 oldRegister_WY; -bool gbLYChangeHappened = false; -bool gbLCDChangeHappened = false; -int gbLine99Ticks = 1; -int gbRegisterLYLCDCOffOn = 0; -int inUseRegister_WY = 0; - -// Used to keep track of the line that ellapse -// when screen is off -int gbWhiteScreen = 0; -bool gbBlackScreen = false; -int register_LCDCBusy = 0; - -// div -int gbDivTicks = GBDIV_CLOCK_TICKS; -// cgb -int gbVramBank = 0; -int gbWramBank = 1; -//sgb -bool gbSgbResetFlag = false; -// gbHdmaDestination is 0x99d0 on startup (tested on HW) -// but I'm not sure what gbHdmaSource is... -int gbHdmaSource = 0x99d0; -int gbHdmaDestination = 0x99d0; -int gbHdmaBytes = 0x0000; -int gbHdmaOn = 0; -int gbSpeed = 0; -// frame counting -int gbFrameCount = 0; -int gbFrameSkip = 0; -int gbFrameSkipCount = 0; -// timing -u32 gbLastTime = 0; -u32 gbElapsedTime = 0; -u32 gbTimeNow = 0; -int gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS; -// emulator features -int gbBattery = 0; -bool gbBatteryError = false; -int gbCaptureNumber = 0; -bool gbCapture = false; -bool gbCapturePrevious = false; -int gbJoymask[4] = { 0, 0, 0, 0 }; - -int gbRomSizes[] = { 0x00008000, // 32K - 0x00010000, // 64K - 0x00020000, // 128K - 0x00040000, // 256K - 0x00080000, // 512K - 0x00100000, // 1024K - 0x00200000, // 2048K - 0x00400000, // 4096K - 0x00800000 // 8192K -}; -int gbRomSizesMasks[] = { 0x00007fff, - 0x0000ffff, - 0x0001ffff, - 0x0003ffff, - 0x0007ffff, - 0x000fffff, - 0x001fffff, - 0x003fffff, - 0x007fffff -}; - -int gbRamSizes[6] = { 0x00000000, // 0K - 0x00002000, // 2K // Changed to 2000 to avoid problems with gbMemoryMap... - 0x00002000, // 8K - 0x00008000, // 32K - 0x00020000, // 128K - 0x00010000 // 64K -}; - -int gbRamSizesMasks[6] = { 0x00000000, - 0x000007ff, - 0x00001fff, - 0x00007fff, - 0x0001ffff, - 0x0000ffff -}; - -int gbCycles[] = { -// 0 1 2 3 4 5 6 7 8 9 a b c d e f - 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1, // 0 - 1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1, // 1 - 2, 3, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 2 - 2, 3, 2, 2, 3, 3, 3, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 3 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 4 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 5 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 6 - 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, // 7 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 8 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 9 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // a - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // b - 2, 3, 3, 4, 3, 4, 2, 4, 2, 4, 3, 2, 3, 6, 2, 4, // c - 2, 3, 3, 1, 3, 4, 2, 4, 2, 4, 3, 1, 3, 1, 2, 4, // d - 3, 3, 2, 1, 1, 4, 2, 4, 4, 1, 4, 1, 1, 1, 2, 4, // e - 3, 3, 2, 1, 1, 4, 2, 4, 3, 2, 4, 1, 0, 1, 2, 4 // f -}; - -int gbCyclesCB[] = { -// 0 1 2 3 4 5 6 7 8 9 a b c d e f - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 0 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 1 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 2 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 3 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 4 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 5 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 6 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 7 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 8 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 9 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // a - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // b - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // c - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // d - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // e - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 // f -}; - -u16 DAATable[] = { - 0x0080,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, - 0x0800,0x0900,0x1020,0x1120,0x1220,0x1320,0x1420,0x1520, - 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, - 0x1800,0x1900,0x2020,0x2120,0x2220,0x2320,0x2420,0x2520, - 0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, - 0x2800,0x2900,0x3020,0x3120,0x3220,0x3320,0x3420,0x3520, - 0x3000,0x3100,0x3200,0x3300,0x3400,0x3500,0x3600,0x3700, - 0x3800,0x3900,0x4020,0x4120,0x4220,0x4320,0x4420,0x4520, - 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, - 0x4800,0x4900,0x5020,0x5120,0x5220,0x5320,0x5420,0x5520, - 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, - 0x5800,0x5900,0x6020,0x6120,0x6220,0x6320,0x6420,0x6520, - 0x6000,0x6100,0x6200,0x6300,0x6400,0x6500,0x6600,0x6700, - 0x6800,0x6900,0x7020,0x7120,0x7220,0x7320,0x7420,0x7520, - 0x7000,0x7100,0x7200,0x7300,0x7400,0x7500,0x7600,0x7700, - 0x7800,0x7900,0x8020,0x8120,0x8220,0x8320,0x8420,0x8520, - 0x8000,0x8100,0x8200,0x8300,0x8400,0x8500,0x8600,0x8700, - 0x8800,0x8900,0x9020,0x9120,0x9220,0x9320,0x9420,0x9520, - 0x9000,0x9100,0x9200,0x9300,0x9400,0x9500,0x9600,0x9700, - 0x9800,0x9900,0x00B0,0x0130,0x0230,0x0330,0x0430,0x0530, - 0x0090,0x0110,0x0210,0x0310,0x0410,0x0510,0x0610,0x0710, - 0x0810,0x0910,0x1030,0x1130,0x1230,0x1330,0x1430,0x1530, - 0x1010,0x1110,0x1210,0x1310,0x1410,0x1510,0x1610,0x1710, - 0x1810,0x1910,0x2030,0x2130,0x2230,0x2330,0x2430,0x2530, - 0x2010,0x2110,0x2210,0x2310,0x2410,0x2510,0x2610,0x2710, - 0x2810,0x2910,0x3030,0x3130,0x3230,0x3330,0x3430,0x3530, - 0x3010,0x3110,0x3210,0x3310,0x3410,0x3510,0x3610,0x3710, - 0x3810,0x3910,0x4030,0x4130,0x4230,0x4330,0x4430,0x4530, - 0x4010,0x4110,0x4210,0x4310,0x4410,0x4510,0x4610,0x4710, - 0x4810,0x4910,0x5030,0x5130,0x5230,0x5330,0x5430,0x5530, - 0x5010,0x5110,0x5210,0x5310,0x5410,0x5510,0x5610,0x5710, - 0x5810,0x5910,0x6030,0x6130,0x6230,0x6330,0x6430,0x6530, - 0x6010,0x6110,0x6210,0x6310,0x6410,0x6510,0x6610,0x6710, - 0x6810,0x6910,0x7030,0x7130,0x7230,0x7330,0x7430,0x7530, - 0x7010,0x7110,0x7210,0x7310,0x7410,0x7510,0x7610,0x7710, - 0x7810,0x7910,0x8030,0x8130,0x8230,0x8330,0x8430,0x8530, - 0x8010,0x8110,0x8210,0x8310,0x8410,0x8510,0x8610,0x8710, - 0x8810,0x8910,0x9030,0x9130,0x9230,0x9330,0x9430,0x9530, - 0x9010,0x9110,0x9210,0x9310,0x9410,0x9510,0x9610,0x9710, - 0x9810,0x9910,0xA030,0xA130,0xA230,0xA330,0xA430,0xA530, - 0xA010,0xA110,0xA210,0xA310,0xA410,0xA510,0xA610,0xA710, - 0xA810,0xA910,0xB030,0xB130,0xB230,0xB330,0xB430,0xB530, - 0xB010,0xB110,0xB210,0xB310,0xB410,0xB510,0xB610,0xB710, - 0xB810,0xB910,0xC030,0xC130,0xC230,0xC330,0xC430,0xC530, - 0xC010,0xC110,0xC210,0xC310,0xC410,0xC510,0xC610,0xC710, - 0xC810,0xC910,0xD030,0xD130,0xD230,0xD330,0xD430,0xD530, - 0xD010,0xD110,0xD210,0xD310,0xD410,0xD510,0xD610,0xD710, - 0xD810,0xD910,0xE030,0xE130,0xE230,0xE330,0xE430,0xE530, - 0xE010,0xE110,0xE210,0xE310,0xE410,0xE510,0xE610,0xE710, - 0xE810,0xE910,0xF030,0xF130,0xF230,0xF330,0xF430,0xF530, - 0xF010,0xF110,0xF210,0xF310,0xF410,0xF510,0xF610,0xF710, - 0xF810,0xF910,0x00B0,0x0130,0x0230,0x0330,0x0430,0x0530, - 0x0090,0x0110,0x0210,0x0310,0x0410,0x0510,0x0610,0x0710, - 0x0810,0x0910,0x1030,0x1130,0x1230,0x1330,0x1430,0x1530, - 0x1010,0x1110,0x1210,0x1310,0x1410,0x1510,0x1610,0x1710, - 0x1810,0x1910,0x2030,0x2130,0x2230,0x2330,0x2430,0x2530, - 0x2010,0x2110,0x2210,0x2310,0x2410,0x2510,0x2610,0x2710, - 0x2810,0x2910,0x3030,0x3130,0x3230,0x3330,0x3430,0x3530, - 0x3010,0x3110,0x3210,0x3310,0x3410,0x3510,0x3610,0x3710, - 0x3810,0x3910,0x4030,0x4130,0x4230,0x4330,0x4430,0x4530, - 0x4010,0x4110,0x4210,0x4310,0x4410,0x4510,0x4610,0x4710, - 0x4810,0x4910,0x5030,0x5130,0x5230,0x5330,0x5430,0x5530, - 0x5010,0x5110,0x5210,0x5310,0x5410,0x5510,0x5610,0x5710, - 0x5810,0x5910,0x6030,0x6130,0x6230,0x6330,0x6430,0x6530, - 0x0600,0x0700,0x0800,0x0900,0x0A00,0x0B00,0x0C00,0x0D00, - 0x0E00,0x0F00,0x1020,0x1120,0x1220,0x1320,0x1420,0x1520, - 0x1600,0x1700,0x1800,0x1900,0x1A00,0x1B00,0x1C00,0x1D00, - 0x1E00,0x1F00,0x2020,0x2120,0x2220,0x2320,0x2420,0x2520, - 0x2600,0x2700,0x2800,0x2900,0x2A00,0x2B00,0x2C00,0x2D00, - 0x2E00,0x2F00,0x3020,0x3120,0x3220,0x3320,0x3420,0x3520, - 0x3600,0x3700,0x3800,0x3900,0x3A00,0x3B00,0x3C00,0x3D00, - 0x3E00,0x3F00,0x4020,0x4120,0x4220,0x4320,0x4420,0x4520, - 0x4600,0x4700,0x4800,0x4900,0x4A00,0x4B00,0x4C00,0x4D00, - 0x4E00,0x4F00,0x5020,0x5120,0x5220,0x5320,0x5420,0x5520, - 0x5600,0x5700,0x5800,0x5900,0x5A00,0x5B00,0x5C00,0x5D00, - 0x5E00,0x5F00,0x6020,0x6120,0x6220,0x6320,0x6420,0x6520, - 0x6600,0x6700,0x6800,0x6900,0x6A00,0x6B00,0x6C00,0x6D00, - 0x6E00,0x6F00,0x7020,0x7120,0x7220,0x7320,0x7420,0x7520, - 0x7600,0x7700,0x7800,0x7900,0x7A00,0x7B00,0x7C00,0x7D00, - 0x7E00,0x7F00,0x8020,0x8120,0x8220,0x8320,0x8420,0x8520, - 0x8600,0x8700,0x8800,0x8900,0x8A00,0x8B00,0x8C00,0x8D00, - 0x8E00,0x8F00,0x9020,0x9120,0x9220,0x9320,0x9420,0x9520, - 0x9600,0x9700,0x9800,0x9900,0x9A00,0x9B00,0x9C00,0x9D00, - 0x9E00,0x9F00,0x00B0,0x0130,0x0230,0x0330,0x0430,0x0530, - 0x0610,0x0710,0x0810,0x0910,0x0A10,0x0B10,0x0C10,0x0D10, - 0x0E10,0x0F10,0x1030,0x1130,0x1230,0x1330,0x1430,0x1530, - 0x1610,0x1710,0x1810,0x1910,0x1A10,0x1B10,0x1C10,0x1D10, - 0x1E10,0x1F10,0x2030,0x2130,0x2230,0x2330,0x2430,0x2530, - 0x2610,0x2710,0x2810,0x2910,0x2A10,0x2B10,0x2C10,0x2D10, - 0x2E10,0x2F10,0x3030,0x3130,0x3230,0x3330,0x3430,0x3530, - 0x3610,0x3710,0x3810,0x3910,0x3A10,0x3B10,0x3C10,0x3D10, - 0x3E10,0x3F10,0x4030,0x4130,0x4230,0x4330,0x4430,0x4530, - 0x4610,0x4710,0x4810,0x4910,0x4A10,0x4B10,0x4C10,0x4D10, - 0x4E10,0x4F10,0x5030,0x5130,0x5230,0x5330,0x5430,0x5530, - 0x5610,0x5710,0x5810,0x5910,0x5A10,0x5B10,0x5C10,0x5D10, - 0x5E10,0x5F10,0x6030,0x6130,0x6230,0x6330,0x6430,0x6530, - 0x6610,0x6710,0x6810,0x6910,0x6A10,0x6B10,0x6C10,0x6D10, - 0x6E10,0x6F10,0x7030,0x7130,0x7230,0x7330,0x7430,0x7530, - 0x7610,0x7710,0x7810,0x7910,0x7A10,0x7B10,0x7C10,0x7D10, - 0x7E10,0x7F10,0x8030,0x8130,0x8230,0x8330,0x8430,0x8530, - 0x8610,0x8710,0x8810,0x8910,0x8A10,0x8B10,0x8C10,0x8D10, - 0x8E10,0x8F10,0x9030,0x9130,0x9230,0x9330,0x9430,0x9530, - 0x9610,0x9710,0x9810,0x9910,0x9A10,0x9B10,0x9C10,0x9D10, - 0x9E10,0x9F10,0xA030,0xA130,0xA230,0xA330,0xA430,0xA530, - 0xA610,0xA710,0xA810,0xA910,0xAA10,0xAB10,0xAC10,0xAD10, - 0xAE10,0xAF10,0xB030,0xB130,0xB230,0xB330,0xB430,0xB530, - 0xB610,0xB710,0xB810,0xB910,0xBA10,0xBB10,0xBC10,0xBD10, - 0xBE10,0xBF10,0xC030,0xC130,0xC230,0xC330,0xC430,0xC530, - 0xC610,0xC710,0xC810,0xC910,0xCA10,0xCB10,0xCC10,0xCD10, - 0xCE10,0xCF10,0xD030,0xD130,0xD230,0xD330,0xD430,0xD530, - 0xD610,0xD710,0xD810,0xD910,0xDA10,0xDB10,0xDC10,0xDD10, - 0xDE10,0xDF10,0xE030,0xE130,0xE230,0xE330,0xE430,0xE530, - 0xE610,0xE710,0xE810,0xE910,0xEA10,0xEB10,0xEC10,0xED10, - 0xEE10,0xEF10,0xF030,0xF130,0xF230,0xF330,0xF430,0xF530, - 0xF610,0xF710,0xF810,0xF910,0xFA10,0xFB10,0xFC10,0xFD10, - 0xFE10,0xFF10,0x00B0,0x0130,0x0230,0x0330,0x0430,0x0530, - 0x0610,0x0710,0x0810,0x0910,0x0A10,0x0B10,0x0C10,0x0D10, - 0x0E10,0x0F10,0x1030,0x1130,0x1230,0x1330,0x1430,0x1530, - 0x1610,0x1710,0x1810,0x1910,0x1A10,0x1B10,0x1C10,0x1D10, - 0x1E10,0x1F10,0x2030,0x2130,0x2230,0x2330,0x2430,0x2530, - 0x2610,0x2710,0x2810,0x2910,0x2A10,0x2B10,0x2C10,0x2D10, - 0x2E10,0x2F10,0x3030,0x3130,0x3230,0x3330,0x3430,0x3530, - 0x3610,0x3710,0x3810,0x3910,0x3A10,0x3B10,0x3C10,0x3D10, - 0x3E10,0x3F10,0x4030,0x4130,0x4230,0x4330,0x4430,0x4530, - 0x4610,0x4710,0x4810,0x4910,0x4A10,0x4B10,0x4C10,0x4D10, - 0x4E10,0x4F10,0x5030,0x5130,0x5230,0x5330,0x5430,0x5530, - 0x5610,0x5710,0x5810,0x5910,0x5A10,0x5B10,0x5C10,0x5D10, - 0x5E10,0x5F10,0x6030,0x6130,0x6230,0x6330,0x6430,0x6530, - 0x00C0,0x0140,0x0240,0x0340,0x0440,0x0540,0x0640,0x0740, - 0x0840,0x0940,0x0440,0x0540,0x0640,0x0740,0x0840,0x0940, - 0x1040,0x1140,0x1240,0x1340,0x1440,0x1540,0x1640,0x1740, - 0x1840,0x1940,0x1440,0x1540,0x1640,0x1740,0x1840,0x1940, - 0x2040,0x2140,0x2240,0x2340,0x2440,0x2540,0x2640,0x2740, - 0x2840,0x2940,0x2440,0x2540,0x2640,0x2740,0x2840,0x2940, - 0x3040,0x3140,0x3240,0x3340,0x3440,0x3540,0x3640,0x3740, - 0x3840,0x3940,0x3440,0x3540,0x3640,0x3740,0x3840,0x3940, - 0x4040,0x4140,0x4240,0x4340,0x4440,0x4540,0x4640,0x4740, - 0x4840,0x4940,0x4440,0x4540,0x4640,0x4740,0x4840,0x4940, - 0x5040,0x5140,0x5240,0x5340,0x5440,0x5540,0x5640,0x5740, - 0x5840,0x5940,0x5440,0x5540,0x5640,0x5740,0x5840,0x5940, - 0x6040,0x6140,0x6240,0x6340,0x6440,0x6540,0x6640,0x6740, - 0x6840,0x6940,0x6440,0x6540,0x6640,0x6740,0x6840,0x6940, - 0x7040,0x7140,0x7240,0x7340,0x7440,0x7540,0x7640,0x7740, - 0x7840,0x7940,0x7440,0x7540,0x7640,0x7740,0x7840,0x7940, - 0x8040,0x8140,0x8240,0x8340,0x8440,0x8540,0x8640,0x8740, - 0x8840,0x8940,0x8440,0x8540,0x8640,0x8740,0x8840,0x8940, - 0x9040,0x9140,0x9240,0x9340,0x9440,0x9540,0x9640,0x9740, - 0x9840,0x9940,0x3450,0x3550,0x3650,0x3750,0x3850,0x3950, - 0x4050,0x4150,0x4250,0x4350,0x4450,0x4550,0x4650,0x4750, - 0x4850,0x4950,0x4450,0x4550,0x4650,0x4750,0x4850,0x4950, - 0x5050,0x5150,0x5250,0x5350,0x5450,0x5550,0x5650,0x5750, - 0x5850,0x5950,0x5450,0x5550,0x5650,0x5750,0x5850,0x5950, - 0x6050,0x6150,0x6250,0x6350,0x6450,0x6550,0x6650,0x6750, - 0x6850,0x6950,0x6450,0x6550,0x6650,0x6750,0x6850,0x6950, - 0x7050,0x7150,0x7250,0x7350,0x7450,0x7550,0x7650,0x7750, - 0x7850,0x7950,0x7450,0x7550,0x7650,0x7750,0x7850,0x7950, - 0x8050,0x8150,0x8250,0x8350,0x8450,0x8550,0x8650,0x8750, - 0x8850,0x8950,0x8450,0x8550,0x8650,0x8750,0x8850,0x8950, - 0x9050,0x9150,0x9250,0x9350,0x9450,0x9550,0x9650,0x9750, - 0x9850,0x9950,0x9450,0x9550,0x9650,0x9750,0x9850,0x9950, - 0xA050,0xA150,0xA250,0xA350,0xA450,0xA550,0xA650,0xA750, - 0xA850,0xA950,0xA450,0xA550,0xA650,0xA750,0xA850,0xA950, - 0xB050,0xB150,0xB250,0xB350,0xB450,0xB550,0xB650,0xB750, - 0xB850,0xB950,0xB450,0xB550,0xB650,0xB750,0xB850,0xB950, - 0xC050,0xC150,0xC250,0xC350,0xC450,0xC550,0xC650,0xC750, - 0xC850,0xC950,0xC450,0xC550,0xC650,0xC750,0xC850,0xC950, - 0xD050,0xD150,0xD250,0xD350,0xD450,0xD550,0xD650,0xD750, - 0xD850,0xD950,0xD450,0xD550,0xD650,0xD750,0xD850,0xD950, - 0xE050,0xE150,0xE250,0xE350,0xE450,0xE550,0xE650,0xE750, - 0xE850,0xE950,0xE450,0xE550,0xE650,0xE750,0xE850,0xE950, - 0xF050,0xF150,0xF250,0xF350,0xF450,0xF550,0xF650,0xF750, - 0xF850,0xF950,0xF450,0xF550,0xF650,0xF750,0xF850,0xF950, - 0x00D0,0x0150,0x0250,0x0350,0x0450,0x0550,0x0650,0x0750, - 0x0850,0x0950,0x0450,0x0550,0x0650,0x0750,0x0850,0x0950, - 0x1050,0x1150,0x1250,0x1350,0x1450,0x1550,0x1650,0x1750, - 0x1850,0x1950,0x1450,0x1550,0x1650,0x1750,0x1850,0x1950, - 0x2050,0x2150,0x2250,0x2350,0x2450,0x2550,0x2650,0x2750, - 0x2850,0x2950,0x2450,0x2550,0x2650,0x2750,0x2850,0x2950, - 0x3050,0x3150,0x3250,0x3350,0x3450,0x3550,0x3650,0x3750, - 0x3850,0x3950,0x3450,0x3550,0x3650,0x3750,0x3850,0x3950, - 0x4050,0x4150,0x4250,0x4350,0x4450,0x4550,0x4650,0x4750, - 0x4850,0x4950,0x4450,0x4550,0x4650,0x4750,0x4850,0x4950, - 0x5050,0x5150,0x5250,0x5350,0x5450,0x5550,0x5650,0x5750, - 0x5850,0x5950,0x5450,0x5550,0x5650,0x5750,0x5850,0x5950, - 0x6050,0x6150,0x6250,0x6350,0x6450,0x6550,0x6650,0x6750, - 0x6850,0x6950,0x6450,0x6550,0x6650,0x6750,0x6850,0x6950, - 0x7050,0x7150,0x7250,0x7350,0x7450,0x7550,0x7650,0x7750, - 0x7850,0x7950,0x7450,0x7550,0x7650,0x7750,0x7850,0x7950, - 0x8050,0x8150,0x8250,0x8350,0x8450,0x8550,0x8650,0x8750, - 0x8850,0x8950,0x8450,0x8550,0x8650,0x8750,0x8850,0x8950, - 0x9050,0x9150,0x9250,0x9350,0x9450,0x9550,0x9650,0x9750, - 0x9850,0x9950,0x9450,0x9550,0x9650,0x9750,0x9850,0x9950, - 0xFA60,0xFB60,0xFC60,0xFD60,0xFE60,0xFF60,0x00C0,0x0140, - 0x0240,0x0340,0x0440,0x0540,0x0640,0x0740,0x0840,0x0940, - 0x0A60,0x0B60,0x0C60,0x0D60,0x0E60,0x0F60,0x1040,0x1140, - 0x1240,0x1340,0x1440,0x1540,0x1640,0x1740,0x1840,0x1940, - 0x1A60,0x1B60,0x1C60,0x1D60,0x1E60,0x1F60,0x2040,0x2140, - 0x2240,0x2340,0x2440,0x2540,0x2640,0x2740,0x2840,0x2940, - 0x2A60,0x2B60,0x2C60,0x2D60,0x2E60,0x2F60,0x3040,0x3140, - 0x3240,0x3340,0x3440,0x3540,0x3640,0x3740,0x3840,0x3940, - 0x3A60,0x3B60,0x3C60,0x3D60,0x3E60,0x3F60,0x4040,0x4140, - 0x4240,0x4340,0x4440,0x4540,0x4640,0x4740,0x4840,0x4940, - 0x4A60,0x4B60,0x4C60,0x4D60,0x4E60,0x4F60,0x5040,0x5140, - 0x5240,0x5340,0x5440,0x5540,0x5640,0x5740,0x5840,0x5940, - 0x5A60,0x5B60,0x5C60,0x5D60,0x5E60,0x5F60,0x6040,0x6140, - 0x6240,0x6340,0x6440,0x6540,0x6640,0x6740,0x6840,0x6940, - 0x6A60,0x6B60,0x6C60,0x6D60,0x6E60,0x6F60,0x7040,0x7140, - 0x7240,0x7340,0x7440,0x7540,0x7640,0x7740,0x7840,0x7940, - 0x7A60,0x7B60,0x7C60,0x7D60,0x7E60,0x7F60,0x8040,0x8140, - 0x8240,0x8340,0x8440,0x8540,0x8640,0x8740,0x8840,0x8940, - 0x8A60,0x8B60,0x8C60,0x8D60,0x8E60,0x8F60,0x9040,0x9140, - 0x9240,0x9340,0x3450,0x3550,0x3650,0x3750,0x3850,0x3950, - 0x3A70,0x3B70,0x3C70,0x3D70,0x3E70,0x3F70,0x4050,0x4150, - 0x4250,0x4350,0x4450,0x4550,0x4650,0x4750,0x4850,0x4950, - 0x4A70,0x4B70,0x4C70,0x4D70,0x4E70,0x4F70,0x5050,0x5150, - 0x5250,0x5350,0x5450,0x5550,0x5650,0x5750,0x5850,0x5950, - 0x5A70,0x5B70,0x5C70,0x5D70,0x5E70,0x5F70,0x6050,0x6150, - 0x6250,0x6350,0x6450,0x6550,0x6650,0x6750,0x6850,0x6950, - 0x6A70,0x6B70,0x6C70,0x6D70,0x6E70,0x6F70,0x7050,0x7150, - 0x7250,0x7350,0x7450,0x7550,0x7650,0x7750,0x7850,0x7950, - 0x7A70,0x7B70,0x7C70,0x7D70,0x7E70,0x7F70,0x8050,0x8150, - 0x8250,0x8350,0x8450,0x8550,0x8650,0x8750,0x8850,0x8950, - 0x8A70,0x8B70,0x8C70,0x8D70,0x8E70,0x8F70,0x9050,0x9150, - 0x9250,0x9350,0x9450,0x9550,0x9650,0x9750,0x9850,0x9950, - 0x9A70,0x9B70,0x9C70,0x9D70,0x9E70,0x9F70,0xA050,0xA150, - 0xA250,0xA350,0xA450,0xA550,0xA650,0xA750,0xA850,0xA950, - 0xAA70,0xAB70,0xAC70,0xAD70,0xAE70,0xAF70,0xB050,0xB150, - 0xB250,0xB350,0xB450,0xB550,0xB650,0xB750,0xB850,0xB950, - 0xBA70,0xBB70,0xBC70,0xBD70,0xBE70,0xBF70,0xC050,0xC150, - 0xC250,0xC350,0xC450,0xC550,0xC650,0xC750,0xC850,0xC950, - 0xCA70,0xCB70,0xCC70,0xCD70,0xCE70,0xCF70,0xD050,0xD150, - 0xD250,0xD350,0xD450,0xD550,0xD650,0xD750,0xD850,0xD950, - 0xDA70,0xDB70,0xDC70,0xDD70,0xDE70,0xDF70,0xE050,0xE150, - 0xE250,0xE350,0xE450,0xE550,0xE650,0xE750,0xE850,0xE950, - 0xEA70,0xEB70,0xEC70,0xED70,0xEE70,0xEF70,0xF050,0xF150, - 0xF250,0xF350,0xF450,0xF550,0xF650,0xF750,0xF850,0xF950, - 0xFA70,0xFB70,0xFC70,0xFD70,0xFE70,0xFF70,0x00D0,0x0150, - 0x0250,0x0350,0x0450,0x0550,0x0650,0x0750,0x0850,0x0950, - 0x0A70,0x0B70,0x0C70,0x0D70,0x0E70,0x0F70,0x1050,0x1150, - 0x1250,0x1350,0x1450,0x1550,0x1650,0x1750,0x1850,0x1950, - 0x1A70,0x1B70,0x1C70,0x1D70,0x1E70,0x1F70,0x2050,0x2150, - 0x2250,0x2350,0x2450,0x2550,0x2650,0x2750,0x2850,0x2950, - 0x2A70,0x2B70,0x2C70,0x2D70,0x2E70,0x2F70,0x3050,0x3150, - 0x3250,0x3350,0x3450,0x3550,0x3650,0x3750,0x3850,0x3950, - 0x3A70,0x3B70,0x3C70,0x3D70,0x3E70,0x3F70,0x4050,0x4150, - 0x4250,0x4350,0x4450,0x4550,0x4650,0x4750,0x4850,0x4950, - 0x4A70,0x4B70,0x4C70,0x4D70,0x4E70,0x4F70,0x5050,0x5150, - 0x5250,0x5350,0x5450,0x5550,0x5650,0x5750,0x5850,0x5950, - 0x5A70,0x5B70,0x5C70,0x5D70,0x5E70,0x5F70,0x6050,0x6150, - 0x6250,0x6350,0x6450,0x6550,0x6650,0x6750,0x6850,0x6950, - 0x6A70,0x6B70,0x6C70,0x6D70,0x6E70,0x6F70,0x7050,0x7150, - 0x7250,0x7350,0x7450,0x7550,0x7650,0x7750,0x7850,0x7950, - 0x7A70,0x7B70,0x7C70,0x7D70,0x7E70,0x7F70,0x8050,0x8150, - 0x8250,0x8350,0x8450,0x8550,0x8650,0x8750,0x8850,0x8950, - 0x8A70,0x8B70,0x8C70,0x8D70,0x8E70,0x8F70,0x9050,0x9150, - 0x9250,0x9350,0x9450,0x9550,0x9650,0x9750,0x9850,0x9950, -}; - -u8 ZeroTable[256] = { - 0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0 -}; - -#define GBSAVE_GAME_VERSION_1 1 -#define GBSAVE_GAME_VERSION_2 2 -#define GBSAVE_GAME_VERSION_3 3 -#define GBSAVE_GAME_VERSION_4 4 -#define GBSAVE_GAME_VERSION_5 5 -#define GBSAVE_GAME_VERSION_6 6 -#define GBSAVE_GAME_VERSION_7 7 -#define GBSAVE_GAME_VERSION_8 8 -#define GBSAVE_GAME_VERSION_9 9 -#define GBSAVE_GAME_VERSION_10 10 -#define GBSAVE_GAME_VERSION_11 11 -#define GBSAVE_GAME_VERSION GBSAVE_GAME_VERSION_11 - -int inline gbGetValue(int min,int max,int v) -{ - return (int)(min+(float)(max-min)*(2.0*(v/31.0)-(v/31.0)*(v/31.0))); -} - -void gbGenFilter() -{ - for (int r=0;r<32;r++) { - for (int g=0;g<32;g++) { - for (int b=0;b<32;b++) { - int nr=gbGetValue(gbGetValue(4,14,g), - gbGetValue(24,29,g),r)-4; - int ng=gbGetValue(gbGetValue(4+gbGetValue(0,5,r), - 14+gbGetValue(0,3,r),b), - gbGetValue(24+gbGetValue(0,3,r), - 29+gbGetValue(0,1,r),b),g)-4; - int nb=gbGetValue(gbGetValue(4+gbGetValue(0,5,r), - 14+gbGetValue(0,3,r),g), - gbGetValue(24+gbGetValue(0,3,r), - 29+gbGetValue(0,1,r),g),b)-4; - gbColorFilter[(b<<10)|(g<<5)|r]=(nb<<10)|(ng<<5)|nr; - } - } - } -} - -bool gbIsGameboyRom(char * file) -{ - if(strlen(file) > 4) { - char * p = strrchr(file,'.'); - - if(p != NULL) { - if(_stricmp(p, ".gb") == 0) - return true; - if(_stricmp(p, ".gbc") == 0) - return true; - if(_stricmp(p, ".cgb") == 0) - return true; - if(_stricmp(p, ".sgb") == 0) - return true; - } - } - - return false; -} - -void gbCopyMemory(u16 d, u16 s, int count) -{ - while(count) { - gbMemoryMap[d>>12][d & 0x0fff] = gbMemoryMap[s>>12][s & 0x0fff]; - s++; - d++; - count--; - } -} - -void gbDoHdma() -{ - - gbCopyMemory((gbHdmaDestination & 0x1ff0) | 0x8000, - gbHdmaSource & 0xfff0, - 0x10); - - gbHdmaDestination += 0x10; - if (gbHdmaDestination == 0xa000) - gbHdmaDestination = 0x8000; - - gbHdmaSource += 0x10; - if (gbHdmaSource == 0x8000) - gbHdmaSource = 0xa000; - - register_HDMA2 = gbHdmaSource & 0xff; - register_HDMA1 = gbHdmaSource>>8; - - register_HDMA4 = gbHdmaDestination & 0xff; - register_HDMA3 = gbHdmaDestination>>8; - - gbHdmaBytes -= 0x10; - gbMemory[0xff55] = --register_HDMA5; - if(register_HDMA5 == 0xff) - gbHdmaOn = 0; - -// We need to add the dmaClockticks for HDMA ! - if(gbSpeed) - gbDmaTicks = 17; - else - gbDmaTicks = 9; - - if (IFF & 0x80) - gbDmaTicks++; - -} - -// fix for Harley and Lego Racers -void gbCompareLYToLYC() -{ - if(register_LCDC & 0x80) { - if(register_LY == register_LYC) { - - // mark that we have a match - register_STAT |= 4; - - // check if we need an interrupt - if (register_STAT & 0x40) - { - // send LCD interrupt only if no interrupt 48h signal... - if (!gbInt48Signal) - { - register_IF |=2; - } - gbInt48Signal |= 8; - } - } - else // no match - { - register_STAT &= 0xfb; - gbInt48Signal &=~8; - } - } -} - -void gbWriteMemory(register u16 address, register u8 value) -{ - - if(address < 0x8000) { -#ifndef FINAL_VERSION - if(memorydebug && (address>0x3fff || address < 0x2000)) { - log("Memory register write %04x=%02x PC=%04x\n", - address, - value, - PC.W); - } - -#endif - if(mapper) - (*mapper)(address, value); - return; - - } - - if(address < 0xa000) { - // No access to Vram during mode 3 - // (used to emulate the gfx differences between GB & GBC-GBA/SP in Stunt Racer) - if ((gbLcdModeDelayed !=3) || - // This part is used to emulate a small difference between hardwares - // (check 8-in-1's arrow on GBA/GBC to verify it) - ((register_LY == 0) && ((gbHardware & 0xa) && (gbScreenOn==false) && - (register_LCDC & 0x80)) && - (gbLcdLYIncrementTicksDelayed ==(GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS)))) - gbMemoryMap[address>>12][address&0x0fff] = value; - return; - } - - // Used for the mirroring of 0xC000 in 0xE000 - if ((address >= 0xe000) && (address < 0xfe00)) - address &= ~0x2000; - - if(address < 0xc000) { -#ifndef FINAL_VERSION - if(memorydebug) { - log("Memory register write %04x=%02x PC=%04x\n", - address, - value, - PC.W); - } -#endif - - // Is that a correct fix ??? (it used to be 'if (mapper)')... - if(mapperRAM) - (*mapperRAM)(address, value); - return; - } - - - if(address < 0xfe00) { - gbMemoryMap[address>>12][address & 0x0fff] = value; - return; - } - - // OAM not accessible during mode 2 & 3. - if(address < 0xfea0) - { - if (((gbHardware & 0xa) && ((gbLcdMode | gbLcdModeDelayed) &2)) || - ((gbHardware & 5) && (((gbLcdModeDelayed == 2) && - (gbLcdTicksDelayed<=GBLCD_MODE_2_CLOCK_TICKS)) || - (gbLcdModeDelayed == 3)))) - return; - else - { - gbMemory[address] = value; - return; - } - } - - - - if((address > 0xfea0) && (address < 0xff00)){ // GBC allows reading/writing to that area - gbMemory[address] = value; - return; - } - - switch(address & 0x00ff) { - - case 0x00: { - gbMemory[0xff00] = ((gbMemory[0xff00] & 0xcf) | - (value & 0x30) | 0xc0); - if(gbSgbMode) { - gbSgbDoBitTransfer(value); - } - return; - } - - case 0x01: { - gbMemory[0xff01] = value; - return; - } - - // serial control - case 0x02: { - gbSerialOn = (value & 0x80); - gbMemory[0xff02] = value; - if(gbSerialOn) { - gbSerialTicks = GBSERIAL_CLOCK_TICKS; -#ifdef LINK_EMULATION - if(linkConnected) { - if(value & 1) { - linkSendByte(0x100|gbMemory[0xFF01]); - Sleep(5); - } - } -#endif - } - - gbSerialBits = 0; - return; - } - - case 0x04: { - // DIV register resets on any write - // (not totally perfect, but better than nothing) - gbMemory[0xff04] = register_DIV = 0; - gbDivTicks = GBDIV_CLOCK_TICKS; - // Another weird timer 'bug' : - // Writing to DIV register resets the internal timer, - // and can also increase TIMA/trigger an interrupt - // in some cases... - if (gbTimerOn && !(gbInternalTimer & (gbTimerClockTicks>>1))) - { - gbMemory[0xff05] = ++register_TIMA; - if(register_TIMA == 0) { - // timer overflow! - - // reload timer modulo - gbMemory[0xff05] = register_TIMA = register_TMA; - - // flag interrupt - gbMemory[0xff0f] = register_IF |= 4; - } - } - gbInternalTimer = 0xff; - return; - } - case 0x05: - gbMemory[0xff05] = register_TIMA = value; - return; - - case 0x06: - gbMemory[0xff06] = register_TMA = value; - return; - - // TIMER control - case 0x07: { - - gbTimerModeChange = (((value & 3) != (register_TAC&3)) && (value & register_TAC & 4)) ? true : false; - gbTimerOnChange = (((value ^ register_TAC) & 4) == 4) ? true : false; - - gbTimerOn = (value & 4) ? true : false; - - if (gbTimerOnChange || gbTimerModeChange) - { - gbTimerMode = value & 3; - - switch(gbTimerMode) { - case 0: - gbTimerClockTicks = GBTIMER_MODE_0_CLOCK_TICKS; - break; - case 1: - gbTimerClockTicks = GBTIMER_MODE_1_CLOCK_TICKS; - break; - case 2: - gbTimerClockTicks = GBTIMER_MODE_2_CLOCK_TICKS; - break; - case 3: - gbTimerClockTicks = GBTIMER_MODE_3_CLOCK_TICKS; - break; - } - } - - - // This looks weird, but this emulates a bug in which register_TIMA - // is increased when writing to register_TAC - // (This fixes Korodice's long-delay between menus bug). - - if (gbTimerOnChange || gbTimerModeChange) - { - bool temp = false; - - if ((gbTimerOn && !gbTimerModeChange) && (gbTimerMode & 2) && - !(gbInternalTimer & 0x80) && (gbInternalTimer & (gbTimerClockTicks>>1)) && - !(gbInternalTimer & (gbTimerClockTicks>>5))) - temp = true; - else if ((!gbTimerOn && !gbTimerModeChange && gbTimerOnChange ) && ((gbTimerTicks-1) < (gbTimerClockTicks>>1))) - temp = true; - else if (gbTimerOn && gbTimerModeChange && !gbTimerOnChange) - { - switch(gbTimerMode & 3) - { - case 0x00: - temp = false; - break; - case 0x01: - if (((gbInternalTimer & 0x82) == 2) && (gbTimerTicks>(clockTicks+1))) - temp = true; - break; - case 0x02: - if (((gbInternalTimer & 0x88) == 0x8) && (gbTimerTicks>(clockTicks+1))) - temp = true; - break; - case 0x03: - if (((gbInternalTimer & 0xA0) == 0x20) && (gbTimerTicks>(clockTicks+1))) - temp = true; - break; - } - } - - if (temp) - { - gbMemory[0xff05] = ++register_TIMA; - if((register_TIMA & 0xff) == 0) { - // timer overflow! - - // reload timer modulo - gbMemory[0xff05] = register_TIMA = register_TMA; - - // flag interrupt - gbMemory[0xff0f] = register_IF |= 4; - } - } - } - gbMemory[0xff07] = register_TAC = value; - return; - } - - case 0x0f: { - gbMemory[0xff0f] = register_IF = value; - //gbMemory[0xff0f] = register_IE |= value; - return; - } - - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1a: - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: { - if (gbMemory[NR52] & 0x80) { - SOUND_EVENT(address,value); - return; - } - } - - case 0x26: { - SOUND_EVENT(address,value); - return; - } - - 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: { - SOUND_EVENT(address,value); - //gbMemory[address] = value; - return; - } - - case 0x40: { - int lcdChange = (register_LCDC & 0x80) ^ (value & 0x80); - - // don't draw the window if it was not enabled and not being drawn before - if(!(register_LCDC & 0x20) && (value & 0x20) && gbWindowLine == -1 && - register_LY > register_WY) - gbWindowLine = 146; - // 007 fix : don't draw the first window's 1st line if it's enable 'too late' - // (ie. if register_LY == register_WY when enabling it) - // and move it to the next line - else if (!(register_LCDC & 0x20) && (value & 0x20) && (register_LY == register_WY)) - gbWindowLine = -2; - - - gbMemory[0xff40] = register_LCDC = value; - - - if(lcdChange) { - if((value & 0x80) && (!register_LCDCBusy)) { - - // if (!gbWhiteScreen && !gbSgbMask) - - // systemDrawScreen(); - - - - gbRegisterLYLCDCOffOn = (register_LY + 144) % 154; - - gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS - (gbSpeed ? 2 : 1); - gbLcdTicksDelayed = GBLCD_MODE_2_CLOCK_TICKS - (gbSpeed ? 1 : 0); - gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS - (gbSpeed ? 2 : 1); - gbLcdLYIncrementTicksDelayed = GBLY_INCREMENT_CLOCK_TICKS - (gbSpeed ? 1 : 0); - gbLcdMode = 2; - gbLcdModeDelayed = 2; - gbMemory[0xff41] = register_STAT = (register_STAT & 0xfc) | 2; - gbMemory[0xff44] = register_LY = 0x00; - gbInt48Signal = 0; - gbLYChangeHappened = false; - gbLCDChangeHappened = false; - gbWindowLine = 146; - oldRegister_WY = 146; - - // Fix for Namco Gallery Vol.2 - // (along with updating register_LCDC at the start of 'case 0x40') : - if(register_STAT & 0x20) - { - // send LCD interrupt only if no interrupt 48h signal... - if (!gbInt48Signal) - { - gbMemory[0xff0f] = register_IF |= 2; - } - gbInt48Signal |= 4; - } - gbCompareLYToLYC(); - - } else { - - register_LCDCBusy = clockTicks+6; - - //used to update the screen with white lines when it's off. - //(it looks strange, but it's pretty accurate) - - gbWhiteScreen = 0; - - gbScreenTicks = ((150-register_LY)*GBLY_INCREMENT_CLOCK_TICKS + - (49<<(gbSpeed ? 1 : 0))); - - // disable the screen rendering - gbScreenOn = false; - gbLcdTicks = 0; - gbLcdMode = 0; - gbLcdModeDelayed = 0; - gbMemory[0xff41] = register_STAT &= 0xfc; - gbInt48Signal = 0; - } - } - return; - } - - // STAT - case 0x41: { - //register_STAT = (register_STAT & 0x87) | - // (value & 0x7c); - gbMemory[0xff41] = register_STAT = (value & 0xf8) | (register_STAT & 0x07); // fix ? - // GB bug from Devrs FAQ - // Corrected : it happens if Lcd Mode<2, but also if LY == LYC whatever - // Lcd Mode is, and if !gbInt48Signal in all cases. The screen being off - // doesn't matter (the bug will still happen). - // That fixes 'Satoru Nakajima - F-1 Hero' crash bug. - - if((gbHardware & 5) && (((!gbInt48Signal) && (gbLcdMode<2) && (register_LCDC & 0x80)) || - (register_LY == register_LYC))) - { - gbMemory[0xff0f] = register_IF |=2; - } - - gbInt48Signal &= ((register_STAT>>3) & 0xF); - - if((register_LCDC & 0x80)) { - if ((register_STAT & 0x08) && (gbLcdMode == 0)) - { - if (!gbInt48Signal) - { - gbMemory[0xff0f] = register_IF |=2; - } - gbInt48Signal |= 1; - } - if ((register_STAT & 0x10) && (gbLcdMode == 1)) - { - if (!gbInt48Signal) - { - gbMemory[0xff0f] = register_IF |=2; - } - gbInt48Signal |= 2; - } - if ((register_STAT & 0x20) && (gbLcdMode == 2)) - { - if (!gbInt48Signal) - { - gbMemory[0xff0f] = register_IF |=2; - } - gbInt48Signal |= 4; - } - gbCompareLYToLYC(); - - gbMemory[0xff0f] = register_IF; - gbMemory[0xff41] = register_STAT; - - } - return; - } - - // SCY - case 0x42: { - int temp = -1; - - if ((gbLcdMode == 3) || (gbLcdModeDelayed == 3)) - temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - - gbLcdLYIncrementTicks); - - if (temp >=0) - { - for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) - if (temp < 300) - gbSCYLine[i] = value; - } - - else - memset(gbSCYLine, value, sizeof(gbSCYLine)); - - gbMemory[0xff42] = register_SCY = value; - return; - } - - // SCX - case 0x43: { - int temp = -1; - - if (gbLcdModeDelayed == 3) - temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - - gbLcdLYIncrementTicksDelayed); - - if (temp >=0) - { - for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) - if (temp < 300) - gbSCXLine[i] = value; - } - - else - memset(gbSCXLine, value, sizeof(gbSCXLine)); - - gbMemory[0xff43] = register_SCX = value; - return; - } - - // LY - case 0x44: { - // read only - return; - } - - // LYC - case 0x45: { - if (register_LYC != value) - { - gbMemory[0xff45] = register_LYC = value; - if(register_LCDC & 0x80) { - gbCompareLYToLYC(); - } - } - return; - } - - // DMA! - case 0x46: { - int source = value * 0x0100; - - gbCopyMemory(0xfe00, - source, - 0xa0); - gbMemory[0xff46] = register_DMA = value; - return; - } - - // BGP - case 0x47: { - - int temp = -1; - - gbMemory[0xff47] = value; - - if (gbLcdModeDelayed == 3) - temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - - gbLcdLYIncrementTicksDelayed); - - if (temp >=0) - { - for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) - if (temp < 300) - gbBgpLine[i] = value; - } - else - memset(gbBgpLine,value,sizeof(gbBgpLine)); - - gbBgp[0] = value & 0x03; - gbBgp[1] = (value & 0x0c)>>2; - gbBgp[2] = (value & 0x30)>>4; - gbBgp[3] = (value & 0xc0)>>6; - break; - } - - // OBP0 - case 0x48: { - int temp = -1; - - gbMemory[0xff48] = value; - - if (gbLcdModeDelayed == 3) - temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - - gbLcdLYIncrementTicksDelayed); - - if (temp >=0) - { - for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) - if (temp < 300) - gbObp0Line[i] = value; - } - else - memset(gbObp0Line,value,sizeof(gbObp0Line)); - - gbObp0[0] = value & 0x03; - gbObp0[1] = (value & 0x0c)>>2; - gbObp0[2] = (value & 0x30)>>4; - gbObp0[3] = (value & 0xc0)>>6; - break; - } - - // OBP1 - case 0x49: { - int temp = -1; - - gbMemory[0xff49] = value; - - if (gbLcdModeDelayed == 3) - temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - - gbLcdLYIncrementTicksDelayed); - - if (temp >=0) - { - for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) - if (temp < 300) - gbObp1Line[i] = value; - } - else - memset(gbObp1Line,value,sizeof(gbObp1Line)); - - gbObp1[0] = value & 0x03; - gbObp1[1] = (value & 0x0c)>>2; - gbObp1[2] = (value & 0x30)>>4; - gbObp1[3] = (value & 0xc0)>>6; - break; - } - - // WY - case 0x4a: - gbMemory[0xff4a] = register_WY = value; - if ((register_LY <= register_WY) && ((gbWindowLine < 0) || (gbWindowLine>=144))) - { - gbWindowLine = -1; - oldRegister_WY = register_WY; - } - return; - - // WX - case 0x4b: - gbMemory[0xff4b] = register_WX = value; - return; - - // KEY1 - case 0x4d: { - if(gbCgbMode) { - gbMemory[0xff4d] = (gbMemory[0xff4d] & 0x80) | (value & 1) | 0x7e; - return; - } - } - break; - - // VBK - case 0x4f: { - if(gbCgbMode) { - value = value & 1; - if(value == gbVramBank) - return; - - int vramAddress = value * 0x2000; - gbMemoryMap[0x08] = &gbVram[vramAddress]; - gbMemoryMap[0x09] = &gbVram[vramAddress + 0x1000]; - - gbVramBank = value; - register_VBK = value; - } - return; - } - break; - - // BOOTROM disable register (also gbCgbMode enabler if value & 0x10 ?) - case 0x50 : - { - if (useBios && inBios && !skipBios && (value & 1)) - { - gbMemoryMap[0x00] = &gbRom[0x0000]; - memcpy ((u8 *)(gbRom+0x100), (u8 *)(gbMemory + 0x100), 0xF00); - inBios = false; - } - } - - // HDMA1 - case 0x51: { - if(gbCgbMode) { - if(value > 0x7f && value < 0xa0) - value = 0; - - gbHdmaSource = (value << 8) | (gbHdmaSource & 0xf0); - - register_HDMA1 = value; - return; - } - } - break; - - // HDMA2 - case 0x52: { - if(gbCgbMode) { - value = value & 0xf0; - - gbHdmaSource = (gbHdmaSource & 0xff00) | (value); - - register_HDMA2 = value; - return; - } - } - break; - - // HDMA3 - case 0x53: { - if(gbCgbMode) { - value = value & 0x1f; - gbHdmaDestination = (value << 8) | (gbHdmaDestination & 0xf0); - gbHdmaDestination |= 0x8000; - register_HDMA3 = value; - return; - } - } - break; - - // HDMA4 - case 0x54: { - if(gbCgbMode) { - value = value & 0xf0; - gbHdmaDestination = (gbHdmaDestination & 0x1f00) | value; - gbHdmaDestination |= 0x8000; - register_HDMA4 = value; - return; - } - } - break; - - // HDMA5 - case 0x55: { - - if(gbCgbMode) { - gbHdmaBytes = 16 + (value & 0x7f) * 16; - if(gbHdmaOn) { - if(value & 0x80) { - gbMemory[0xff55] = register_HDMA5 = (value & 0x7f); - } else { - register_HDMA5 = 0xff; - gbHdmaOn = 0; - } - } else { - if(value & 0x80) { - gbHdmaOn = 1; - gbMemory[0xff55] = register_HDMA5 = value & 0x7f; - if(gbLcdModeDelayed == 0) - gbDoHdma(); - } else { - // we need to take the time it takes to complete the transfer into - // account... according to GB DEV FAQs, the setup time is the same - // for single and double speed, but the actual transfer takes the - // same time - if(gbSpeed) - gbDmaTicks = 2+16 * ((value & 0x7f) +1); - else - gbDmaTicks = 1+8 * ((value & 0x7f)+1); - - gbCopyMemory((gbHdmaDestination & 0x1ff0) | 0x8000, - gbHdmaSource & 0xfff0, - gbHdmaBytes); - gbHdmaDestination += gbHdmaBytes; - gbHdmaSource += gbHdmaBytes; - - gbMemory[0xff51] = register_HDMA1 = 0xff;// = (gbHdmaSource >> 8) & 0xff; - gbMemory[0xff52] = register_HDMA2 = 0xff;// = gbHdmaSource & 0xf0; - gbMemory[0xff53] = register_HDMA3 = 0xff;// = ((gbHdmaDestination - 0x8000) >> 8) & 0x1f; - gbMemory[0xff54] = register_HDMA4 = 0xff;// = gbHdmaDestination & 0xf0; - gbMemory[0xff55] = register_HDMA5 = 0xff; - } - } - return; - } - } - break; - - // BCPS - case 0x68: { - if(gbCgbMode) { - int paletteIndex = (value & 0x3f) >> 1; - int paletteHiLo = (value & 0x01); - - gbMemory[0xff68] = value; - - gbMemory[0xff69] = (paletteHiLo ? - (gbPalette[paletteIndex] >> 8) : - (gbPalette[paletteIndex] & 0x00ff)); - return; - } - } - break; - - // BCPD - case 0x69: { - if(gbCgbMode) { - int v = gbMemory[0xff68]; - int paletteIndex = (v & 0x3f) >> 1; - int paletteHiLo = (v & 0x01); - - // No access to gbPalette during mode 3 (Color Panel Demo) - if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || - (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || - ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || - ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) - { - gbMemory[0xff69] = value; - gbPalette[paletteIndex] = (paletteHiLo ? - ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : - ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; - } - - - if(gbMemory[0xff68] & 0x80) { - int index = ((gbMemory[0xff68] & 0x3f) + 1) & 0x3f; - - gbMemory[0xff68] = (gbMemory[0xff68] & 0x80) | index; - gbMemory[0xff69] = (index & 1 ? - (gbPalette[index>>1] >> 8) : - (gbPalette[index>>1] & 0x00ff)); - } - return; - } - } - break; - - // OCPS - case 0x6a: { - if(gbCgbMode) { - int paletteIndex = (value & 0x3f) >> 1; - int paletteHiLo = (value & 0x01); - - paletteIndex += 32; - - gbMemory[0xff6a] = value; - - gbMemory[0xff6b] = (paletteHiLo ? - (gbPalette[paletteIndex] >> 8) : - (gbPalette[paletteIndex] & 0x00ff)); - return; - } - } - break; - - // OCPD - case 0x6b: { - - if(gbCgbMode) { - int v = gbMemory[0xff6a]; - int paletteIndex = (v & 0x3f) >> 1; - int paletteHiLo = (v & 0x01); - - paletteIndex += 32; - - // No access to gbPalette during mode 3 (Color Panel Demo) - if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || - (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || - ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || - ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) - { - gbMemory[0xff6b] = value; - gbPalette[paletteIndex] = (paletteHiLo ? - ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : - ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; - } - - if(gbMemory[0xff6a] & 0x80) { - int index = ((gbMemory[0xff6a] & 0x3f) + 1) & 0x3f; - - gbMemory[0xff6a] = (gbMemory[0xff6a] & 0x80) | index; - - gbMemory[0xff6b] = (index & 1 ? - (gbPalette[(index>>1) + 32] >> 8) : - (gbPalette[(index>>1) + 32] & 0x00ff)); - } - return; - } - } - break; - - case 0x6c: { - gbMemory[0xff6c] = 0xfe | value; - return; - } - - - // SVBK - case 0x70: { - if(gbCgbMode) { - value = value & 7; - - int bank = value; - if(value == 0) - bank = 1; - - if(bank == gbWramBank) - return; - - int wramAddress = bank * 0x1000; - gbMemoryMap[0x0d] = &gbWram[wramAddress]; - - gbWramBank = bank; - gbMemory[0xff70] = register_SVBK = value; - return; - } - } - - case 0x75:{ - gbMemory[0xff75] = 0x8f | value; - return; - } - - case 0xff: { - gbMemory[0xffff] = register_IE = value; - return; - } - } - - if(address < 0xff80) - { - gbMemory[address] = value; - return; - } - - gbMemory[address] = value; -} - -u8 gbReadOpcode(register u16 address) -{ - if(gbCheatMap[address]) - return gbCheatRead(address); - - if(address < 0x8000) - return gbMemoryMap[address>>12][address&0x0fff]; - - if(address < 0xa000) - { - // A lot of 'ugly' checks... But only way to emulate this particular behaviour... - if (((gbHardware & 0xa) && ((gbLcdModeDelayed !=3) || ((register_LY == 0) && - (gbScreenOn==false) && (register_LCDC & 0x80)) && - (gbLcdLYIncrementTicksDelayed ==(GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS)))) || - ((gbHardware & 0x5) && (gbLcdModeDelayed !=3) && - ((gbLcdMode !=3) || ((register_LY == 0) && ((gbScreenOn==false) && - (register_LCDC & 0x80)) && - (gbLcdLYIncrementTicks ==(GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS)))))) - return gbMemoryMap[address>>12][address&0x0fff]; - return 0xff; - } - - // Used for the mirroring of 0xC000 in 0xE000 - if ((address >= 0xe000) && (address < 0xfe00)) - address &= ~0x2000; - - switch(address & 0xf000) { - case 0x0a: - case 0x0b: - if(mapperReadRAM) - return mapperReadRAM(address); - break; - case 0x0f: - if(address > 0xff00) { - switch(address & 0x00ff) { - case 0x02: - return (gbMemory[0xff02]); - case 0x03: - return (0xff); - case 0x04: - return register_DIV; - case 0x05: - return register_TIMA; - case 0x06: - return register_TMA; - case 0x07: - return (0xf8 | register_TAC); - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - return (0xff); - case 0x0f: - return (0xe0 | gbMemory[0xff0f]); - case 0x40: - return register_LCDC; - case 0x41: - // This is a GB/C only bug (ie. not GBA/SP). - if ((gbHardware & 7) && (gbLcdMode == 2) && (gbLcdModeDelayed == 1) && (!gbSpeed)) - return (0x80 | gbMemory[0xff41] & 0xFC); - else - return (0x80 | gbMemory[0xff41]); - case 0x42: - return register_SCY; - case 0x43: - return register_SCX; - case 0x44: - if (((gbHardware & 7) && ((gbLcdMode == 1) && (gbLcdTicks == 0x71))) || - (!(register_LCDC && 0x80))) - return 0; - else - return register_LY; - case 0x45: - return register_LYC; - case 0x46: - return register_DMA; - case 0x4a: - return register_WY; - case 0x4b: - return register_WX; - case 0x4c: - return 0xff; - case 0x4f: - return (0xfe | register_VBK); - case 0x51: - return register_HDMA1; - case 0x52: - return register_HDMA2; - case 0x53: - return register_HDMA3; - case 0x54: - return register_HDMA4; - case 0x55: - return register_HDMA5; - case 0x68: - case 0x6a: - if (gbCgbMode) - return (0x40 | gbMemory[address]); - else - return 0xc0; - case 0x69: - case 0x6b: - if (gbCgbMode) - { - // No access to gbPalette during mode 3 (Color Panel Demo) - if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || - (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || - ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || - ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) - return (gbMemory[address]); - else - return 0xff; - } - else - return 0xff; - case 0x70: - if (gbCgbMode) - return (0xf8 | register_SVBK); - else - return 0xff; - case 0xff: - return register_IE; - } - } - // OAM not accessible during mode 2 & 3. - if(((address >= 0xfe00) && (address<0xfea0)) && - ((gbLcdMode | gbLcdModeDelayed) &2)) - return 0xff; - break; - } - - if ((address >= 0xfea0) && (address < 0xff00)) - { - if (gbHardware & 1) - return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0x00 : 0xff ); - else if (gbHardware & 2) - return gbMemoryMap[address>>12][address & 0x0fff]; - else if (gbHardware & 4) - return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0xff : 0x00 ); - else if (gbHardware & 8) - return ((address & 0xf0) |((address & 0xf0)>>4)); - } - - return gbMemoryMap[address>>12][address & 0x0fff]; -} - -u8 gbReadMemory(register u16 address) -{ - if(gbCheatMap[address]) - return gbCheatRead(address); - - - if(address < 0x8000) - return gbMemoryMap[address>>12][address&0x0fff]; - - if(address < 0xa000) - { - // A lot of 'ugly' checks... But only way to emulate this particular behaviour... - if (((gbHardware & 0xa) && ((gbLcdModeDelayed !=3) || ((register_LY == 0) && - (gbScreenOn==false) && (register_LCDC & 0x80)) && - (gbLcdLYIncrementTicksDelayed ==(GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS)))) || - ((gbHardware & 0x5) && (gbLcdModeDelayed !=3) && - ((gbLcdMode !=3) || ((register_LY == 0) && ((gbScreenOn==false) && - (register_LCDC & 0x80)) && - (gbLcdLYIncrementTicks ==(GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS)))))) - return gbMemoryMap[address>>12][address&0x0fff]; - return 0xff; - } - - if ((address >= 0xe000) && (address < 0xfe00)) - address &= ~0x2000; - - if(address < 0xc000) { -#ifndef FINAL_VERSION - if(memorydebug) { - log("Memory register read %04x PC=%04x\n", - address, - PC.W); - } -#endif - - // for the 2kb ram limit (fixes crash in shawu's story - // but now its sram test fails, as the it expects 8kb and not 2kb... - // So use the 'genericflashcard' option to fix it). - if (address<=(0xa000+gbRamSizeMask)) - { - if(mapperReadRAM) - return mapperReadRAM(address); - return gbMemoryMap[address>>12][address & 0x0fff]; - } - return 0xff; - } - - if(address >= 0xff00) { - if ( address >= 0xFF10 && address <= 0xFF3F ) - return gbSoundRead( address ); - - switch(address & 0x00ff) { - case 0x00: - { - if(gbSgbMode) { - gbSgbReadingController |= 4; - gbSgbResetPacketState(); - } - - int b = gbMemory[0xff00]; - - if((b & 0x30) == 0x20) { - b &= 0xf0; - - int joy = 0; - if(gbSgbMode && gbSgbMultiplayer) { - switch(gbSgbNextController) { - case 0x0f: - joy = 0; - break; - case 0x0e: - joy = 1; - break; - case 0x0d: - joy = 2; - break; - case 0x0c: - joy = 3; - break; - default: - joy = 0; - } - } - int joystate = gbJoymask[joy]; - if(!(joystate & 128)) - b |= 0x08; - if(!(joystate & 64)) - b |= 0x04; - if(!(joystate & 32)) - b |= 0x02; - if(!(joystate & 16)) - b |= 0x01; - - gbMemory[0xff00] = b; - } else if((b & 0x30) == 0x10) { - b &= 0xf0; - - int joy = 0; - if(gbSgbMode && gbSgbMultiplayer) { - switch(gbSgbNextController) { - case 0x0f: - joy = 0; - break; - case 0x0e: - joy = 1; - break; - case 0x0d: - joy = 2; - break; - case 0x0c: - joy = 3; - break; - default: - joy = 0; - } - } - int joystate = gbJoymask[joy]; - if(!(joystate & 8)) - b |= 0x08; - if(!(joystate & 4)) - b |= 0x04; - if(!(joystate & 2)) - b |= 0x02; - if(!(joystate & 1)) - b |= 0x01; - - gbMemory[0xff00] = b; - } else { - if(gbSgbMode && gbSgbMultiplayer) { - gbMemory[0xff00] = 0xf0 | gbSgbNextController; - } else { - gbMemory[0xff00] = 0xff; - } - } - } - return gbMemory[0xff00]; - break; - case 0x01: - return gbMemory[0xff01]; - case 0x02: - return (gbMemory[0xff02]); - case 0x04: - return register_DIV; - case 0x05: - return register_TIMA; - case 0x06: - return register_TMA; - case 0x07: - return (0xf8 | register_TAC); - case 0x0f: - return (0xe0 | gbMemory[0xff0f]); - 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: - if ((gbMemory[NR30] & 0x80) && (gbMemory[NR34] & 0x80)) - return 0xFF; - else - return gbMemoryMap[address>>12][address & 0x0fff]; - case 0x40: - return register_LCDC; - case 0x41: - // This is a GB/C only bug (ie. not GBA/SP). - if ((gbHardware & 7) && (gbLcdMode == 2) && (gbLcdModeDelayed == 1) && (!gbSpeed)) - return (0x80 | gbMemory[0xff41] & 0xFC); - else - return (0x80 | gbMemory[0xff41]); - case 0x42: - return register_SCY; - case 0x43: - return register_SCX; - case 0x44: - if (((gbHardware & 7) && ((gbLcdMode == 1) && (gbLcdTicks == 0x71))) || - (!(register_LCDC && 0x80))) - return (0); - else - return register_LY; - case 0x45: - return register_LYC; - case 0x46: - return register_DMA; - case 0x4a: - return register_WY; - case 0x4b: - return register_WX; - case 0x4f: - return (0xfe | register_VBK); - case 0x51: - return register_HDMA1; - case 0x52: - return register_HDMA2; - case 0x53: - return register_HDMA3; - case 0x54: - return register_HDMA4; - case 0x55: - return register_HDMA5; - case 0x68: - case 0x6a: - if (gbCgbMode) - return (0x40 | gbMemory[address]); - else - return 0xc0; - case 0x69: - case 0x6b: - if (gbCgbMode) - { - // No access to gbPalette during mode 3 (Color Panel Demo) - if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || - (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || - ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || - ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) - return (gbMemory[address]); - else - return 0xff; - } - else - return 0xff; - case 0x70: - if (gbCgbMode) - return (0xf8 | register_SVBK); - else - return 0xff; - case 0xff: - return register_IE; - } - } - // OAM not accessible during mode 2 & 3. - if(((address >= 0xfe00) && (address<0xfea0)) && - (((gbLcdMode | gbLcdModeDelayed) &2) && - (!(gbSpeed && (gbHardware & 0x2) && !(gbLcdModeDelayed & 2) && (gbLcdMode == 2))) || - (gbSpeed && (gbHardware & 0x2) && (gbLcdModeDelayed == 0) && (gbLcdTicksDelayed == (GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]))))) - return 0xff; - - if ((address >= 0xfea0) && (address < 0xff00)) - { - if (gbHardware & 1) - return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0x00 : 0xff ); - else if (gbHardware & 2) - return gbMemoryMap[address>>12][address & 0x0fff]; - else if (gbHardware & 4) - return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0xff : 0x00 ); - else if (gbHardware & 8) - return ((address & 0xf0) |((address & 0xf0)>>4)); - } - - return gbMemoryMap[address>>12][address & 0x0fff]; -} - -void gbVblank_interrupt() -{ - gbCheatWrite(false); // Emulates GS codes. - gbMemory[0xff0f] = register_IF &= 0xfe; - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = 0x40; -} - -void gbLcd_interrupt() -{ - gbMemory[0xff0f] = register_IF &= 0xfd; - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = 0x48; -} - -void gbTimer_interrupt() -{ - gbMemory[0xff0f] = register_IF &= 0xfb; - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = 0x50; -} - -void gbSerial_interrupt() -{ - gbMemory[0xff0f] = register_IF &= 0xf7; - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = 0x58; -} - -void gbJoypad_interrupt() -{ - gbMemory[0xff0f] = register_IF &= 0xef; - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = 0x60; -} - -void gbSpeedSwitch() -{ - gbBlackScreen = true; - if(gbSpeed == 0) { - gbSpeed = 1; - GBLCD_MODE_0_CLOCK_TICKS = 51 * 2; - GBLCD_MODE_1_CLOCK_TICKS = 1140 * 2; - GBLCD_MODE_2_CLOCK_TICKS = 20 * 2; - GBLCD_MODE_3_CLOCK_TICKS = 43 * 2; - GBLY_INCREMENT_CLOCK_TICKS = 114 * 2; - GBDIV_CLOCK_TICKS = 64; - GBTIMER_MODE_0_CLOCK_TICKS = 256; - GBTIMER_MODE_1_CLOCK_TICKS = 4; - GBTIMER_MODE_2_CLOCK_TICKS = 16; - GBTIMER_MODE_3_CLOCK_TICKS = 64; - GBSERIAL_CLOCK_TICKS = 128 * 2; - gbLcdTicks *= 2; - gbLcdTicksDelayed *=2; - gbLcdTicksDelayed--; - gbLcdLYIncrementTicks *= 2; - gbLcdLYIncrementTicksDelayed *= 2; - gbLcdLYIncrementTicksDelayed--; - gbSerialTicks *= 2; - //SOUND_CLOCK_TICKS = soundQuality * 24 * 2; - //soundTicks *= 2; - gbLine99Ticks = 3; - } else { - gbSpeed = 0; - GBLCD_MODE_0_CLOCK_TICKS = 51; - GBLCD_MODE_1_CLOCK_TICKS = 1140; - GBLCD_MODE_2_CLOCK_TICKS = 20; - GBLCD_MODE_3_CLOCK_TICKS = 43; - GBLY_INCREMENT_CLOCK_TICKS = 114; - GBDIV_CLOCK_TICKS = 64; - GBTIMER_MODE_0_CLOCK_TICKS = 256; - GBTIMER_MODE_1_CLOCK_TICKS = 4; - GBTIMER_MODE_2_CLOCK_TICKS = 16; - GBTIMER_MODE_3_CLOCK_TICKS = 64; - GBSERIAL_CLOCK_TICKS = 128; - gbLcdTicks >>= 1; - gbLcdTicksDelayed++; - gbLcdTicksDelayed >>=1; - gbLcdLYIncrementTicks >>= 1; - gbLcdLYIncrementTicksDelayed++; - gbLcdLYIncrementTicksDelayed >>= 1; - gbSerialTicks /= 2; - //SOUND_CLOCK_TICKS = soundQuality * 24; - //soundTicks /= 2; - gbLine99Ticks = 1; - if (gbHardware & 8) - gbLine99Ticks++; - } - gbDmaTicks += (134)*GBLY_INCREMENT_CLOCK_TICKS + (37<<(gbSpeed ? 1 : 0)); -} - -bool CPUIsGBBios(const char * file) -{ - if(strlen(file) > 4) { - const char * p = strrchr(file,'.'); - - if(p != NULL) { - if(_stricmp(p, ".gb") == 0) - return true; - if(_stricmp(p, ".bin") == 0) - return true; - if(_stricmp(p, ".bios") == 0) - return true; - if(_stricmp(p, ".rom") == 0) - return true; - } - } - - return false; -} - -void gbCPUInit(const char *biosFileName, bool useBiosFile) -{ - useBios = false; - if (useBiosFile) - { - int size = 0x100; - if(utilLoad(biosFileName, - CPUIsGBBios, - bios, - size)) { - if(size == 0x100) - useBios = true; - else - systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file size")); - } - } -} - -void gbGetHardwareType() -{ - gbCgbMode = 0; - gbSgbMode = 0; - if(gbRom[0x143] & 0x80) { - if((gbEmulatorType == 0) || - gbEmulatorType == 1 || - gbEmulatorType == 4) { - gbCgbMode = 1; - } - } - - if((gbCgbMode == 0 ) && (gbRom[0x146] == 0x03)) { - if(gbEmulatorType == 0 || - gbEmulatorType == 2 || - gbEmulatorType == 5) - gbSgbMode = 1; - } - - gbHardware = 1; // GB - if (((gbCgbMode == 1) && (gbEmulatorType == 0)) || (gbEmulatorType == 1)) - gbHardware = 2; // GBC - else if (((gbSgbMode == 1) && (gbEmulatorType == 0)) || (gbEmulatorType == 2) || (gbEmulatorType == 5)) - gbHardware = 4; // SGB(2) - else if (gbEmulatorType == 4) - gbHardware = 8; // GBA - - gbGBCColorType = 0; - if (gbHardware & 8) // If GBA is selected, choose the GBA default settings. - gbGBCColorType = 2; // (0 = GBC, 1 = GBA, 2 = GBASP) -} - -void gbReset() -{ - gbGetHardwareType(); - - oldRegister_WY = 146; - gbInterruptLaunched = 0; - - if(gbCgbMode == 1) { - if (gbVram == NULL) - gbVram = (u8 *)malloc(0x4000); - if (gbWram == NULL) - gbWram = (u8 *)malloc(0x8000); - memset(gbVram,0,0x4000); - memset(gbPalette,0, 2*128); - } - else - { - if(gbVram != NULL) { - free(gbVram); - gbVram = NULL; - } - if(gbWram != NULL) { - free(gbWram); - gbWram = NULL; - } - } - - gbLYChangeHappened = false; - gbLCDChangeHappened = false; - gbBlackScreen = false; - gbInterruptWait = 0; - gbDmaTicks = 0; - clockTicks = 0; - - if(gbSpeed) { - gbSpeedSwitch(); - gbMemory[0xff4d] = 0; - } - - // clean Wram - // This kinda emulates the startup state of Wram on GB/C (not very accurate, - // but way closer to the reality than filling it with 00es or FFes). - // On GBA/GBASP, it's kinda filled with random data. - // In all cases, most of the 2nd bank is filled with 00s. - // The starting data are important for some 'buggy' games, like Buster Brothers or - // Karamuchou ha Oosawagi!. - if (gbMemory != NULL) - { - memset(gbMemory,0xff, 65536); - for (int temp = 0xC000; temp < 0xE000; temp++) - if ((temp & 0x8) ^((temp & 0x800)>>8)) - { - if ((gbHardware & 0x02) && (gbGBCColorType == 0)) - gbMemory[temp] = 0x0; - else - gbMemory[temp] = 0x0f; - } - - else - gbMemory[temp] = 0xff; - } - - - - // clean LineBuffer - if (gbLineBuffer != NULL) - memset(gbLineBuffer, 0, sizeof(gbLineBuffer)); - // clean Pix - if (pix != NULL) - memset(pix, 0, sizeof(pix)); - // clean Vram - if (gbVram != NULL) - memset(gbVram, 0, 0x4000); - // clean Wram 2 - // This kinda emulates the startup state of Wram on GBC (not very accurate, - // but way closer to the reality than filling it with 00es or FFes). - // On GBA/GBASP, it's kinda filled with random data. - // In all cases, most of the 2nd bank is filled with 00s. - // The starting data are important for some 'buggy' games, like Buster Brothers or - // Karamuchou ha Oosawagi! - if (gbWram != NULL) - { - for (int i = 0; i<8; i++) - if (i != 2) - memcpy ((u16 *)(gbWram+i*0x1000), (u16 *)(gbMemory+0xC000), 0x1000); - } - - memset(gbSCYLine,0,sizeof(gbSCYLine)); - memset(gbSCXLine,0,sizeof(gbSCXLine)); - memset(gbBgpLine,0xfc,sizeof(gbBgpLine)); - if (gbHardware & 5) - { - memset(gbObp0Line,0xff,sizeof(gbObp0Line)); - memset(gbObp1Line,0xff,sizeof(gbObp1Line)); - } - else - { - memset(gbObp0Line,0x0,sizeof(gbObp0Line)); - memset(gbObp1Line,0x0,sizeof(gbObp1Line)); - } - memset(gbSpritesTicks,0x0,sizeof(gbSpritesTicks)); - - SP.W = 0xfffe; - AF.W = 0x01b0; - BC.W = 0x0013; - DE.W = 0x00d8; - HL.W = 0x014d; - PC.W = 0x0100; - IFF = 0; - gbInt48Signal = 0; - - register_TIMA = 0; - register_TMA = 0; - register_TAC = 0; - gbMemory[0xff0f] = register_IF = 1; - gbMemory[0xff40] = register_LCDC = 0x91; - gbMemory[0xff47] = 0xfc; - - if (gbCgbMode) - gbMemory[0xff4d] = 0x7e; - else - gbMemory[0xff4d] = 0xff; - - if (!gbCgbMode) - gbMemory[0xff70] = gbMemory[0xff74] = 0xff; - - if (gbCgbMode) - gbMemory[0xff56] = 0x3e; - else - gbMemory[0xff56] = 0xff; - - register_SCY = 0; - register_SCX = 0; - register_LYC = 0; - register_DMA = 0xff; - register_WY = 0; - register_WX = 0; - register_VBK = 0; - register_HDMA1 = 0xff; - register_HDMA2 = 0xff; - register_HDMA3 = 0xff; - register_HDMA4 = 0xff; - register_HDMA5 = 0xff; - register_SVBK = 0; - register_IE = 0; - - if (gbCgbMode) - gbMemory[0xff02] = 0x7c; - else - gbMemory[0xff02] = 0x7e; - - gbMemory[0xff03] = 0xff; - int i; - for (i = 0x8; i<0xf; i++) - gbMemory[0xff00+i] = 0xff; - - gbMemory[0xff13] = 0xff; - gbMemory[0xff15] = 0xff; - gbMemory[0xff18] = 0xff; - gbMemory[0xff1d] = 0xff; - gbMemory[0xff1f] = 0xff; - - for (i = 0x27; i<0x30; i++) - gbMemory[0xff00+i] = 0xff; - - gbMemory[0xff4c] = 0xff; - gbMemory[0xff4e] = 0xff; - gbMemory[0xff50] = 0xff; - - for (i = 0x57; i<0x68; i++) - gbMemory[0xff00+i] = 0xff; - - for (i = 0x5d; i<0x70; i++) - gbMemory[0xff00+i] = 0xff; - - gbMemory[0xff71] = 0xff; - - for (i = 0x78; i<0x80; i++) - gbMemory[0xff00+i] = 0xff; - - if (gbHardware & 0xa) - { - - if (gbHardware & 2) - { - AF.W = 0x1180; - BC.W = 0x0000; - } - else - { - AF.W = 0x1100; - BC.W = 0x0100; // GBA/SP have B = 0x01 (which means GBC & GBA/SP bootrom are different !) - } - - gbMemory[0xff26] = 0xf1; - if (gbCgbMode) - { - - gbMemory[0xff31] = 0xff; - gbMemory[0xff33] = 0xff; - gbMemory[0xff35] = 0xff; - gbMemory[0xff37] = 0xff; - gbMemory[0xff39] = 0xff; - gbMemory[0xff3b] = 0xff; - gbMemory[0xff3d] = 0xff; - - gbMemory[0xff44] = register_LY = 0x90; - gbDivTicks = 0x19 + ((gbHardware & 2) >> 1); - gbInternalTimer = 0x58 + ((gbHardware & 2) >> 1); - gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS - - (register_LY-0x8F)*GBLY_INCREMENT_CLOCK_TICKS + 72 + ((gbHardware & 2) >> 1); - gbLcdLYIncrementTicks = 72 + ((gbHardware & 2) >> 1); - gbMemory[0xff04] = register_DIV = 0x1E; - } - else - { - gbMemory[0xff44] = register_LY = 0x94; - gbDivTicks = 0x22 + ((gbHardware & 2) >> 1); - gbInternalTimer = 0x61 + ((gbHardware & 2) >> 1); - gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS - - (register_LY-0x8F)*GBLY_INCREMENT_CLOCK_TICKS + 25 + ((gbHardware & 2) >> 1); - gbLcdLYIncrementTicks = 25 + ((gbHardware & 2) >> 1); - gbMemory[0xff04] = register_DIV = 0x26; - } - - - DE.W = 0xff56; - HL.W = 0x000d; - - register_HDMA5 = 0xff; - gbMemory[0xff68] = 0xc0; - gbMemory[0xff6a] = 0xc0; - - - gbMemory[0xff41] = register_STAT = 0x81; - gbLcdMode = 1; - } - else - { - if (gbHardware & 4) - { - if(gbEmulatorType == 5) - AF.W = 0xffb0; - else - AF.W = 0x01b0; - BC.W = 0x0013; - DE.W = 0x00d8; - HL.W = 0x014d; - } - gbDivTicks = 14; - gbInternalTimer = gbDivTicks--; - gbMemory[0xff04] = register_DIV = 0xAB; - gbMemory[0xff41] = register_STAT = 0x85; - gbMemory[0xff44] = register_LY = 0x00; - gbLcdTicks = 15; - gbLcdLYIncrementTicks = 114+gbLcdTicks; - gbLcdMode = 1; - - // used for the handling of the gb Boot Rom - if ((gbHardware & 5) && (bios != NULL) && useBios && !skipBios) - { - memcpy ((u8 *)(gbMemory), (u8 *)(gbRom), 0x1000); - memcpy ((u8 *)(gbMemory), (u8 *)(bios), 0x100); - gbWhiteScreen = 0; - - gbInternalTimer = 0x3e; - gbDivTicks = 0x3f; - gbMemory[0xff04] = register_DIV = 0x00; - PC.W = 0x0000; - register_LCDC = 0x11; - gbScreenOn = false; - gbLcdTicks = 0; - gbLcdMode = 0; - gbLcdModeDelayed = 0; - gbMemory[0xff41] = register_STAT &= 0xfc; - gbInt48Signal = 0; - gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS; - } - } - - gbLine99Ticks = 1; - if (gbHardware & 8) - gbLine99Ticks++; - - gbLcdModeDelayed = gbLcdMode; - gbLcdTicksDelayed = gbLcdTicks+1; - gbLcdLYIncrementTicksDelayed = gbLcdLYIncrementTicks+1; - - - gbTimerModeChange = false; - gbTimerOnChange = false; - gbTimerOn = false; - - if(gbCgbMode) { - for (int i = 0; i<0x20; i++) - gbPalette[i] = 0x7fff; - - // This is just to show that the starting values of the OBJ palettes are different - // between the 3 consoles, and that they 'kinda' stay the same at each reset - // (they can slightly change, somehow (randomly?)). - // You can check the effects of gbGBCColorType on the "Vila Caldan Color" gbc demo. - // Note that you could also check the Div register to check on which system the game - // is running (GB,GBC and GBA(SP) have different startup values). - // Unfortunatly, I don't have any SGB system, so I can't get their starting values. - - if (gbGBCColorType == 0) // GBC Hardware - { - gbPalette[0x20] = 0x0600; - gbPalette[0x21] = 0xfdf3; - gbPalette[0x22] = 0x041c; - gbPalette[0x23] = 0xf5db; - gbPalette[0x24] = 0x4419; - gbPalette[0x25] = 0x57ea; - gbPalette[0x26] = 0x2808; - gbPalette[0x27] = 0x9b75; - gbPalette[0x28] = 0x129b; - gbPalette[0x29] = 0xfce0; - gbPalette[0x2a] = 0x22da; - gbPalette[0x2b] = 0x4ac5; - gbPalette[0x2c] = 0x2d71; - gbPalette[0x2d] = 0xf0c2; - gbPalette[0x2e] = 0x5137; - gbPalette[0x2f] = 0x2d41; - gbPalette[0x30] = 0x6b2d; - gbPalette[0x31] = 0x2215; - gbPalette[0x32] = 0xbe0a; - gbPalette[0x33] = 0xc053; - gbPalette[0x34] = 0xfe5f; - gbPalette[0x35] = 0xe000; - gbPalette[0x36] = 0xbe10; - gbPalette[0x37] = 0x914d; - gbPalette[0x38] = 0x7f91; - gbPalette[0x39] = 0x02b5; - gbPalette[0x3a] = 0x77ac; - gbPalette[0x3b] = 0x14e5; - gbPalette[0x3c] = 0xcf89; - gbPalette[0x3d] = 0xa03d; - gbPalette[0x3e] = 0xfd50; - gbPalette[0x3f] = 0x91ff; - } - else if (gbGBCColorType == 1) // GBA Hardware - { - gbPalette[0x20] = 0xbe00; - gbPalette[0x21] = 0xfdfd; - gbPalette[0x22] = 0xbd69; - gbPalette[0x23] = 0x7baf; - gbPalette[0x24] = 0xf5ff; - gbPalette[0x25] = 0x3f8f; - gbPalette[0x26] = 0xcee5; - gbPalette[0x27] = 0x5bf7; - gbPalette[0x28] = 0xb35b; - gbPalette[0x29] = 0xef97; - gbPalette[0x2a] = 0xef9f; - gbPalette[0x2b] = 0x97f7; - gbPalette[0x2c] = 0x82bf; - gbPalette[0x2d] = 0x9f3d; - gbPalette[0x2e] = 0xddde; - gbPalette[0x2f] = 0xbad5; - gbPalette[0x30] = 0x3cba; - gbPalette[0x31] = 0xdfd7; - gbPalette[0x32] = 0xedea; - gbPalette[0x33] = 0xfeda; - gbPalette[0x34] = 0xf7f9; - gbPalette[0x35] = 0xfdee; - gbPalette[0x36] = 0x6d2f; - gbPalette[0x37] = 0xf0e6; - gbPalette[0x38] = 0xf7f0; - gbPalette[0x39] = 0xf296; - gbPalette[0x3a] = 0x3bf1; - gbPalette[0x3b] = 0xe211; - gbPalette[0x3c] = 0x69ba; - gbPalette[0x3d] = 0x3d0d; - gbPalette[0x3e] = 0xdfd3; - gbPalette[0x3f] = 0xa6ba; - } - else if (gbGBCColorType == 2) // GBASP Hardware - { - gbPalette[0x20] = 0x9c00; - gbPalette[0x21] = 0x6340; - gbPalette[0x22] = 0x10c6; - gbPalette[0x23] = 0xdb97; - gbPalette[0x24] = 0x7622; - gbPalette[0x25] = 0x3e57; - gbPalette[0x26] = 0x2e12; - gbPalette[0x27] = 0x95c3; - gbPalette[0x28] = 0x1095; - gbPalette[0x29] = 0x488c; - gbPalette[0x2a] = 0x8241; - gbPalette[0x2b] = 0xde8c; - gbPalette[0x2c] = 0xfabc; - gbPalette[0x2d] = 0x0e81; - gbPalette[0x2e] = 0x7675; - gbPalette[0x2f] = 0xfdec; - gbPalette[0x30] = 0xddfd; - gbPalette[0x31] = 0x5995; - gbPalette[0x32] = 0x066a; - gbPalette[0x33] = 0xed1e; - gbPalette[0x34] = 0x1e84; - gbPalette[0x35] = 0x1d14; - gbPalette[0x36] = 0x11c3; - gbPalette[0x37] = 0x2749; - gbPalette[0x38] = 0xa727; - gbPalette[0x39] = 0x6266; - gbPalette[0x3a] = 0xe27b; - gbPalette[0x3b] = 0xe3fc; - gbPalette[0x3c] = 0x1f76; - gbPalette[0x3d] = 0xf158; - gbPalette[0x3e] = 0x468e; - gbPalette[0x3f] = 0xa540; - } - } else { - if(gbSgbMode) { - for(int i = 0; i < 8; i++) - gbPalette[i] = systemGbPalette[gbPaletteOption*8+i]; - - } - for(int i = 0; i < 8; i++) - gbPalette[i] = systemGbPalette[gbPaletteOption*8+i]; - } - - GBTIMER_MODE_0_CLOCK_TICKS = 256; - GBTIMER_MODE_1_CLOCK_TICKS = 4; - GBTIMER_MODE_2_CLOCK_TICKS = 16; - GBTIMER_MODE_3_CLOCK_TICKS = 64; - - GBLY_INCREMENT_CLOCK_TICKS = 114; - gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS; - gbTimerClockTicks = GBTIMER_MODE_0_CLOCK_TICKS; - gbSerialTicks = 0; - gbSerialBits = 0; - gbSerialOn = 0; - gbWindowLine = -1; - gbTimerOn = false; - gbTimerMode = 0; - gbSpeed = 0; - gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; - - if(gbCgbMode) { - gbSpeed = 0; - gbHdmaOn = 0; - gbHdmaSource = 0x99d0; - gbHdmaDestination = 0x99d0; - gbVramBank = 0; - gbWramBank = 1; - - } - - // used to clean the borders - if (gbSgbMode) - { - gbSgbResetFlag = true; - gbSgbReset(); - if (gbBorderOn) - gbSgbRenderBorder(); - gbSgbResetFlag = false; - } - - for(i = 0; i < 4; i++) - gbBgp[i] = gbObp0[i] = gbObp1[i] = i; - - memset(&gbDataMBC1,0, sizeof(gbDataMBC1)); - gbDataMBC1.mapperROMBank = 1; - - gbDataMBC2.mapperRAMEnable = 0; - gbDataMBC2.mapperROMBank = 1; - - memset(&gbDataMBC3,0, 6 * sizeof(int)); - gbDataMBC3.mapperROMBank = 1; - - memset(&gbDataMBC5, 0, sizeof(gbDataMBC5)); - gbDataMBC5.mapperROMBank = 1; - - memset(&gbDataHuC1, 0, sizeof(gbDataHuC1)); - gbDataHuC1.mapperROMBank = 1; - - memset(&gbDataHuC3, 0, sizeof(gbDataHuC3)); - gbDataHuC3.mapperROMBank = 1; - - memset(&gbDataTAMA5,0, 26*sizeof(int)); - gbDataTAMA5.mapperROMBank = 1; - - memset(&gbDataMMM01,0, sizeof(gbDataMMM01)); - gbDataMMM01.mapperROMBank = 1; - - if (useBios && !skipBios && (gbHardware & 5)) - { - gbMemoryMap[0x00] = &gbMemory[0x0000]; - inBios = true; - } - else - { - gbMemoryMap[0x00] = &gbRom[0x0000]; - inBios = false; - } - - gbMemoryMap[0x01] = &gbRom[0x1000]; - gbMemoryMap[0x02] = &gbRom[0x2000]; - gbMemoryMap[0x03] = &gbRom[0x3000]; - gbMemoryMap[0x04] = &gbRom[0x4000]; - gbMemoryMap[0x05] = &gbRom[0x5000]; - gbMemoryMap[0x06] = &gbRom[0x6000]; - gbMemoryMap[0x07] = &gbRom[0x7000]; - if(gbCgbMode) { - gbMemoryMap[0x08] = &gbVram[0x0000]; - gbMemoryMap[0x09] = &gbVram[0x1000]; - gbMemoryMap[0x0a] = &gbMemory[0xa000]; - gbMemoryMap[0x0b] = &gbMemory[0xb000]; - gbMemoryMap[0x0c] = &gbMemory[0xc000]; - gbMemoryMap[0x0d] = &gbWram[0x1000]; - gbMemoryMap[0x0e] = &gbMemory[0xe000]; - gbMemoryMap[0x0f] = &gbMemory[0xf000]; - } else { - gbMemoryMap[0x08] = &gbMemory[0x8000]; - gbMemoryMap[0x09] = &gbMemory[0x9000]; - gbMemoryMap[0x0a] = &gbMemory[0xa000]; - gbMemoryMap[0x0b] = &gbMemory[0xb000]; - gbMemoryMap[0x0c] = &gbMemory[0xc000]; - gbMemoryMap[0x0d] = &gbMemory[0xd000]; - gbMemoryMap[0x0e] = &gbMemory[0xe000]; - gbMemoryMap[0x0f] = &gbMemory[0xf000]; - } - - if(gbRam) { - gbMemoryMap[0x0a] = &gbRam[0x0000]; - gbMemoryMap[0x0b] = &gbRam[0x1000]; - } - - gbSoundReset(); - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - gbLastTime = systemGetClock(); - gbFrameCount = 0; - - gbScreenOn = true; - gbSystemMessage = false; - - gbCheatWrite(true); // Emulates GS codes. - -} - -void gbWriteSaveMBC1(const char * name) -{ - if (gbRam) - { - FILE *gzFile = fopen(name,"wb"); - - if(gzFile == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(gbRam, - 1, - (gbRamSizeMask+1), - gzFile); - - fclose(gzFile); - } -} - -void gbWriteSaveMBC2(const char * name) -{ - if (gbRam) - { - FILE *file = fopen(name, "wb"); - - if(file == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(&gbMemory[0xa000], - 1, - 256, - file); - - fclose(file); - } -} - -void gbWriteSaveMBC3(const char * name, bool extendedSave) -{ - if (gbRam || extendedSave) - { - FILE *gzFile = fopen(name,"wb"); - if (gbRam) - { - - if(gzFile == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(gbRam, - 1, - (gbRamSizeMask+1), - gzFile); - } - - if(extendedSave) - fwrite(&gbDataMBC3.mapperSeconds, - 1, - 10*sizeof(int) + sizeof(time_t), - gzFile); - - fclose(gzFile); - } -} - -void gbWriteSaveMBC5(const char * name) -{ - if (gbRam) - { - FILE *gzFile = fopen(name,"wb"); - - if(gzFile == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(gbRam, - 1, - (gbRamSizeMask+1), - gzFile); - - fclose(gzFile); - } -} - -void gbWriteSaveMBC7(const char * name) -{ - if (gbRam) - { - FILE *file = fopen(name, "wb"); - - if(file == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(&gbMemory[0xa000], - 1, - 256, - file); - - fclose(file); - } -} - -void gbWriteSaveTAMA5(const char * name, bool extendedSave) -{ - FILE *gzFile = fopen(name,"wb"); - - if(gzFile == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - if (gbRam) - fwrite(gbRam, - 1, - (gbRamSizeMask+1), - gzFile); - - fwrite(gbTAMA5ram, - 1, - (gbTAMA5ramSize), - gzFile); - - if(extendedSave) - fwrite(&gbDataTAMA5.mapperSeconds, - 1, - 14*sizeof(int) + sizeof(time_t), - gzFile); - - fclose(gzFile); -} - -void gbWriteSaveMMM01(const char * name) -{ - if (gbRam) - { - FILE *gzFile = fopen(name,"wb"); - - if(gzFile == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(gbRam, - 1, - (gbRamSizeMask+1), - gzFile); - - fclose(gzFile); - } -} - - -bool gbReadSaveMBC1(const char * name) -{ - if (gbRam) - { - gzFile gzFile = gzopen(name, "rb"); - - if(gzFile == NULL) { - return false; - } - - int read = gzread(gzFile, - gbRam, - (gbRamSizeMask+1)); - - if(read != (gbRamSizeMask+1)) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gzclose(gzFile); - gbBatteryError = true; - return false; - } - - // Also checks if the battery file it bigger than gbRamSizeMask+1 ! - u8 data[1]; - data[0] = 0; - - read = gzread(gzFile, - data, - 1); - if(read >0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gzclose(gzFile); - gbBatteryError = true; - return false; - } - - gzclose(gzFile); - return true; - } - else - return false; -} - - -bool gbReadSaveMBC2(const char * name) -{ - if (gbRam) - { - FILE *file = fopen(name, "rb"); - - if(file == NULL) { - return false; - } - - size_t read = fread(&gbMemory[0xa000], - 1, - 256, - file); - - if(read != 256) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - fclose(file); - gbBatteryError = true; - return false; - } - - // Also checks if the battery file it bigger than gbRamSizeMask+1 ! - u8 data[1]; - data[0] = 0; - - read = fread(&data[0], - 1, - 1, - file); - if(read > 0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - fclose(file); - gbBatteryError = true; - return false; - } - - fclose(file); - return true; - } - else - return false; -} - -bool gbReadSaveMBC3(const char * name) -{ - gzFile gzFile = gzopen(name, "rb"); - - if(gzFile == NULL) { - return false; - } - - int read = 0; - - if (gbRam) - read = gzread(gzFile, - gbRam, - (gbRamSizeMask+1)); - else - read = (gbRamSizeMask+1); - - - bool res = true; - - if(read != (gbRamSizeMask+1)) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gbBatteryError = true; - res = false; - } else if ((gbRomType == 0xf) || (gbRomType == 0x10)){ - read = gzread(gzFile, - &gbDataMBC3.mapperSeconds, - sizeof(int)*10 + sizeof(time_t)); - - if(read != (sizeof(int)*10 + sizeof(time_t)) && read != 0) { - systemMessage(MSG_FAILED_TO_READ_RTC,N_("Failed to read RTC from save game %s (continuing)"), - name); - res = false; - } - else if (read == 0) - { - systemMessage(MSG_FAILED_TO_READ_RTC,N_("Failed to read RTC from save game %s (continuing)"), - name); - res = false; - } - else - { - // Also checks if the battery file it bigger than gbRamSizeMask+1+RTC ! - u8 data[1]; - data[0] = 0; - - read = gzread(gzFile, - data, - 1); - if(read >0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gbBatteryError = true; - res = false; - } - } - } - - gzclose(gzFile); - return res; -} - -bool gbReadSaveMBC5(const char * name) -{ - if (gbRam) - { - gzFile gzFile = gzopen(name, "rb"); - - if(gzFile == NULL) { - return false; - } - - int read = gzread(gzFile, - gbRam, - (gbRamSizeMask+1)); - - if(read != (gbRamSizeMask+1)) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gzclose(gzFile); - gbBatteryError = true; - return false; - } - - - // Also checks if the battery file it bigger than gbRamSizeMask+1 ! - u8 data[1]; - data[0] = 0; - - read = gzread(gzFile, - data, - 1); - if(read >0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gzclose(gzFile); - gbBatteryError = true; - return false; - } - - gzclose(gzFile); - return true; - } - else - return false; -} - -bool gbReadSaveMBC7(const char * name) -{ - if (gbRam) - { - FILE *file = fopen(name, "rb"); - - if(file == NULL) { - return false; - } - - size_t read = fread(&gbMemory[0xa000], - 1, - 256, - file); - - if(read != 256) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - fclose(file); - gbBatteryError = true; - return false; - } - - // Also checks if the battery file it bigger than gbRamSizeMask+1 ! - u8 data[1]; - data[0] = 0; - - read = fread(&data[0], - 1, - 1, - file); - if(read > 0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - fclose(file); - gbBatteryError = true; - return false; - } - - fclose(file); - return true; - } - else - return false; -} - -bool gbReadSaveTAMA5(const char * name) -{ - gzFile gzFile = gzopen(name, "rb"); - - if(gzFile == NULL) { - return false; - } - - int read = 0; - - if (gbRam) - read = gzread(gzFile, - gbRam, - (gbRamSizeMask+1)); - else - read = gbRamSizeMask; - - read += gzread(gzFile, - gbTAMA5ram, - gbTAMA5ramSize); - - bool res = true; - - if(read != (gbRamSizeMask+gbTAMA5ramSize+1)) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gbBatteryError = true; - res = false; - } else { - read = gzread(gzFile, - &gbDataTAMA5.mapperSeconds, - sizeof(int)*14 + sizeof(time_t)); - - if(read != (sizeof(int)*14 + sizeof(time_t)) && read != 0) { - systemMessage(MSG_FAILED_TO_READ_RTC,N_("Failed to read RTC from save game %s (continuing)"), - name); - res = false; - } - else if (read == 0) - { - systemMessage(MSG_FAILED_TO_READ_RTC,N_("Failed to read RTC from save game %s (continuing)"), - name); - res = false; - } - else - { - // Also checks if the battery file it bigger than gbRamSizeMask+1+RTC ! - u8 data[1]; - data[0] = 0; - - read = gzread(gzFile, - data, - 1); - if(read >0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gbBatteryError = true; - res = false; - } - } - } - - gzclose(gzFile); - return res; -} - - -bool gbReadSaveMMM01(const char * name) -{ - if (gbRam) - { - gzFile gzFile = gzopen(name, "rb"); - - if(gzFile == NULL) { - return false; - } - - int read = gzread(gzFile, - gbRam, - (gbRamSizeMask+1)); - - if(read != (gbRamSizeMask+1)) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gzclose(gzFile); - gbBatteryError = true; - return false; - } - - // Also checks if the battery file it bigger than gbRamSizeMask+1 ! - u8 data[1]; - data[0] = 0; - - read = gzread(gzFile, - data, - 1); - if(read >0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gzclose(gzFile); - gbBatteryError = true; - return false; - } - - gzclose(gzFile); - return true; - } - else - return false; -} - -void gbInit() -{ - gbGenFilter(); - gbSgbInit(); - - gbMemory = (u8 *)malloc(65536); - - pix = (u8 *)calloc(1,4*257*226); - - gbLineBuffer = (u16 *)malloc(160 * sizeof(u16)); -} - -bool gbWriteBatteryFile(const char *file, bool extendedSave) -{ - if(gbBattery) { - switch(gbRomType) { - case 0x03: - gbWriteSaveMBC1(file); - break; - case 0x06: - gbWriteSaveMBC2(file); - break; - case 0x0d: - gbWriteSaveMMM01(file); - break; - case 0x0f: - case 0x10: - gbWriteSaveMBC3(file, extendedSave); - break; - case 0x13: - case 0xfc: - gbWriteSaveMBC3(file, false); - case 0x1b: - case 0x1e: - gbWriteSaveMBC5(file); - break; - case 0x22: - gbWriteSaveMBC7(file); - break; - case 0xfd: - gbWriteSaveTAMA5(file, extendedSave); - break; - case 0xff: - gbWriteSaveMBC1(file); - break; - } - } - return true; -} - -bool gbWriteBatteryFile(const char *file) -{ - if (!gbBatteryError) - { - gbWriteBatteryFile(file, true); - return true; - } - else return false; -} - -bool gbReadBatteryFile(const char *file) -{ - bool res = false; - if(gbBattery) { - switch(gbRomType) { - case 0x03: - res = gbReadSaveMBC1(file); - break; - case 0x06: - res = gbReadSaveMBC2(file); - break; - case 0x0d: - res = gbReadSaveMMM01(file); - break; - case 0x0f: - case 0x10: - if(!gbReadSaveMBC3(file)) { - time(&gbDataMBC3.mapperLastTime); - struct tm *lt; - lt = localtime(&gbDataMBC3.mapperLastTime); - gbDataMBC3.mapperSeconds = lt->tm_sec; - gbDataMBC3.mapperMinutes = lt->tm_min; - gbDataMBC3.mapperHours = lt->tm_hour; - gbDataMBC3.mapperDays = lt->tm_yday & 255; - gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) | - (lt->tm_yday > 255 ? 1: 0); - res = false; - break; - } - res = true; - break; - case 0x13: - case 0xfc: - res = gbReadSaveMBC3(file); - case 0x1b: - case 0x1e: - res = gbReadSaveMBC5(file); - break; - case 0x22: - res = gbReadSaveMBC7(file); - case 0xfd: - if(!gbReadSaveTAMA5(file)) { - u8 gbDaysinMonth [12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - time(&gbDataTAMA5.mapperLastTime); - struct tm *lt; - lt = localtime(&gbDataTAMA5.mapperLastTime); - gbDataTAMA5.mapperSeconds = lt->tm_sec; - gbDataTAMA5.mapperMinutes = lt->tm_min; - gbDataTAMA5.mapperHours = lt->tm_hour; - gbDataTAMA5.mapperDays = 1; - gbDataTAMA5.mapperMonths = 1; - gbDataTAMA5.mapperYears = 1970; - int days = lt->tm_yday+365*3; - while (days) - { - gbDataTAMA5.mapperDays++; - days--; - if (gbDataTAMA5.mapperDays>gbDaysinMonth[gbDataTAMA5.mapperMonths-1]) - { - gbDataTAMA5.mapperDays = 1; - gbDataTAMA5.mapperMonths++; - if (gbDataTAMA5.mapperMonths>12) - { - gbDataTAMA5.mapperMonths = 1; - gbDataTAMA5.mapperYears++; - if ((gbDataTAMA5.mapperYears & 3) == 0) - gbDaysinMonth[1] = 29; - else - gbDaysinMonth[1] = 28; - } - } - } - gbDataTAMA5.mapperControl = (gbDataTAMA5.mapperControl & 0xfe) | - (lt->tm_yday > 255 ? 1: 0); - res = false; - break; - } - res = true; - break; - case 0xff: - res = gbReadSaveMBC1(file); - break; - } - } - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - return res; -} - -bool gbReadGSASnapshot(const char *fileName) -{ - FILE *file = fopen(fileName, "rb"); - - if(!file) { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); - return false; - } - - fseek(file, 0x4, SEEK_SET); - char buffer[16]; - char buffer2[16]; - fread(buffer, 1, 15, file); - buffer[15] = 0; - memcpy(buffer2, &gbRom[0x134], 15); - buffer2[15] = 0; - if(memcmp(buffer, buffer2, 15)) { - systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, - N_("Cannot import snapshot for %s. Current game is %s"), - buffer, - buffer2); - fclose(file); - return false; - } - fseek(file, 0x13, SEEK_SET); - size_t read = 0; - int toRead = 0; - switch(gbRomType) { - case 0x03: - case 0x0f: - case 0x10: - case 0x13: - case 0x1b: - case 0x1e: - case 0xff: - read = fread(gbRam, 1, (gbRamSizeMask+1), file); - toRead = (gbRamSizeMask+1); - break; - case 0x06: - case 0x22: - read = fread(&gbMemory[0xa000],1,256,file); - toRead = 256; - break; - default: - systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, - N_("Unsupported snapshot file %s"), - fileName); - fclose(file); - return false; - } - fclose(file); - gbReset(); - return true; -} - -variable_desc gbSaveGameStruct[] = { - { &PC.W, sizeof(u16) }, - { &SP.W, sizeof(u16) }, - { &AF.W, sizeof(u16) }, - { &BC.W, sizeof(u16) }, - { &DE.W, sizeof(u16) }, - { &HL.W, sizeof(u16) }, - { &IFF, sizeof(u8) }, - { &GBLCD_MODE_0_CLOCK_TICKS, sizeof(int) }, - { &GBLCD_MODE_1_CLOCK_TICKS, sizeof(int) }, - { &GBLCD_MODE_2_CLOCK_TICKS, sizeof(int) }, - { &GBLCD_MODE_3_CLOCK_TICKS, sizeof(int) }, - { &GBDIV_CLOCK_TICKS, sizeof(int) }, - { &GBLY_INCREMENT_CLOCK_TICKS, sizeof(int) }, - { &GBTIMER_MODE_0_CLOCK_TICKS, sizeof(int) }, - { &GBTIMER_MODE_1_CLOCK_TICKS, sizeof(int) }, - { &GBTIMER_MODE_2_CLOCK_TICKS, sizeof(int) }, - { &GBTIMER_MODE_3_CLOCK_TICKS, sizeof(int) }, - { &GBSERIAL_CLOCK_TICKS, sizeof(int) }, - { &GBSYNCHRONIZE_CLOCK_TICKS, sizeof(int) }, - { &gbDivTicks, sizeof(int) }, - { &gbLcdMode, sizeof(int) }, - { &gbLcdTicks, sizeof(int) }, - { &gbLcdLYIncrementTicks, sizeof(int) }, - { &gbTimerTicks, sizeof(int) }, - { &gbTimerClockTicks, sizeof(int) }, - { &gbSerialTicks, sizeof(int) }, - { &gbSerialBits, sizeof(int) }, - { &gbInt48Signal, sizeof(int) }, - { &gbInterruptWait, sizeof(int) }, - { &gbSynchronizeTicks, sizeof(int) }, - { &gbTimerOn, sizeof(int) }, - { &gbTimerMode, sizeof(int) }, - { &gbSerialOn, sizeof(int) }, - { &gbWindowLine, sizeof(int) }, - { &gbCgbMode, sizeof(int) }, - { &gbVramBank, sizeof(int) }, - { &gbWramBank, sizeof(int) }, - { &gbHdmaSource, sizeof(int) }, - { &gbHdmaDestination, sizeof(int) }, - { &gbHdmaBytes, sizeof(int) }, - { &gbHdmaOn, sizeof(int) }, - { &gbSpeed, sizeof(int) }, - { &gbSgbMode, sizeof(int) }, - { ®ister_DIV, sizeof(u8) }, - { ®ister_TIMA, sizeof(u8) }, - { ®ister_TMA, sizeof(u8) }, - { ®ister_TAC, sizeof(u8) }, - { ®ister_IF, sizeof(u8) }, - { ®ister_LCDC, sizeof(u8) }, - { ®ister_STAT, sizeof(u8) }, - { ®ister_SCY, sizeof(u8) }, - { ®ister_SCX, sizeof(u8) }, - { ®ister_LY, sizeof(u8) }, - { ®ister_LYC, sizeof(u8) }, - { ®ister_DMA, sizeof(u8) }, - { ®ister_WY, sizeof(u8) }, - { ®ister_WX, sizeof(u8) }, - { ®ister_VBK, sizeof(u8) }, - { ®ister_HDMA1, sizeof(u8) }, - { ®ister_HDMA2, sizeof(u8) }, - { ®ister_HDMA3, sizeof(u8) }, - { ®ister_HDMA4, sizeof(u8) }, - { ®ister_HDMA5, sizeof(u8) }, - { ®ister_SVBK, sizeof(u8) }, - { ®ister_IE , sizeof(u8) }, - { &gbBgp[0], sizeof(u8) }, - { &gbBgp[1], sizeof(u8) }, - { &gbBgp[2], sizeof(u8) }, - { &gbBgp[3], sizeof(u8) }, - { &gbObp0[0], sizeof(u8) }, - { &gbObp0[1], sizeof(u8) }, - { &gbObp0[2], sizeof(u8) }, - { &gbObp0[3], sizeof(u8) }, - { &gbObp1[0], sizeof(u8) }, - { &gbObp1[1], sizeof(u8) }, - { &gbObp1[2], sizeof(u8) }, - { &gbObp1[3], sizeof(u8) }, - { NULL, 0 } -}; - - -static bool gbWriteSaveState(gzFile gzFile) -{ - - utilWriteInt(gzFile, GBSAVE_GAME_VERSION); - - utilGzWrite(gzFile, &gbRom[0x134], 15); - - utilWriteInt(gzFile, useBios); - utilWriteInt(gzFile, inBios); - - utilWriteData(gzFile, gbSaveGameStruct); - - utilGzWrite(gzFile, &IFF, 2); - - if(gbSgbMode) { - gbSgbSaveGame(gzFile); - } - - utilGzWrite(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); - utilGzWrite(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); - utilGzWrite(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); - utilGzWrite(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); - utilGzWrite(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); - utilGzWrite(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); - utilGzWrite(gzFile, &gbDataTAMA5, sizeof(gbDataTAMA5)); - if (gbTAMA5ram != NULL) - utilGzWrite(gzFile, gbTAMA5ram, gbTAMA5ramSize); - utilGzWrite(gzFile, &gbDataMMM01, sizeof(gbDataMMM01)); - - utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16)); - - utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000); - - if(gbRamSize && gbRam) { - utilWriteInt(gzFile, gbRamSize); - utilGzWrite(gzFile, gbRam, gbRamSize); - } - - if(gbCgbMode) { - utilGzWrite(gzFile, gbVram, 0x4000); - utilGzWrite(gzFile, gbWram, 0x8000); - } - - gbSoundSaveGame(gzFile); - - gbCheatsSaveGame(gzFile); - - utilWriteInt(gzFile, gbLcdModeDelayed); - utilWriteInt(gzFile, gbLcdTicksDelayed); - utilWriteInt(gzFile, gbLcdLYIncrementTicksDelayed); - utilWriteInt(gzFile, gbSpritesTicks[299]); - utilWriteInt(gzFile, gbTimerModeChange); - utilWriteInt(gzFile, gbTimerOnChange); - utilWriteInt(gzFile, gbHardware); - utilWriteInt(gzFile, gbBlackScreen); - utilWriteInt(gzFile, oldRegister_WY); - utilWriteInt(gzFile, gbWindowLine); - utilWriteInt(gzFile, inUseRegister_WY); - utilWriteInt(gzFile, gbScreenOn); - return true; -} - -bool gbWriteMemSaveState(char *memory, int available) -{ - gzFile gzFile = utilMemGzOpen(memory, available, "w"); - - if(gzFile == NULL) { - return false; - } - - bool res = gbWriteSaveState(gzFile); - - long pos = utilGzMemTell(gzFile)+8; - - if(pos >= (available)) - res = false; - - utilGzClose(gzFile); - - return res; -} - -bool gbWriteSaveState(const char *name) -{ - gzFile gzFile = utilGzOpen(name,"wb"); - - if(gzFile == NULL) - return false; - - bool res = gbWriteSaveState(gzFile); - - utilGzClose(gzFile); - return res; -} - -static bool gbReadSaveState(gzFile gzFile) -{ - int version = utilReadInt(gzFile); - - if(version > GBSAVE_GAME_VERSION || version < 0) { - systemMessage(MSG_UNSUPPORTED_VB_SGM, - N_("Unsupported VisualBoy save game version %d"), version); - return false; - } - - u8 romname[20]; - - utilGzRead(gzFile, romname, 15); - - if(memcmp(&gbRom[0x134], romname, 15) != 0) { - systemMessage(MSG_CANNOT_LOAD_SGM_FOR, - N_("Cannot load save game for %s. Playing %s"), - romname, &gbRom[0x134]); - return false; - } - - - bool ub = false; - bool ib = false; - - if (version >= 11) - { - ub = utilReadInt(gzFile) ? true : false; - ib = utilReadInt(gzFile) ? true : false; - - if((ub != useBios) && (ib)) { - if(useBios) - systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS, - N_("Save game is not using the BIOS files")); - else - systemMessage(MSG_SAVE_GAME_USING_BIOS, - N_("Save game is using the BIOS file")); - return false; - } - } - - gbReset(); - - inBios = ib; - - utilReadData(gzFile, gbSaveGameStruct); - - - // Correct crash when loading color gameboy save in regular gameboy type. - if (!gbCgbMode) - { - if(gbVram != NULL) { - free(gbVram); - gbVram = NULL; - } - if(gbWram != NULL) { - free(gbWram); - gbWram = NULL; - } - } - else - { - if(gbVram == NULL) - gbVram = (u8 *)malloc(0x4000); - if(gbWram == NULL) - gbWram = (u8 *)malloc(0x8000); - memset(gbVram,0,0x4000); - memset(gbPalette,0, 2*128); - } - - - - if(version >= GBSAVE_GAME_VERSION_7) { - utilGzRead(gzFile, &IFF, 2); - } - - if(gbSgbMode) { - gbSgbReadGame(gzFile, version); - } else { - gbSgbMask = 0; // loading a game at the wrong time causes no display - } - if (version<11) - utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1) - sizeof(int)); - else - utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); - utilGzRead(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); - if(version < GBSAVE_GAME_VERSION_4) - // prior to version 4, there was no adjustment for the time the game - // was last played, so we have less to read. This needs update if the - // structure changes again. - utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)-sizeof(time_t)); - else - utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); - utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); - utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); - utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); - if (version>=11) - { - utilGzRead(gzFile, &gbDataTAMA5, sizeof(gbDataTAMA5)); - if (gbTAMA5ram != NULL) - utilGzRead(gzFile, gbTAMA5ram, gbTAMA5ramSize); - utilGzRead(gzFile, &gbDataMMM01, sizeof(gbDataMMM01)); - } - - if(version < GBSAVE_GAME_VERSION_5) { - utilGzRead(gzFile, pix, 256*224*sizeof(u16)); - } - memset(pix, 0, 257*226*sizeof(u32)); - - if(version < GBSAVE_GAME_VERSION_6) { - utilGzRead(gzFile, gbPalette, 64 * sizeof(u16)); - } else - utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); - - if (version < 11) - utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); - - if(version < GBSAVE_GAME_VERSION_10) { - if(!gbCgbMode && !gbSgbMode) { - for(int i = 0; i < 8; i++) - gbPalette[i] = systemGbPalette[gbPaletteOption*8+i]; - } - } - - utilGzRead(gzFile, &gbMemory[0x8000], 0x8000); - - if(gbRamSize && gbRam) { - if (version < 11) - utilGzRead(gzFile, gbRam, gbRamSize); - else - { - int ramSize = utilReadInt(gzFile); - utilGzRead(gzFile, gbRam, (gbRamSize>ramSize) ? ramSize : gbRamSize); - if (ramSize>gbRamSize) - gzseek(gzFile,ramSize-gbRamSize,SEEK_CUR); - } - } - - memset(gbSCYLine, register_SCY, sizeof(gbSCYLine)); - memset(gbSCXLine, register_SCX, sizeof(gbSCXLine)); - memset(gbBgpLine, (gbBgp[0] | (gbBgp[1]<<2) | (gbBgp[2]<<4) | - (gbBgp[3]<<6)), sizeof(gbBgpLine)); - memset(gbObp0Line, (gbObp0[0] | (gbObp0[1]<<2) | (gbObp0[2]<<4) | - (gbObp0[3]<<6)), sizeof(gbObp0Line)); - memset(gbObp1Line, (gbObp1[0] | (gbObp1[1]<<2) | (gbObp1[2]<<4) | - (gbObp1[3]<<6)), sizeof(gbObp1Line)); - memset(gbSpritesTicks, 0x0, sizeof(gbSpritesTicks)); - - if (inBios) - { - gbMemoryMap[0x00] = &gbMemory[0x0000]; - memcpy ((u8 *)(gbMemory), (u8 *)(gbRom), 0x1000); - memcpy ((u8 *)(gbMemory), (u8 *)(bios), 0x100); - } - else - gbMemoryMap[0x00] = &gbRom[0x0000]; - gbMemoryMap[0x01] = &gbRom[0x1000]; - gbMemoryMap[0x02] = &gbRom[0x2000]; - gbMemoryMap[0x03] = &gbRom[0x3000]; - gbMemoryMap[0x04] = &gbRom[0x4000]; - gbMemoryMap[0x05] = &gbRom[0x5000]; - gbMemoryMap[0x06] = &gbRom[0x6000]; - gbMemoryMap[0x07] = &gbRom[0x7000]; - gbMemoryMap[0x08] = &gbMemory[0x8000]; - gbMemoryMap[0x09] = &gbMemory[0x9000]; - gbMemoryMap[0x0a] = &gbMemory[0xa000]; - gbMemoryMap[0x0b] = &gbMemory[0xb000]; - gbMemoryMap[0x0c] = &gbMemory[0xc000]; - gbMemoryMap[0x0d] = &gbMemory[0xd000]; - gbMemoryMap[0x0e] = &gbMemory[0xe000]; - gbMemoryMap[0x0f] = &gbMemory[0xf000]; - - switch(gbRomType) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - // MBC 1 - memoryUpdateMapMBC1(); - break; - case 0x05: - case 0x06: - // MBC2 - memoryUpdateMapMBC2(); - break; - case 0x0b: - case 0x0c: - case 0x0d: - // MMM01 - memoryUpdateMapMMM01(); - break; - case 0x0f: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - // MBC 3 - memoryUpdateMapMBC3(); - break; - case 0x19: - case 0x1a: - case 0x1b: - // MBC5 - memoryUpdateMapMBC5(); - break; - case 0x1c: - case 0x1d: - case 0x1e: - // MBC 5 Rumble - memoryUpdateMapMBC5(); - break; - case 0x22: - // MBC 7 - memoryUpdateMapMBC7(); - break; - case 0x56: - // GS3 - memoryUpdateMapGS3(); - break; - case 0xfd: - // TAMA5 - memoryUpdateMapTAMA5(); - break; - case 0xfe: - // HuC3 - memoryUpdateMapHuC3(); - break; - case 0xff: - // HuC1 - memoryUpdateMapHuC1(); - break; - } - - if(gbCgbMode) { - utilGzRead(gzFile, gbVram, 0x4000); - utilGzRead(gzFile, gbWram, 0x8000); - - int value = register_SVBK; - if(value == 0) - value = 1; - - gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000]; - gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000]; - gbMemoryMap[0x0d] = &gbWram[value * 0x1000]; - } - - gbSoundReadGame(version, gzFile); - - if (gbCgbMode && gbSgbMode) { - gbSgbMode = 0; - } - - if(gbBorderOn && !gbSgbMask) { - gbSgbRenderBorder(); - } - - systemDrawScreen(); - - if(version > GBSAVE_GAME_VERSION_1) - gbCheatsReadGame(gzFile, version); - - if (version<11) - { - gbWriteMemory(0xff00, 0); - gbMemory[0xff04] = register_DIV; - gbMemory[0xff05] = register_TIMA; - gbMemory[0xff06] = register_TMA; - gbMemory[0xff07] = register_TAC; - gbMemory[0xff40] = register_LCDC; - gbMemory[0xff42] = register_SCY; - gbMemory[0xff43] = register_SCX; - gbMemory[0xff44] = register_LY; - gbMemory[0xff45] = register_LYC; - gbMemory[0xff46] = register_DMA; - gbMemory[0xff4a] = register_WY; - gbMemory[0xff4b] = register_WX; - gbMemory[0xff4f] = register_VBK; - gbMemory[0xff51] = register_HDMA1; - gbMemory[0xff52] = register_HDMA2; - gbMemory[0xff53] = register_HDMA3; - gbMemory[0xff54] = register_HDMA4; - gbMemory[0xff55] = register_HDMA5; - gbMemory[0xff70] = register_SVBK; - gbMemory[0xffff] = register_IE; - GBDIV_CLOCK_TICKS = 64; - - if (gbSpeed) - gbDivTicks /=2; - - if ((gbLcdMode == 0) && (register_STAT & 8)) - gbInt48Signal |= 1; - if ((gbLcdMode == 1) && (register_STAT & 0x10)) - gbInt48Signal |= 2; - if ((gbLcdMode == 2) && (register_STAT & 0x20)) - gbInt48Signal |= 4; - if ((register_LY==register_LYC) && (register_STAT & 0x40)) - gbInt48Signal |= 8; - - gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS; - - if (gbLcdMode == 2) - gbLcdLYIncrementTicks-=GBLCD_MODE_2_CLOCK_TICKS-gbLcdTicks; - else if (gbLcdMode == 3) - gbLcdLYIncrementTicks -=GBLCD_MODE_2_CLOCK_TICKS+GBLCD_MODE_3_CLOCK_TICKS-gbLcdTicks; - else if (gbLcdMode == 0) - gbLcdLYIncrementTicks =gbLcdTicks; - else if (gbLcdMode == 1) - { - gbLcdLYIncrementTicks = gbLcdTicks % GBLY_INCREMENT_CLOCK_TICKS; - if (register_LY == 0x99) - gbLcdLYIncrementTicks =gbLine99Ticks; - else if (register_LY == 0) - gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; - } - - gbLcdModeDelayed = gbLcdMode; - gbLcdTicksDelayed = gbLcdTicks--; - gbLcdLYIncrementTicksDelayed = gbLcdLYIncrementTicks--; - gbInterruptWait = 0; - memset(gbSpritesTicks,0,sizeof(gbSpritesTicks)); - } - else - { - gbLcdModeDelayed = utilReadInt(gzFile); - gbLcdTicksDelayed = utilReadInt(gzFile); - gbLcdLYIncrementTicksDelayed = utilReadInt(gzFile); - gbSpritesTicks[299] = utilReadInt(gzFile) & 0xff; - gbTimerModeChange = (utilReadInt(gzFile) ? true : false); - gbTimerOnChange = (utilReadInt(gzFile) ? true : false); - gbHardware = utilReadInt(gzFile); - gbBlackScreen = (utilReadInt(gzFile) ? true : false); - oldRegister_WY = utilReadInt(gzFile); - gbWindowLine = utilReadInt(gzFile); - inUseRegister_WY = utilReadInt(gzFile); - gbScreenOn = (utilReadInt(gzFile) ? true : false); - } - - if (gbSpeed) - gbLine99Ticks *= 2; - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - return true; -} - -bool gbReadMemSaveState(char *memory, int available) -{ - gzFile gzFile = utilMemGzOpen(memory, available, "r"); - - bool res = gbReadSaveState(gzFile); - - utilGzClose(gzFile); - - return res; -} - -bool gbReadSaveState(const char *name) -{ - gzFile gzFile = utilGzOpen(name,"rb"); - - if(gzFile == NULL) { - return false; - } - - bool res = gbReadSaveState(gzFile); - - utilGzClose(gzFile); - - return res; -} - -bool gbWritePNGFile(const char *fileName) -{ - if(gbBorderOn) - return utilWritePNGFile(fileName, 256, 224, pix); - return utilWritePNGFile(fileName, 160, 144, pix); -} - -bool gbWriteBMPFile(const char *fileName) -{ - if(gbBorderOn) - return utilWriteBMPFile(fileName, 256, 224, pix); - return utilWriteBMPFile(fileName, 160, 144, pix); -} - -void gbCleanUp() -{ - if(gbRam != NULL) { - free(gbRam); - gbRam = NULL; - } - - if(gbRom != NULL) { - free(gbRom); - gbRom = NULL; - } - - if(gbMemory != NULL) { - free(gbMemory); - gbMemory = NULL; - } - - if(gbLineBuffer != NULL) { - free(gbLineBuffer); - gbLineBuffer = NULL; - } - - if(pix != NULL) { - free(pix); - pix = NULL; - } - - gbSgbShutdown(); - - if(gbVram != NULL) { - free(gbVram); - gbVram = NULL; - } - - if(gbWram != NULL) { - free(gbWram); - gbWram = NULL; - } - - if(gbTAMA5ram != NULL) { - free(gbTAMA5ram); - gbTAMA5ram = NULL; - } - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; -} - -bool gbLoadRom(const char *szFile) -{ - int size = 0; - - if(gbRom != NULL) { - gbCleanUp(); - } - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - gbRom = utilLoad(szFile, - utilIsGBImage, - NULL, - size); - if(!gbRom) - return false; - - gbRomSize = size; - - gbBatteryError = false; - - if(bios != NULL) { - free(bios); - bios = NULL; - } - bios = (u8 *)calloc(1,0x100); - - return gbUpdateSizes(); -} - -bool gbUpdateSizes() -{ - if(gbRom[0x148] > 8) { - systemMessage(MSG_UNSUPPORTED_ROM_SIZE, - N_("Unsupported rom size %02x"), gbRom[0x148]); - return false; - } - - if(gbRomSize < gbRomSizes[gbRom[0x148]]) { - gbRom = (u8 *)realloc(gbRom, gbRomSizes[gbRom[0x148]]); - for (int i = gbRomSize; igbRomSizes[gbRom[0x148]]) && (genericflashcardEnable)) - { - gbRomSize = gbRomSize>>16; - gbRom[0x148] = 0; - if (gbRomSize) - { - while (!((gbRomSize & 1) || (gbRom[0x148] == 7))) - { - gbRom[0x148]++; - gbRomSize>>=1; - } - gbRom[0x148]++; - } - gbRom = (u8 *)realloc(gbRom, gbRomSizes[gbRom[0x148]]); - } - gbRomSize = gbRomSizes[gbRom[0x148]]; - gbRomSizeMask = gbRomSizesMasks[gbRom[0x148]]; - - - // The 'genericflashcard' option allows some PD to work. - // However, the setting is dangerous (if you let in enabled - // and play a normal game, it might just break everything). - // That's why it is not saved in the emulator options. - // Also I added some checks in VBA to make sure your saves will not be - // overwritten if you wrongly enable this option for a game - // you already played (and vice-versa, ie. if you forgot to - // enable the option for a game you played with it enabled, like Shawu Story). - u8 ramsize = genericflashcardEnable ? 5 : gbRom[0x149]; - gbRom[0x149] = ramsize; - - if ((gbRom[2] == 0x6D) && (gbRom[5] == 0x47) && (gbRom[6] == 0x65) && (gbRom[7] == 0x6E) && - (gbRom[8] == 0x69) && (gbRom[9] == 0x65) && (gbRom[0xA] == 0x28) && (gbRom[0xB] == 0x54)) - { - gbCheatingDevice = 1; // GameGenie - for (int i = 0; i < 0x20; i++) // Cleans GG hardware registers - gbRom[0x4000+i] = 0; - } - else if (((gbRom[0x104] == 0x44) && (gbRom[0x156] == 0xEA) && (gbRom[0x158] == 0x7F) && - (gbRom[0x159] == 0xEA) && (gbRom[0x15B] == 0x7F)) || ((gbRom[0x165] == 0x3E) && - (gbRom[0x166] == 0xD9) && (gbRom[0x16D] == 0xE1) && (gbRom[0x16E] == 0x7F))) - gbCheatingDevice = 2; // GameShark - else gbCheatingDevice = 0; - - if(ramsize > 5) { - systemMessage(MSG_UNSUPPORTED_RAM_SIZE, - N_("Unsupported ram size %02x"), gbRom[0x149]); - return false; - } - - gbRamSize = gbRamSizes[ramsize]; - gbRamSizeMask = gbRamSizesMasks[ramsize]; - - if(gbRamSize) { - gbRam = (u8 *)malloc(gbRamSize); - memset(gbRam, 0xff, gbRamSize); - } - - - gbRomType = gbRom[0x147]; - if (genericflashcardEnable) - { - /*if (gbRomType<2) - gbRomType =3; - else if ((gbRomType == 0xc) || (gbRomType == 0xf) || (gbRomType == 0x12) || - (gbRomType == 0x16) || (gbRomType == 0x1a) || (gbRomType == 0x1d)) - gbRomType++; - else if ((gbRomType == 0xb) || (gbRomType == 0x11) || (gbRomType == 0x15) || - (gbRomType == 0x19) || (gbRomType == 0x1c)) - gbRomType+=2; - else if ((gbRomType == 0x5) || (gbRomType == 0x6)) - gbRomType = 0x1a;*/ - gbRomType = 0x1b; - } - else if (gbCheatingDevice == 1) - gbRomType = 0x55; - else if (gbCheatingDevice == 2) - gbRomType = 0x56; - - gbRom[0x147] = gbRomType; - - mapperReadRAM = NULL; - - switch(gbRomType) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x08: - case 0x09: - // MBC 1 - mapper = mapperMBC1ROM; - mapperRAM = mapperMBC1RAM; - mapperReadRAM = mapperMBC1ReadRAM; - break; - case 0x05: - case 0x06: - // MBC2 - mapper = mapperMBC2ROM; - mapperRAM = mapperMBC2RAM; - gbRamSize = 0x200; - gbRamSizeMask = 0x1ff; - break; - case 0x0b: - case 0x0c: - case 0x0d: - // MMM01 - mapper = mapperMMM01ROM; - mapperRAM = mapperMMM01RAM; - break; - case 0x0f: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0xfc: - // MBC 3 - mapper = mapperMBC3ROM; - mapperRAM = mapperMBC3RAM; - mapperReadRAM = mapperMBC3ReadRAM; - break; - case 0x19: - case 0x1a: - case 0x1b: - // MBC5 - mapper = mapperMBC5ROM; - mapperRAM = mapperMBC5RAM; - mapperReadRAM = mapperMBC5ReadRAM; - break; - case 0x1c: - case 0x1d: - case 0x1e: - // MBC 5 Rumble - mapper = mapperMBC5ROM; - mapperRAM = mapperMBC5RAM; - mapperReadRAM = mapperMBC5ReadRAM; - break; - case 0x22: - // MBC 7 - mapper = mapperMBC7ROM; - mapperRAM = mapperMBC7RAM; - mapperReadRAM = mapperMBC7ReadRAM; - break; - // GG (GameGenie) - case 0x55: - mapper = mapperGGROM; - break; - case 0x56: - // GS (GameShark) - mapper = mapperGS3ROM; - break; - case 0xfd: - // TAMA5 - if (gbRam!= NULL) - { - free(gbRam); - gbRam = NULL; - } - - ramsize = 3; - gbRamSize = gbRamSizes[3]; - gbRamSizeMask = gbRamSizesMasks[3]; - gbRam = (u8 *)malloc(gbRamSize); - memset(gbRam, 0x0, gbRamSize); - - gbTAMA5ramSize = 0x100; - - if (gbTAMA5ram == NULL) - gbTAMA5ram = (u8 *)malloc(gbTAMA5ramSize); - memset(gbTAMA5ram, 0x0, gbTAMA5ramSize); - - mapperRAM = mapperTAMA5RAM; - mapperReadRAM = mapperTAMA5ReadRAM; - mapperUpdateClock = memoryUpdateTAMA5Clock; - break; - case 0xfe: - // HuC3 - mapper = mapperHuC3ROM; - mapperRAM = mapperHuC3RAM; - mapperReadRAM = mapperHuC3ReadRAM; - break; - case 0xff: - // HuC1 - mapper = mapperHuC1ROM; - mapperRAM = mapperHuC1RAM; - break; - default: - systemMessage(MSG_UNKNOWN_CARTRIDGE_TYPE, - N_("Unknown cartridge type %02x"), gbRomType); - return false; - } - - switch(gbRomType) { - case 0x03: - case 0x06: - case 0x0f: - case 0x10: - case 0x13: - case 0x1b: - case 0x1d: - case 0x1e: - case 0x22: - case 0xfd: - case 0xff: - gbBattery = 1; - break; - } - - gbInit(); - - //gbReset(); - - switch(gbRomType) { - case 0x1c: - case 0x1d: - case 0x1e: - gbDataMBC5.isRumbleCartridge = 1; - } - - return true; -} - -int gbGetNextEvent (int clockTicks) -{ - if (register_LCDC & 0x80) - { - if(gbLcdTicks < clockTicks) - clockTicks = gbLcdTicks; - - if(gbLcdTicksDelayed < clockTicks) - clockTicks = gbLcdTicksDelayed; - - if(gbLcdLYIncrementTicksDelayed < clockTicks) - clockTicks = gbLcdLYIncrementTicksDelayed; - } - - if(gbLcdLYIncrementTicks < clockTicks) - clockTicks = gbLcdLYIncrementTicks; - - if(gbSerialOn && (gbSerialTicks < clockTicks)) - clockTicks = gbSerialTicks; - - if(gbTimerOn && (((gbInternalTimer) & gbTimerMask[gbTimerMode])+1 < clockTicks)) - clockTicks = ((gbInternalTimer) & gbTimerMask[gbTimerMode])+1; - - //if(soundTicks && (soundTicks < clockTicks)) - // clockTicks = soundTicks; - - if ((clockTicks<=0) || (gbInterruptWait)) - clockTicks = 1; - - return clockTicks; -} - -void gbDrawLine() -{ - switch(systemColorDepth) { - case 16: - { - u16 * dest = (u16 *)pix + - (gbBorderLineSkip+2) * (register_LY + gbBorderRowSkip+1) - + gbBorderColumnSkip; - for(int x = 0; x < 160; ) { - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - } - if(gbBorderOn) - dest += gbBorderColumnSkip; - *dest++ = 0; // for filters that read one pixel more - } - break; - - case 24: - { - u8 *dest = (u8 *)pix + - 3*(gbBorderLineSkip * (register_LY + gbBorderRowSkip) + - gbBorderColumnSkip); - for(int x = 0; x < 160;) { - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - } - } - break; - - case 32: - { - u32 * dest = (u32 *)pix + - (gbBorderLineSkip+1) * (register_LY + gbBorderRowSkip+1) - + gbBorderColumnSkip; - for(int x = 0; x < 160;) { - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - } - } - break; - } -} - -void gbEmulate(int ticksToStop) -{ - gbRegister tempRegister; - u8 tempValue; - s8 offset; - - clockTicks = 0; - gbDmaTicks = 0; - - register int opcode = 0; - - int opcode1 = 0; - int opcode2 = 0; - bool execute = false; - - while(1) { -#ifndef FINAL_VERSION - if(systemDebug) { - if(!(IFF & 0x80)) { - if(systemDebug > 1) { - sprintf(gbBuffer,"PC=%04x AF=%04x BC=%04x DE=%04x HL=%04x SP=%04x I=%04x\n", - PC.W, AF.W, BC.W, DE.W,HL.W,SP.W,IFF); - } else { - sprintf(gbBuffer,"PC=%04x I=%02x\n", PC.W, IFF); - } - log(gbBuffer); - } - } -#endif - - u16 oldPCW = PC.W; - - if(IFF & 0x80) { - if(register_LCDC & 0x80) { - clockTicks = gbLcdTicks; - } else - clockTicks = 1000; - - clockTicks = gbGetNextEvent(clockTicks); - - /*if(gbLcdTicksDelayed < clockTicks) - clockTicks = gbLcdTicksDelayed; - - if(gbLcdLYIncrementTicksDelayed < clockTicks) - clockTicks = gbLcdLYIncrementTicksDelayed; - - if(gbLcdLYIncrementTicks < clockTicks) - clockTicks = gbLcdLYIncrementTicks; - - if(gbSerialOn && (gbSerialTicks < clockTicks)) - clockTicks = gbSerialTicks; - - if(gbTimerOn && (((gbInternalTimer) & gbTimerMask[gbTimerMode])+1 < clockTicks)) - clockTicks = ((gbInternalTimer) & gbTimerMask[gbTimerMode])+1; - - if(soundTicks && (soundTicks < clockTicks)) - clockTicks = soundTicks; - - if ((clockTicks<=0) || (gbInterruptWait)) - clockTicks = 1;*/ - - } else { - - // First we apply the clockTicks, then we execute the opcodes. - opcode1 = 0; - opcode2 = 0; - execute = true; - - opcode2 = opcode1 = opcode = gbReadOpcode(PC.W++); - - // If HALT state was launched while IME = 0 and (register_IF & register_IE & 0x1F), - // PC.W is not incremented for the first byte of the next instruction. - if (IFF & 2) - { - PC.W--; - IFF &= ~2; - } - - clockTicks = gbCycles[opcode]; - - switch(opcode) { - case 0xCB: - // extended opcode - opcode2 = opcode = gbReadOpcode(PC.W++); - clockTicks = gbCyclesCB[opcode]; - break; - } - gbOldClockTicks = clockTicks-1; - gbIntBreak = 1; - } - - - if(!emulating) - return; - - // For 'breakpoint' support (opcode 0xFC is considered as a breakpoint) - if ((clockTicks==0) && execute) - { - PC.W = oldPCW; - return; - } - - - if (!(IFF & 0x80)) - clockTicks = 1; - - gbRedoLoop: - - - - if (gbInterruptWait) - gbInterruptWait = 0; - else - gbInterruptLaunched = 0; - - - // Used for the EI/DI instruction's delay. - if (IFF & 0x38) - { - int tempIFF = (IFF >> 4) & 3; - - if (tempIFF <=clockTicks) - { - tempIFF = 0; - IFF |=1; - } - else - tempIFF -= clockTicks; - IFF = (IFF & 0xCF) | (tempIFF <<4); - - if (IFF & 0x08) - IFF &= 0x82; - } - - - if (register_LCDCBusy) - { - register_LCDCBusy-=clockTicks; - if (register_LCDCBusy<0) - register_LCDCBusy = 0; - } - - - if(gbSgbMode) { - if(gbSgbPacketTimeout) { - gbSgbPacketTimeout -= clockTicks; - - if(gbSgbPacketTimeout <= 0) - gbSgbResetPacketState(); - } - } - - ticksToStop -= clockTicks; - - // DIV register emulation - gbDivTicks -= clockTicks; - while(gbDivTicks <= 0) { - gbMemory[0xff04] = ++register_DIV; - gbDivTicks += GBDIV_CLOCK_TICKS; - } - - if(register_LCDC & 0x80) { - // LCD stuff - - gbLcdTicks -= clockTicks; - gbLcdTicksDelayed -= clockTicks; - gbLcdLYIncrementTicks -= clockTicks; - gbLcdLYIncrementTicksDelayed -= clockTicks; - - - // our counters are off, see what we need to do - - // This looks (and kinda is) complicated, however this - // is the only way I found to emulate properly the way - // the real hardware operates... - while(((gbLcdTicks <= 0) && (gbLCDChangeHappened == false)) || - ((gbLcdTicksDelayed <= 0) && (gbLCDChangeHappened == true)) || - ((gbLcdLYIncrementTicks <= 0) && (gbLYChangeHappened == false)) || - ((gbLcdLYIncrementTicksDelayed<=0) && (gbLYChangeHappened == true))) - { - - if ((gbLcdLYIncrementTicks <= 0) && (!gbLYChangeHappened)) - { - gbLYChangeHappened = true; - gbMemory[0xff44] = register_LY = (register_LY + 1) % 154; - - if (register_LY == 0x91) - { - /* if (IFF & 0x80) - gbScreenOn = !gbScreenOn; - else*/ if (register_LCDC & 0x80) - gbScreenOn = true; - } - - gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; - - if (gbLcdMode == 1) - { - - if(register_LY == 153) - gbLcdLYIncrementTicks -= GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; - else if(register_LY == 0) - gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; - } - - // GB only 'bug' : Halt state is broken one tick before LY==LYC interrupt - // is reflected in the registers. - if ((gbHardware & 5) && (IFF & 0x80) && (register_LY == register_LYC) - && (register_STAT & 0x40) && (register_LY != 0)) - { - if (!((gbLcdModeDelayed != 1) && (register_LY==0))) - { - gbInt48Signal &= ~9; - gbCompareLYToLYC(); - gbLYChangeHappened = false; - gbMemory[0xff41] = register_STAT; - gbMemory[0xff0f] = register_IF; - } - - gbLcdLYIncrementTicksDelayed += GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks+1; - } - } - - - if ((gbLcdTicks <= 0) && (!gbLCDChangeHappened)) - { - gbLCDChangeHappened = true; - - switch(gbLcdMode) - { - case 0: - { - // H-Blank - // check if we reached the V-Blank period - if(register_LY == 144) { - // Yes, V-Blank - // set the LY increment counter - if (gbHardware & 0x5) - { - register_IF |= 1; // V-Blank interrupt - } - - gbInt48Signal &= ~6; - if(register_STAT & 0x10) - { - // send LCD interrupt only if no interrupt 48h signal... - if ((!(gbInt48Signal & 1)) && ((!(gbInt48Signal & 8)) || (gbHardware & 0x0a))) - { - register_IF |=2; - gbInterruptLaunched |= 2; - if (gbHardware & 0xa) - gbInterruptWait = 1; - } - gbInt48Signal |= 2; - } - gbInt48Signal &= ~1; - - gbLcdTicks += GBLCD_MODE_1_CLOCK_TICKS; - gbLcdMode = 1; - - } else { - // go the the OAM being accessed mode - gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; - gbLcdMode = 2; - - gbInt48Signal &= ~6; - if(register_STAT & 0x20) - { - // send LCD interrupt only if no interrupt 48h signal... - if (!gbInt48Signal) - { - register_IF |= 2; - gbInterruptLaunched |= 2; - } - gbInt48Signal |= 4; - } - gbInt48Signal &= ~1; - } - } - break; - case 1: - { - // V-Blank - // next mode is OAM being accessed mode - gbInt48Signal &= ~5; - if(register_STAT & 0x20) - { - // send LCD interrupt only if no interrupt 48h signal... - if (!gbInt48Signal) - { - register_IF |= 2; - gbInterruptLaunched |= 2; - if ((gbHardware & 0xa) && (IFF & 0x80)) - gbInterruptWait = 1; - } - gbInt48Signal |= 4; - } - gbInt48Signal &= ~2; - - gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; - - gbLcdMode = 2; - register_LY = 0x00; - - } - break; - case 2: - { - - // OAM being accessed mode - // next mode is OAM and VRAM in use - if ((gbScreenOn) && (register_LCDC & 0x80)) - { - gbDrawSprites(false); - // Used to add a one tick delay when a window line is drawn. - //(fixes a part of Carmaggedon problem) - if((register_LCDC & 0x01 || gbCgbMode) && (register_LCDC & 0x20) && - (gbWindowLine != -2)) { - - int inUseRegister_WY = 0; - int tempgbWindowLine = gbWindowLine; - - if ((tempgbWindowLine == -1) || (tempgbWindowLine>144)) - { - inUseRegister_WY = oldRegister_WY; - if (register_LY>oldRegister_WY) - tempgbWindowLine = 146; - } - - int wy = inUseRegister_WY; - - if(register_LY >= inUseRegister_WY) { - - if (tempgbWindowLine == -1) - tempgbWindowLine = 0; - - int wx = register_WX; - wx -= 7; - if (wx<0) - wx = 0; - - if((wx <= 159) && (tempgbWindowLine <= 143)) - for (int i = wx; i<300; i++) - if (gbSpeed) - gbSpritesTicks[i]+=3; - else - gbSpritesTicks[i]+=1; - } - } - } - - gbInt48Signal &= ~7; - - gbLcdTicks += GBLCD_MODE_3_CLOCK_TICKS+gbSpritesTicks[299]; - gbLcdMode = 3; - } - break; - case 3: - { - // OAM and VRAM in use - // next mode is H-Blank - - - gbInt48Signal &= ~7; - if(register_STAT & 0x08) - { - // send LCD interrupt only if no interrupt 48h signal... - if (!(gbInt48Signal & 8)) - { - register_IF |= 2; - if ((gbHardware & 0xa) && (IFF & 0x80)) - gbInterruptWait = 1; - } - gbInt48Signal |= 1; - } - - gbLcdTicks += GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]; - - gbLcdMode = 0; - - // No HDMA during HALT ! - if(gbHdmaOn && (!(IFF & 0x80) || (register_IE & register_IF & 0x1f))) { - gbDoHdma(); - } - - } - break; - } - } - - - if ((gbLcdTicksDelayed <= 0) && (gbLCDChangeHappened)) { - int framesToSkip = systemFrameSkip; - if(speedup) - framesToSkip = 9; // try 6 FPS during speedup - //gbLcdTicksDelayed = gbLcdTicks+1; - gbLCDChangeHappened = false; - switch(gbLcdModeDelayed) { - case 0: - { - // H-Blank - - memset(gbSCYLine,gbSCYLine[299],sizeof(gbSCYLine)); - memset(gbSCXLine,gbSCXLine[299],sizeof(gbSCXLine)); - memset(gbBgpLine,gbBgpLine[299],sizeof(gbBgpLine)); - memset(gbObp0Line,gbObp0Line[299],sizeof(gbObp0Line)); - memset(gbObp1Line,gbObp1Line[299],sizeof(gbObp1Line)); - memset(gbSpritesTicks,gbSpritesTicks[299],sizeof(gbSpritesTicks)); - - if (gbWindowLine <0) - oldRegister_WY = register_WY; - // check if we reached the V-Blank period - if(register_LY == 144) { - // Yes, V-Blank - // set the LY increment counter - - if(register_LCDC & 0x80) { - if (gbHardware & 0xa) - { - - register_IF |= 1; // V-Blank interrupt - gbInterruptLaunched |=1; - } - - - } - - gbLcdTicksDelayed += GBLCD_MODE_1_CLOCK_TICKS; - gbLcdModeDelayed = 1; - - gbFrameCount++; - systemFrame(); - - if((gbFrameCount % 10) == 0) - system10Frames(60); - - if(gbFrameCount >= 60) { - u32 currentTime = systemGetClock(); - if(currentTime != gbLastTime) - systemShowSpeed(100000/(currentTime - gbLastTime)); - else - systemShowSpeed(0); - gbLastTime = currentTime; - gbFrameCount = 0; - } - - if(systemReadJoypads()) { - // read joystick - if(gbSgbMode && gbSgbMultiplayer) { - if(gbSgbFourPlayers) { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - gbJoymask[2] = systemReadJoypad(2); - gbJoymask[3] = systemReadJoypad(3); - } else { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - } - } else { - gbJoymask[0] = systemReadJoypad(-1); - } - } - int newmask = gbJoymask[0] & 255; - - if(gbRomType == 0x22) { - systemUpdateMotionSensor(); - } - - if(newmask) - { - gbMemory[0xff0f] |= 16; - } - - - newmask = (gbJoymask[0] >> 10); - - speedup = (newmask & 1) ? true : false; - gbCapture = (newmask & 2) ? true : false; - - if(gbCapture && !gbCapturePrevious) { - gbCaptureNumber++; - systemScreenCapture(gbCaptureNumber); - } - gbCapturePrevious = gbCapture; - - if(gbFrameSkipCount >= framesToSkip) { - - if(!gbSgbMask) - { - if (gbBorderOn) - gbSgbRenderBorder(); - //if (gbScreenOn) - systemDrawScreen(); - } - gbFrameSkipCount = 0; - } else - gbFrameSkipCount++; - - } else { - // go the the OAM being accessed mode - gbLcdTicksDelayed += GBLCD_MODE_2_CLOCK_TICKS; - gbLcdModeDelayed = 2; - gbInt48Signal &= ~3; - } - } - break; - case 1: - { - // V-Blank - // next mode is OAM being accessed mode - - // gbScreenOn = true; - - oldRegister_WY = register_WY; - - gbLcdTicksDelayed += GBLCD_MODE_2_CLOCK_TICKS; - gbLcdModeDelayed = 2; - - // reset the window line - gbWindowLine = -1; - } - break; - case 2: - { - // OAM being accessed mode - // next mode is OAM and VRAM in use - gbLcdTicksDelayed += GBLCD_MODE_3_CLOCK_TICKS+gbSpritesTicks[299]; - gbLcdModeDelayed = 3; - } - break; - case 3: - { - - // OAM and VRAM in use - // next mode is H-Blank - if((register_LY < 144) && (register_LCDC & 0x80) && gbScreenOn) { - if(!gbSgbMask) { - if(gbFrameSkipCount >= framesToSkip) { - if (!gbBlackScreen) - { - gbRenderLine(); - gbDrawSprites(true); - } - else if (gbBlackScreen) - { - u16 color = gbColorOption ? gbColorFilter[0] : 0; - if (!gbCgbMode) - color = gbColorOption ? gbColorFilter[gbPalette[3] & 0x7FFF] : - gbPalette[3] & 0x7FFF; - for(int i = 0; i < 160; i++) - { - gbLineMix[i] = color; - gbLineBuffer[i] = 0; - } - } - gbDrawLine(); - } - } - } - gbLcdTicksDelayed += GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]; - gbLcdModeDelayed = 0; - } - break; - } - } - - if ((gbLcdLYIncrementTicksDelayed <= 0) && (gbLYChangeHappened == true)) - { - - gbLYChangeHappened = false; - - if (!((gbLcdMode != 1) && (register_LY==0))) - { - { - gbInt48Signal &= ~8; - gbCompareLYToLYC(); - if ((gbInt48Signal == 8) && (!((register_LY == 0) && (gbHardware & 1)))) - gbInterruptLaunched |= 2; - if ((gbHardware & (gbSpeed ? 8 : 2)) && (register_LY==0) && ((register_STAT & 0x44) == 0x44) && (gbLcdLYIncrementTicksDelayed==0)) - { - gbInterruptWait = 1; - - } - } - } - gbLcdLYIncrementTicksDelayed += GBLY_INCREMENT_CLOCK_TICKS; - - if (gbLcdModeDelayed == 1) - { - - if(register_LY == 153) - gbLcdLYIncrementTicksDelayed -= GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; - else if(register_LY == 0) - gbLcdLYIncrementTicksDelayed += GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; - } - gbMemory[0xff0f] = register_IF; - gbMemory[0xff41] = register_STAT; - } - } - gbMemory[0xff0f] = register_IF; - gbMemory[0xff41] = register_STAT = (register_STAT & 0xfc) | gbLcdModeDelayed; - } - else - { - - // Used to update the screen with white lines when it's off. - // (it looks strange, but it's kinda accurate :p) - // You can try the Mario Demo Vx.x for exemple - // (check the bottom 2 lines while moving) - if (!gbWhiteScreen) - { - gbScreenTicks -= clockTicks; - gbLcdLYIncrementTicks -= clockTicks; - while (gbLcdLYIncrementTicks <=0) - { - register_LY = ((register_LY+1)%154); - gbLcdLYIncrementTicks+=GBLY_INCREMENT_CLOCK_TICKS; - } - if (gbScreenTicks <= 0) - { - gbWhiteScreen = 1; - u8 register_LYLcdOff = ((register_LY+154)%154); - for (register_LY=0;register_LY <= 0x90;register_LY++) - { - u16 color = gbColorOption ? gbColorFilter[0x7FFF] : - 0x7FFF; - if (!gbCgbMode) - color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : - gbPalette[0] & 0x7FFF; - for(int i = 0; i < 160; i++) - { - gbLineMix[i] = color; - gbLineBuffer[i] = 0; - } - gbDrawLine(); - } - register_LY = register_LYLcdOff; - } - } - - if (gbWhiteScreen) - { - gbLcdLYIncrementTicks -= clockTicks; - - while (gbLcdLYIncrementTicks <=0) - { - register_LY = ((register_LY+1)%154); - gbLcdLYIncrementTicks+=GBLY_INCREMENT_CLOCK_TICKS; - if (register_LY<144) - { - - u16 color = gbColorOption ? gbColorFilter[0x7FFF] : - 0x7FFF; - if (!gbCgbMode) - color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : - gbPalette[0] & 0x7FFF; - for(int i = 0; i < 160; i++) - { - gbLineMix[i] = color; - gbLineBuffer[i] = 0; - } - gbDrawLine(); - } - else if ((register_LY==144) && (!systemFrameSkip)) - { - int framesToSkip = systemFrameSkip; - if(speedup) - framesToSkip = 9; // try 6 FPS during speedup - if((gbFrameSkipCount >= framesToSkip) || (gbWhiteScreen == 1)) { - gbWhiteScreen = 2; - - if(!gbSgbMask) - { - if (gbBorderOn) - gbSgbRenderBorder(); - //if (gbScreenOn) - systemDrawScreen(); - } - } - if(systemReadJoypads()) { - // read joystick - if(gbSgbMode && gbSgbMultiplayer) { - if(gbSgbFourPlayers) { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - gbJoymask[2] = systemReadJoypad(2); - gbJoymask[3] = systemReadJoypad(3); - } else { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - } - } else { - gbJoymask[0] = systemReadJoypad(-1); - } - } - gbFrameCount++; - - systemFrame(); - - if((gbFrameCount % 10) == 0) - system10Frames(60); - - if(gbFrameCount >= 60) { - u32 currentTime = systemGetClock(); - if(currentTime != gbLastTime) - systemShowSpeed(100000/(currentTime - gbLastTime)); - else - systemShowSpeed(0); - gbLastTime = currentTime; - gbFrameCount = 0; - } - } - } - } - } - - gbMemory[0xff41] = register_STAT; - - // serial emulation - if(gbSerialOn) { -#ifdef LINK_EMULATION - if(linkConnected) { - gbSerialTicks -= clockTicks; - - while(gbSerialTicks <= 0) { - // increment number of shifted bits - gbSerialBits++; - linkProc(); - if(gbSerialOn && (gbMemory[0xff02] & 1)) { - if(gbSerialBits == 8) { - gbSerialBits = 0; - gbMemory[0xff01] = 0xff; - gbMemory[0xff02] &= 0x7f; - gbSerialOn = 0; - gbMemory[0xff0f] = register_IF |= 8; - gbSerialTicks = 0; - } - } - gbSerialTicks += GBSERIAL_CLOCK_TICKS; - } - } else { -#endif - if(gbMemory[0xff02] & 1) { - gbSerialTicks -= clockTicks; - - // overflow - while(gbSerialTicks <= 0) { - // shift serial byte to right and put a 1 bit in its place - // gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1); - // increment number of shifted bits - gbSerialBits++; - if(gbSerialBits == 8) { - // end of transmission - if(gbSerialFunction) // external device - gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); - else - gbMemory[0xff01] = 0xff; - gbSerialTicks = 0; - gbMemory[0xff02] &= 0x7f; - gbSerialOn = 0; - gbMemory[0xff0f] = register_IF |= 8; - gbSerialBits = 0; - } else - gbSerialTicks += GBSERIAL_CLOCK_TICKS; - } - } -#ifdef LINK_EMULATION - } -#endif - } - - - soundTicks -= clockTicks; - if ( !gbSpeed ) - soundTicks -= clockTicks; - - while(soundTicks < 0) { - soundTicks += SOUND_CLOCK_TICKS; - - gbSoundTick(); - } - - - // timer emulation - - if(gbTimerOn) { - gbTimerTicks= ((gbInternalTimer) & gbTimerMask[gbTimerMode])+1-clockTicks; - - while(gbTimerTicks <= 0) { - register_TIMA++; - // timer overflow! - if((register_TIMA & 0xff) == 0) { - // reload timer modulo - register_TIMA = register_TMA; - // flag interrupt - gbMemory[0xff0f] = register_IF |= 4; - } - gbTimerTicks += gbTimerClockTicks; - } - gbTimerOnChange = false; - gbTimerModeChange = false; - - gbMemory[0xff05] = register_TIMA; - - } - - gbInternalTimer -= clockTicks; - while (gbInternalTimer<0) - gbInternalTimer+=0x100; - - /* - if(soundOffFlag) { - if(synchronize && !speedup) { - synchronizeTicks -= clockTicks; - - while(synchronizeTicks < 0) { - synchronizeTicks += SYNCHRONIZE_CLOCK_TICKS; - - DWORD now = timeGetTime(); - gbElapsedTime += (now - timeNow); - - if(gbElapsedTime < 50) { - DWORD diff = 50 - gbElapsedTime; - Sleep(diff); - timeNow = timeGetTime(); - elapsedTime = timeNow - now - diff; - if((int)elapsedTime < 0) - elapsedTime = 0; - } else { - timeNow = timeGetTime(); - elapsedTime = 0; - } - } - } - } - */ - - clockTicks = 0; - - if (gbIntBreak == 1) - { - gbIntBreak = 0; - if ((register_IE & register_IF & gbInterruptLaunched & 0x3) && - ((IFF & 0x81) == 1) && (!gbInterruptWait) && (execute)) - { - gbIntBreak = 2; - PC.W = oldPCW; - execute = false; - gbOldClockTicks = 0; - } - if (gbOldClockTicks) - { - clockTicks = gbOldClockTicks; - gbOldClockTicks = 0; - goto gbRedoLoop; - } - } - - // Executes the opcode(s), and apply the instruction's remaining clockTicks (if any). - if (execute) - { - switch(opcode1) { - case 0xCB: - // extended opcode - switch(opcode2) { -#include "gbCodesCB.h" - } - break; -#include "gbCodes.h" - } - execute = false; - - if (clockTicks) - { - gbDmaTicks += clockTicks; - clockTicks = 0; - } - } - - if (gbDmaTicks) - { - clockTicks = gbGetNextEvent(gbDmaTicks); - - if (clockTicks<=gbDmaTicks) - gbDmaTicks -= clockTicks; - else - { - clockTicks = gbDmaTicks; - gbDmaTicks = 0; - } - - goto gbRedoLoop; - } - - - // Remove the 'if an IE is pending' flag if IE has finished being executed. - if ((IFF & 0x40) && !(IFF & 0x30)) - IFF &= 0x81; - - - - if ((register_IE & register_IF & 0x1f) && (IFF & 0x81) && (!gbInterruptWait)) - { - - if (IFF & 1) - { - // Add 5 ticks for the interrupt execution time - gbDmaTicks += 5; - - if (gbIntBreak == 2) - { - gbDmaTicks--; - gbIntBreak = 0; - } - - - if(register_IF & register_IE & 1) - gbVblank_interrupt(); - else if(register_IF & register_IE & 2) - gbLcd_interrupt(); - else if(register_IF & register_IE & 4) - gbTimer_interrupt(); - else if(register_IF & register_IE & 8) - gbSerial_interrupt(); - else if(register_IF & register_IE & 16) - gbJoypad_interrupt(); - } - - IFF &= ~0x81; - } - - if (IFF & 0x08) - IFF &=~0x79; - - // Used to apply the interrupt's execution time. - if (gbDmaTicks) - { - clockTicks = gbGetNextEvent(gbDmaTicks); - - if (clockTicks<=gbDmaTicks) - gbDmaTicks -= clockTicks; - else - { - clockTicks = gbDmaTicks; - gbDmaTicks = 0; - } - goto gbRedoLoop; - } - - - gbBlackScreen = false; - - if((ticksToStop <= 0)) { - if(!(register_LCDC & 0x80)) { - if(systemReadJoypads()) { - // read joystick - if(gbSgbMode && gbSgbMultiplayer) { - if(gbSgbFourPlayers) { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - gbJoymask[2] = systemReadJoypad(2); - gbJoymask[3] = systemReadJoypad(3); - } else { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - } - } else { - gbJoymask[0] = systemReadJoypad(-1); - } - } - } - return; - } - } -} - -struct EmulatedSystem GBSystem = { - // emuMain - gbEmulate, - // emuReset - gbReset, - // emuCleanUp - gbCleanUp, - // emuReadBattery - gbReadBatteryFile, - // emuWriteBattery - gbWriteBatteryFile, - // emuReadState - gbReadSaveState, - // emuWriteState - gbWriteSaveState, - // emuReadMemState - gbReadMemSaveState, - // emuWriteMemState - gbWriteMemSaveState, - // emuWritePNG - gbWritePNGFile, - // emuWriteBMP - gbWriteBMPFile, - // emuUpdateCPSR - NULL, - // emuHasDebugger - false, - // emuCount -#ifdef FINAL_VERSION - 70000/4, -#else - 1000, -#endif -}; +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include +#include +#include + +#include "../System.h" +#include "../NLS.h" +#include "gb.h" +#include "gbCheats.h" +#include "gbGlobals.h" +#include "gbMemory.h" +#include "gbSGB.h" +#include "gbSound.h" +#include "../Util.h" + +#ifdef __GNUC__ +#define _stricmp strcasecmp +#endif + +extern u8 *pix; +extern bool speedup; + +bool gbUpdateSizes(); +bool inBios = false; + +// debugging +bool memorydebug = false; +char gbBuffer[2048]; + +extern u16 gbLineMix[160]; + +// mappers +void (*mapper)(u16,u8) = NULL; +void (*mapperRAM)(u16,u8) = NULL; +u8 (*mapperReadRAM)(u16) = NULL; +void (*mapperUpdateClock)() = NULL; + +// registers +gbRegister PC; +gbRegister SP; +gbRegister AF; +gbRegister BC; +gbRegister DE; +gbRegister HL; +u16 IFF = 0; +// 0xff04 +u8 register_DIV = 0; +// 0xff05 +u8 register_TIMA = 0; +// 0xff06 +u8 register_TMA = 0; +// 0xff07 +u8 register_TAC = 0; +// 0xff0f +u8 register_IF = 0; +// 0xff40 +u8 register_LCDC = 0; +// 0xff41 +u8 register_STAT = 0; +// 0xff42 +u8 register_SCY = 0; +// 0xff43 +u8 register_SCX = 0; +// 0xff44 +u8 register_LY = 0; +// 0xff45 +u8 register_LYC = 0; +// 0xff46 +u8 register_DMA = 0; +// 0xff4a +u8 register_WY = 0; +// 0xff4b +u8 register_WX = 0; +// 0xff4f +u8 register_VBK = 0; +// 0xff51 +u8 register_HDMA1 = 0; +// 0xff52 +u8 register_HDMA2 = 0; +// 0xff53 +u8 register_HDMA3 = 0; +// 0xff54 +u8 register_HDMA4 = 0; +// 0xff55 +u8 register_HDMA5 = 0; +// 0xff70 +u8 register_SVBK = 0; +// 0xffff +u8 register_IE = 0; + +// ticks definition +int GBDIV_CLOCK_TICKS = 64; +int GBLCD_MODE_0_CLOCK_TICKS = 51; +int GBLCD_MODE_1_CLOCK_TICKS = 1140; +int GBLCD_MODE_2_CLOCK_TICKS = 20; +int GBLCD_MODE_3_CLOCK_TICKS = 43; +int GBLY_INCREMENT_CLOCK_TICKS = 114; +int GBTIMER_MODE_0_CLOCK_TICKS = 256; +int GBTIMER_MODE_1_CLOCK_TICKS = 4; +int GBTIMER_MODE_2_CLOCK_TICKS = 16; +int GBTIMER_MODE_3_CLOCK_TICKS = 64; +int GBSERIAL_CLOCK_TICKS = 128; +int GBSYNCHRONIZE_CLOCK_TICKS = 52920; + +// state variables + +// general +int clockTicks = 0; +bool gbSystemMessage = false; +int gbGBCColorType = 0; +int gbHardware = 0; +int gbRomType = 0; +int gbRemainingClockTicks = 0; +int gbOldClockTicks = 0; +int gbIntBreak = 0; +int gbInterruptLaunched = 0; +u8 gbCheatingDevice = 0; // 1 = GS, 2 = GG +// breakpoint +bool breakpoint = false; +// interrupt +int gbInt48Signal = 0; +int gbInterruptWait = 0; +// serial +int gbSerialOn = 0; +int gbSerialTicks = 0; +int gbSerialBits = 0; +// timer +bool gbTimerOn = false; +int gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS; +int gbTimerClockTicks = GBTIMER_MODE_0_CLOCK_TICKS; +int gbTimerMode = 0; +bool gbIncreased = false; +// The internal timer is always active, and it is +// not reset by writing to register_TIMA/TMA, but by +// writing to register_DIV... +int gbInternalTimer = 0x55; +const u8 gbTimerMask [4] = {0xff, 0x3, 0xf, 0x3f}; +const u8 gbTimerBug [8] = {0x80, 0x80, 0x02, 0x02, 0x0, 0xff, 0x0, 0xff}; +bool gbTimerModeChange = false; +bool gbTimerOnChange = false; +// lcd +bool gbScreenOn = true; +int gbLcdMode = 2; +int gbLcdModeDelayed = 2; +int gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS-1; +int gbLcdTicksDelayed = GBLCD_MODE_2_CLOCK_TICKS; +int gbLcdLYIncrementTicks = 114; +int gbLcdLYIncrementTicksDelayed = 115; +int gbScreenTicks = 0; +u8 gbSCYLine[300]; +u8 gbSCXLine[300]; +u8 gbBgpLine[300]; +u8 gbObp0Line [300]; +u8 gbObp1Line [300]; +u8 gbSpritesTicks [300]; +u8 oldRegister_WY; +bool gbLYChangeHappened = false; +bool gbLCDChangeHappened = false; +int gbLine99Ticks = 1; +int gbRegisterLYLCDCOffOn = 0; +int inUseRegister_WY = 0; + +// Used to keep track of the line that ellapse +// when screen is off +int gbWhiteScreen = 0; +bool gbBlackScreen = false; +int register_LCDCBusy = 0; + +// div +int gbDivTicks = GBDIV_CLOCK_TICKS; +// cgb +int gbVramBank = 0; +int gbWramBank = 1; +//sgb +bool gbSgbResetFlag = false; +// gbHdmaDestination is 0x99d0 on startup (tested on HW) +// but I'm not sure what gbHdmaSource is... +int gbHdmaSource = 0x99d0; +int gbHdmaDestination = 0x99d0; +int gbHdmaBytes = 0x0000; +int gbHdmaOn = 0; +int gbSpeed = 0; +// frame counting +int gbFrameCount = 0; +int gbFrameSkip = 0; +int gbFrameSkipCount = 0; +// timing +u32 gbLastTime = 0; +u32 gbElapsedTime = 0; +u32 gbTimeNow = 0; +int gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS; +// emulator features +int gbBattery = 0; +bool gbBatteryError = false; +int gbCaptureNumber = 0; +bool gbCapture = false; +bool gbCapturePrevious = false; +int gbJoymask[4] = { 0, 0, 0, 0 }; + +int gbRomSizes[] = { 0x00008000, // 32K + 0x00010000, // 64K + 0x00020000, // 128K + 0x00040000, // 256K + 0x00080000, // 512K + 0x00100000, // 1024K + 0x00200000, // 2048K + 0x00400000, // 4096K + 0x00800000 // 8192K +}; +int gbRomSizesMasks[] = { 0x00007fff, + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff +}; + +int gbRamSizes[6] = { 0x00000000, // 0K + 0x00002000, // 2K // Changed to 2000 to avoid problems with gbMemoryMap... + 0x00002000, // 8K + 0x00008000, // 32K + 0x00020000, // 128K + 0x00010000 // 64K +}; + +int gbRamSizesMasks[6] = { 0x00000000, + 0x000007ff, + 0x00001fff, + 0x00007fff, + 0x0001ffff, + 0x0000ffff +}; + +int gbCycles[] = { +// 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1, // 0 + 1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1, // 1 + 2, 3, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 2 + 2, 3, 2, 2, 3, 3, 3, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 3 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 4 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 5 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 6 + 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, // 7 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 8 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 9 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // a + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // b + 2, 3, 3, 4, 3, 4, 2, 4, 2, 4, 3, 2, 3, 6, 2, 4, // c + 2, 3, 3, 1, 3, 4, 2, 4, 2, 4, 3, 1, 3, 1, 2, 4, // d + 3, 3, 2, 1, 1, 4, 2, 4, 4, 1, 4, 1, 1, 1, 2, 4, // e + 3, 3, 2, 1, 1, 4, 2, 4, 3, 2, 4, 1, 0, 1, 2, 4 // f +}; + +int gbCyclesCB[] = { +// 0 1 2 3 4 5 6 7 8 9 a b c d e f + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 0 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 1 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 2 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 3 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 4 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 5 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 6 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 7 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 8 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 9 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // a + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // b + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // c + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // d + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // e + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 // f +}; + +u16 DAATable[] = { + 0x0080,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0800,0x0900,0x1020,0x1120,0x1220,0x1320,0x1420,0x1520, + 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, + 0x1800,0x1900,0x2020,0x2120,0x2220,0x2320,0x2420,0x2520, + 0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, + 0x2800,0x2900,0x3020,0x3120,0x3220,0x3320,0x3420,0x3520, + 0x3000,0x3100,0x3200,0x3300,0x3400,0x3500,0x3600,0x3700, + 0x3800,0x3900,0x4020,0x4120,0x4220,0x4320,0x4420,0x4520, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4800,0x4900,0x5020,0x5120,0x5220,0x5320,0x5420,0x5520, + 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, + 0x5800,0x5900,0x6020,0x6120,0x6220,0x6320,0x6420,0x6520, + 0x6000,0x6100,0x6200,0x6300,0x6400,0x6500,0x6600,0x6700, + 0x6800,0x6900,0x7020,0x7120,0x7220,0x7320,0x7420,0x7520, + 0x7000,0x7100,0x7200,0x7300,0x7400,0x7500,0x7600,0x7700, + 0x7800,0x7900,0x8020,0x8120,0x8220,0x8320,0x8420,0x8520, + 0x8000,0x8100,0x8200,0x8300,0x8400,0x8500,0x8600,0x8700, + 0x8800,0x8900,0x9020,0x9120,0x9220,0x9320,0x9420,0x9520, + 0x9000,0x9100,0x9200,0x9300,0x9400,0x9500,0x9600,0x9700, + 0x9800,0x9900,0x00B0,0x0130,0x0230,0x0330,0x0430,0x0530, + 0x0090,0x0110,0x0210,0x0310,0x0410,0x0510,0x0610,0x0710, + 0x0810,0x0910,0x1030,0x1130,0x1230,0x1330,0x1430,0x1530, + 0x1010,0x1110,0x1210,0x1310,0x1410,0x1510,0x1610,0x1710, + 0x1810,0x1910,0x2030,0x2130,0x2230,0x2330,0x2430,0x2530, + 0x2010,0x2110,0x2210,0x2310,0x2410,0x2510,0x2610,0x2710, + 0x2810,0x2910,0x3030,0x3130,0x3230,0x3330,0x3430,0x3530, + 0x3010,0x3110,0x3210,0x3310,0x3410,0x3510,0x3610,0x3710, + 0x3810,0x3910,0x4030,0x4130,0x4230,0x4330,0x4430,0x4530, + 0x4010,0x4110,0x4210,0x4310,0x4410,0x4510,0x4610,0x4710, + 0x4810,0x4910,0x5030,0x5130,0x5230,0x5330,0x5430,0x5530, + 0x5010,0x5110,0x5210,0x5310,0x5410,0x5510,0x5610,0x5710, + 0x5810,0x5910,0x6030,0x6130,0x6230,0x6330,0x6430,0x6530, + 0x6010,0x6110,0x6210,0x6310,0x6410,0x6510,0x6610,0x6710, + 0x6810,0x6910,0x7030,0x7130,0x7230,0x7330,0x7430,0x7530, + 0x7010,0x7110,0x7210,0x7310,0x7410,0x7510,0x7610,0x7710, + 0x7810,0x7910,0x8030,0x8130,0x8230,0x8330,0x8430,0x8530, + 0x8010,0x8110,0x8210,0x8310,0x8410,0x8510,0x8610,0x8710, + 0x8810,0x8910,0x9030,0x9130,0x9230,0x9330,0x9430,0x9530, + 0x9010,0x9110,0x9210,0x9310,0x9410,0x9510,0x9610,0x9710, + 0x9810,0x9910,0xA030,0xA130,0xA230,0xA330,0xA430,0xA530, + 0xA010,0xA110,0xA210,0xA310,0xA410,0xA510,0xA610,0xA710, + 0xA810,0xA910,0xB030,0xB130,0xB230,0xB330,0xB430,0xB530, + 0xB010,0xB110,0xB210,0xB310,0xB410,0xB510,0xB610,0xB710, + 0xB810,0xB910,0xC030,0xC130,0xC230,0xC330,0xC430,0xC530, + 0xC010,0xC110,0xC210,0xC310,0xC410,0xC510,0xC610,0xC710, + 0xC810,0xC910,0xD030,0xD130,0xD230,0xD330,0xD430,0xD530, + 0xD010,0xD110,0xD210,0xD310,0xD410,0xD510,0xD610,0xD710, + 0xD810,0xD910,0xE030,0xE130,0xE230,0xE330,0xE430,0xE530, + 0xE010,0xE110,0xE210,0xE310,0xE410,0xE510,0xE610,0xE710, + 0xE810,0xE910,0xF030,0xF130,0xF230,0xF330,0xF430,0xF530, + 0xF010,0xF110,0xF210,0xF310,0xF410,0xF510,0xF610,0xF710, + 0xF810,0xF910,0x00B0,0x0130,0x0230,0x0330,0x0430,0x0530, + 0x0090,0x0110,0x0210,0x0310,0x0410,0x0510,0x0610,0x0710, + 0x0810,0x0910,0x1030,0x1130,0x1230,0x1330,0x1430,0x1530, + 0x1010,0x1110,0x1210,0x1310,0x1410,0x1510,0x1610,0x1710, + 0x1810,0x1910,0x2030,0x2130,0x2230,0x2330,0x2430,0x2530, + 0x2010,0x2110,0x2210,0x2310,0x2410,0x2510,0x2610,0x2710, + 0x2810,0x2910,0x3030,0x3130,0x3230,0x3330,0x3430,0x3530, + 0x3010,0x3110,0x3210,0x3310,0x3410,0x3510,0x3610,0x3710, + 0x3810,0x3910,0x4030,0x4130,0x4230,0x4330,0x4430,0x4530, + 0x4010,0x4110,0x4210,0x4310,0x4410,0x4510,0x4610,0x4710, + 0x4810,0x4910,0x5030,0x5130,0x5230,0x5330,0x5430,0x5530, + 0x5010,0x5110,0x5210,0x5310,0x5410,0x5510,0x5610,0x5710, + 0x5810,0x5910,0x6030,0x6130,0x6230,0x6330,0x6430,0x6530, + 0x0600,0x0700,0x0800,0x0900,0x0A00,0x0B00,0x0C00,0x0D00, + 0x0E00,0x0F00,0x1020,0x1120,0x1220,0x1320,0x1420,0x1520, + 0x1600,0x1700,0x1800,0x1900,0x1A00,0x1B00,0x1C00,0x1D00, + 0x1E00,0x1F00,0x2020,0x2120,0x2220,0x2320,0x2420,0x2520, + 0x2600,0x2700,0x2800,0x2900,0x2A00,0x2B00,0x2C00,0x2D00, + 0x2E00,0x2F00,0x3020,0x3120,0x3220,0x3320,0x3420,0x3520, + 0x3600,0x3700,0x3800,0x3900,0x3A00,0x3B00,0x3C00,0x3D00, + 0x3E00,0x3F00,0x4020,0x4120,0x4220,0x4320,0x4420,0x4520, + 0x4600,0x4700,0x4800,0x4900,0x4A00,0x4B00,0x4C00,0x4D00, + 0x4E00,0x4F00,0x5020,0x5120,0x5220,0x5320,0x5420,0x5520, + 0x5600,0x5700,0x5800,0x5900,0x5A00,0x5B00,0x5C00,0x5D00, + 0x5E00,0x5F00,0x6020,0x6120,0x6220,0x6320,0x6420,0x6520, + 0x6600,0x6700,0x6800,0x6900,0x6A00,0x6B00,0x6C00,0x6D00, + 0x6E00,0x6F00,0x7020,0x7120,0x7220,0x7320,0x7420,0x7520, + 0x7600,0x7700,0x7800,0x7900,0x7A00,0x7B00,0x7C00,0x7D00, + 0x7E00,0x7F00,0x8020,0x8120,0x8220,0x8320,0x8420,0x8520, + 0x8600,0x8700,0x8800,0x8900,0x8A00,0x8B00,0x8C00,0x8D00, + 0x8E00,0x8F00,0x9020,0x9120,0x9220,0x9320,0x9420,0x9520, + 0x9600,0x9700,0x9800,0x9900,0x9A00,0x9B00,0x9C00,0x9D00, + 0x9E00,0x9F00,0x00B0,0x0130,0x0230,0x0330,0x0430,0x0530, + 0x0610,0x0710,0x0810,0x0910,0x0A10,0x0B10,0x0C10,0x0D10, + 0x0E10,0x0F10,0x1030,0x1130,0x1230,0x1330,0x1430,0x1530, + 0x1610,0x1710,0x1810,0x1910,0x1A10,0x1B10,0x1C10,0x1D10, + 0x1E10,0x1F10,0x2030,0x2130,0x2230,0x2330,0x2430,0x2530, + 0x2610,0x2710,0x2810,0x2910,0x2A10,0x2B10,0x2C10,0x2D10, + 0x2E10,0x2F10,0x3030,0x3130,0x3230,0x3330,0x3430,0x3530, + 0x3610,0x3710,0x3810,0x3910,0x3A10,0x3B10,0x3C10,0x3D10, + 0x3E10,0x3F10,0x4030,0x4130,0x4230,0x4330,0x4430,0x4530, + 0x4610,0x4710,0x4810,0x4910,0x4A10,0x4B10,0x4C10,0x4D10, + 0x4E10,0x4F10,0x5030,0x5130,0x5230,0x5330,0x5430,0x5530, + 0x5610,0x5710,0x5810,0x5910,0x5A10,0x5B10,0x5C10,0x5D10, + 0x5E10,0x5F10,0x6030,0x6130,0x6230,0x6330,0x6430,0x6530, + 0x6610,0x6710,0x6810,0x6910,0x6A10,0x6B10,0x6C10,0x6D10, + 0x6E10,0x6F10,0x7030,0x7130,0x7230,0x7330,0x7430,0x7530, + 0x7610,0x7710,0x7810,0x7910,0x7A10,0x7B10,0x7C10,0x7D10, + 0x7E10,0x7F10,0x8030,0x8130,0x8230,0x8330,0x8430,0x8530, + 0x8610,0x8710,0x8810,0x8910,0x8A10,0x8B10,0x8C10,0x8D10, + 0x8E10,0x8F10,0x9030,0x9130,0x9230,0x9330,0x9430,0x9530, + 0x9610,0x9710,0x9810,0x9910,0x9A10,0x9B10,0x9C10,0x9D10, + 0x9E10,0x9F10,0xA030,0xA130,0xA230,0xA330,0xA430,0xA530, + 0xA610,0xA710,0xA810,0xA910,0xAA10,0xAB10,0xAC10,0xAD10, + 0xAE10,0xAF10,0xB030,0xB130,0xB230,0xB330,0xB430,0xB530, + 0xB610,0xB710,0xB810,0xB910,0xBA10,0xBB10,0xBC10,0xBD10, + 0xBE10,0xBF10,0xC030,0xC130,0xC230,0xC330,0xC430,0xC530, + 0xC610,0xC710,0xC810,0xC910,0xCA10,0xCB10,0xCC10,0xCD10, + 0xCE10,0xCF10,0xD030,0xD130,0xD230,0xD330,0xD430,0xD530, + 0xD610,0xD710,0xD810,0xD910,0xDA10,0xDB10,0xDC10,0xDD10, + 0xDE10,0xDF10,0xE030,0xE130,0xE230,0xE330,0xE430,0xE530, + 0xE610,0xE710,0xE810,0xE910,0xEA10,0xEB10,0xEC10,0xED10, + 0xEE10,0xEF10,0xF030,0xF130,0xF230,0xF330,0xF430,0xF530, + 0xF610,0xF710,0xF810,0xF910,0xFA10,0xFB10,0xFC10,0xFD10, + 0xFE10,0xFF10,0x00B0,0x0130,0x0230,0x0330,0x0430,0x0530, + 0x0610,0x0710,0x0810,0x0910,0x0A10,0x0B10,0x0C10,0x0D10, + 0x0E10,0x0F10,0x1030,0x1130,0x1230,0x1330,0x1430,0x1530, + 0x1610,0x1710,0x1810,0x1910,0x1A10,0x1B10,0x1C10,0x1D10, + 0x1E10,0x1F10,0x2030,0x2130,0x2230,0x2330,0x2430,0x2530, + 0x2610,0x2710,0x2810,0x2910,0x2A10,0x2B10,0x2C10,0x2D10, + 0x2E10,0x2F10,0x3030,0x3130,0x3230,0x3330,0x3430,0x3530, + 0x3610,0x3710,0x3810,0x3910,0x3A10,0x3B10,0x3C10,0x3D10, + 0x3E10,0x3F10,0x4030,0x4130,0x4230,0x4330,0x4430,0x4530, + 0x4610,0x4710,0x4810,0x4910,0x4A10,0x4B10,0x4C10,0x4D10, + 0x4E10,0x4F10,0x5030,0x5130,0x5230,0x5330,0x5430,0x5530, + 0x5610,0x5710,0x5810,0x5910,0x5A10,0x5B10,0x5C10,0x5D10, + 0x5E10,0x5F10,0x6030,0x6130,0x6230,0x6330,0x6430,0x6530, + 0x00C0,0x0140,0x0240,0x0340,0x0440,0x0540,0x0640,0x0740, + 0x0840,0x0940,0x0440,0x0540,0x0640,0x0740,0x0840,0x0940, + 0x1040,0x1140,0x1240,0x1340,0x1440,0x1540,0x1640,0x1740, + 0x1840,0x1940,0x1440,0x1540,0x1640,0x1740,0x1840,0x1940, + 0x2040,0x2140,0x2240,0x2340,0x2440,0x2540,0x2640,0x2740, + 0x2840,0x2940,0x2440,0x2540,0x2640,0x2740,0x2840,0x2940, + 0x3040,0x3140,0x3240,0x3340,0x3440,0x3540,0x3640,0x3740, + 0x3840,0x3940,0x3440,0x3540,0x3640,0x3740,0x3840,0x3940, + 0x4040,0x4140,0x4240,0x4340,0x4440,0x4540,0x4640,0x4740, + 0x4840,0x4940,0x4440,0x4540,0x4640,0x4740,0x4840,0x4940, + 0x5040,0x5140,0x5240,0x5340,0x5440,0x5540,0x5640,0x5740, + 0x5840,0x5940,0x5440,0x5540,0x5640,0x5740,0x5840,0x5940, + 0x6040,0x6140,0x6240,0x6340,0x6440,0x6540,0x6640,0x6740, + 0x6840,0x6940,0x6440,0x6540,0x6640,0x6740,0x6840,0x6940, + 0x7040,0x7140,0x7240,0x7340,0x7440,0x7540,0x7640,0x7740, + 0x7840,0x7940,0x7440,0x7540,0x7640,0x7740,0x7840,0x7940, + 0x8040,0x8140,0x8240,0x8340,0x8440,0x8540,0x8640,0x8740, + 0x8840,0x8940,0x8440,0x8540,0x8640,0x8740,0x8840,0x8940, + 0x9040,0x9140,0x9240,0x9340,0x9440,0x9540,0x9640,0x9740, + 0x9840,0x9940,0x3450,0x3550,0x3650,0x3750,0x3850,0x3950, + 0x4050,0x4150,0x4250,0x4350,0x4450,0x4550,0x4650,0x4750, + 0x4850,0x4950,0x4450,0x4550,0x4650,0x4750,0x4850,0x4950, + 0x5050,0x5150,0x5250,0x5350,0x5450,0x5550,0x5650,0x5750, + 0x5850,0x5950,0x5450,0x5550,0x5650,0x5750,0x5850,0x5950, + 0x6050,0x6150,0x6250,0x6350,0x6450,0x6550,0x6650,0x6750, + 0x6850,0x6950,0x6450,0x6550,0x6650,0x6750,0x6850,0x6950, + 0x7050,0x7150,0x7250,0x7350,0x7450,0x7550,0x7650,0x7750, + 0x7850,0x7950,0x7450,0x7550,0x7650,0x7750,0x7850,0x7950, + 0x8050,0x8150,0x8250,0x8350,0x8450,0x8550,0x8650,0x8750, + 0x8850,0x8950,0x8450,0x8550,0x8650,0x8750,0x8850,0x8950, + 0x9050,0x9150,0x9250,0x9350,0x9450,0x9550,0x9650,0x9750, + 0x9850,0x9950,0x9450,0x9550,0x9650,0x9750,0x9850,0x9950, + 0xA050,0xA150,0xA250,0xA350,0xA450,0xA550,0xA650,0xA750, + 0xA850,0xA950,0xA450,0xA550,0xA650,0xA750,0xA850,0xA950, + 0xB050,0xB150,0xB250,0xB350,0xB450,0xB550,0xB650,0xB750, + 0xB850,0xB950,0xB450,0xB550,0xB650,0xB750,0xB850,0xB950, + 0xC050,0xC150,0xC250,0xC350,0xC450,0xC550,0xC650,0xC750, + 0xC850,0xC950,0xC450,0xC550,0xC650,0xC750,0xC850,0xC950, + 0xD050,0xD150,0xD250,0xD350,0xD450,0xD550,0xD650,0xD750, + 0xD850,0xD950,0xD450,0xD550,0xD650,0xD750,0xD850,0xD950, + 0xE050,0xE150,0xE250,0xE350,0xE450,0xE550,0xE650,0xE750, + 0xE850,0xE950,0xE450,0xE550,0xE650,0xE750,0xE850,0xE950, + 0xF050,0xF150,0xF250,0xF350,0xF450,0xF550,0xF650,0xF750, + 0xF850,0xF950,0xF450,0xF550,0xF650,0xF750,0xF850,0xF950, + 0x00D0,0x0150,0x0250,0x0350,0x0450,0x0550,0x0650,0x0750, + 0x0850,0x0950,0x0450,0x0550,0x0650,0x0750,0x0850,0x0950, + 0x1050,0x1150,0x1250,0x1350,0x1450,0x1550,0x1650,0x1750, + 0x1850,0x1950,0x1450,0x1550,0x1650,0x1750,0x1850,0x1950, + 0x2050,0x2150,0x2250,0x2350,0x2450,0x2550,0x2650,0x2750, + 0x2850,0x2950,0x2450,0x2550,0x2650,0x2750,0x2850,0x2950, + 0x3050,0x3150,0x3250,0x3350,0x3450,0x3550,0x3650,0x3750, + 0x3850,0x3950,0x3450,0x3550,0x3650,0x3750,0x3850,0x3950, + 0x4050,0x4150,0x4250,0x4350,0x4450,0x4550,0x4650,0x4750, + 0x4850,0x4950,0x4450,0x4550,0x4650,0x4750,0x4850,0x4950, + 0x5050,0x5150,0x5250,0x5350,0x5450,0x5550,0x5650,0x5750, + 0x5850,0x5950,0x5450,0x5550,0x5650,0x5750,0x5850,0x5950, + 0x6050,0x6150,0x6250,0x6350,0x6450,0x6550,0x6650,0x6750, + 0x6850,0x6950,0x6450,0x6550,0x6650,0x6750,0x6850,0x6950, + 0x7050,0x7150,0x7250,0x7350,0x7450,0x7550,0x7650,0x7750, + 0x7850,0x7950,0x7450,0x7550,0x7650,0x7750,0x7850,0x7950, + 0x8050,0x8150,0x8250,0x8350,0x8450,0x8550,0x8650,0x8750, + 0x8850,0x8950,0x8450,0x8550,0x8650,0x8750,0x8850,0x8950, + 0x9050,0x9150,0x9250,0x9350,0x9450,0x9550,0x9650,0x9750, + 0x9850,0x9950,0x9450,0x9550,0x9650,0x9750,0x9850,0x9950, + 0xFA60,0xFB60,0xFC60,0xFD60,0xFE60,0xFF60,0x00C0,0x0140, + 0x0240,0x0340,0x0440,0x0540,0x0640,0x0740,0x0840,0x0940, + 0x0A60,0x0B60,0x0C60,0x0D60,0x0E60,0x0F60,0x1040,0x1140, + 0x1240,0x1340,0x1440,0x1540,0x1640,0x1740,0x1840,0x1940, + 0x1A60,0x1B60,0x1C60,0x1D60,0x1E60,0x1F60,0x2040,0x2140, + 0x2240,0x2340,0x2440,0x2540,0x2640,0x2740,0x2840,0x2940, + 0x2A60,0x2B60,0x2C60,0x2D60,0x2E60,0x2F60,0x3040,0x3140, + 0x3240,0x3340,0x3440,0x3540,0x3640,0x3740,0x3840,0x3940, + 0x3A60,0x3B60,0x3C60,0x3D60,0x3E60,0x3F60,0x4040,0x4140, + 0x4240,0x4340,0x4440,0x4540,0x4640,0x4740,0x4840,0x4940, + 0x4A60,0x4B60,0x4C60,0x4D60,0x4E60,0x4F60,0x5040,0x5140, + 0x5240,0x5340,0x5440,0x5540,0x5640,0x5740,0x5840,0x5940, + 0x5A60,0x5B60,0x5C60,0x5D60,0x5E60,0x5F60,0x6040,0x6140, + 0x6240,0x6340,0x6440,0x6540,0x6640,0x6740,0x6840,0x6940, + 0x6A60,0x6B60,0x6C60,0x6D60,0x6E60,0x6F60,0x7040,0x7140, + 0x7240,0x7340,0x7440,0x7540,0x7640,0x7740,0x7840,0x7940, + 0x7A60,0x7B60,0x7C60,0x7D60,0x7E60,0x7F60,0x8040,0x8140, + 0x8240,0x8340,0x8440,0x8540,0x8640,0x8740,0x8840,0x8940, + 0x8A60,0x8B60,0x8C60,0x8D60,0x8E60,0x8F60,0x9040,0x9140, + 0x9240,0x9340,0x3450,0x3550,0x3650,0x3750,0x3850,0x3950, + 0x3A70,0x3B70,0x3C70,0x3D70,0x3E70,0x3F70,0x4050,0x4150, + 0x4250,0x4350,0x4450,0x4550,0x4650,0x4750,0x4850,0x4950, + 0x4A70,0x4B70,0x4C70,0x4D70,0x4E70,0x4F70,0x5050,0x5150, + 0x5250,0x5350,0x5450,0x5550,0x5650,0x5750,0x5850,0x5950, + 0x5A70,0x5B70,0x5C70,0x5D70,0x5E70,0x5F70,0x6050,0x6150, + 0x6250,0x6350,0x6450,0x6550,0x6650,0x6750,0x6850,0x6950, + 0x6A70,0x6B70,0x6C70,0x6D70,0x6E70,0x6F70,0x7050,0x7150, + 0x7250,0x7350,0x7450,0x7550,0x7650,0x7750,0x7850,0x7950, + 0x7A70,0x7B70,0x7C70,0x7D70,0x7E70,0x7F70,0x8050,0x8150, + 0x8250,0x8350,0x8450,0x8550,0x8650,0x8750,0x8850,0x8950, + 0x8A70,0x8B70,0x8C70,0x8D70,0x8E70,0x8F70,0x9050,0x9150, + 0x9250,0x9350,0x9450,0x9550,0x9650,0x9750,0x9850,0x9950, + 0x9A70,0x9B70,0x9C70,0x9D70,0x9E70,0x9F70,0xA050,0xA150, + 0xA250,0xA350,0xA450,0xA550,0xA650,0xA750,0xA850,0xA950, + 0xAA70,0xAB70,0xAC70,0xAD70,0xAE70,0xAF70,0xB050,0xB150, + 0xB250,0xB350,0xB450,0xB550,0xB650,0xB750,0xB850,0xB950, + 0xBA70,0xBB70,0xBC70,0xBD70,0xBE70,0xBF70,0xC050,0xC150, + 0xC250,0xC350,0xC450,0xC550,0xC650,0xC750,0xC850,0xC950, + 0xCA70,0xCB70,0xCC70,0xCD70,0xCE70,0xCF70,0xD050,0xD150, + 0xD250,0xD350,0xD450,0xD550,0xD650,0xD750,0xD850,0xD950, + 0xDA70,0xDB70,0xDC70,0xDD70,0xDE70,0xDF70,0xE050,0xE150, + 0xE250,0xE350,0xE450,0xE550,0xE650,0xE750,0xE850,0xE950, + 0xEA70,0xEB70,0xEC70,0xED70,0xEE70,0xEF70,0xF050,0xF150, + 0xF250,0xF350,0xF450,0xF550,0xF650,0xF750,0xF850,0xF950, + 0xFA70,0xFB70,0xFC70,0xFD70,0xFE70,0xFF70,0x00D0,0x0150, + 0x0250,0x0350,0x0450,0x0550,0x0650,0x0750,0x0850,0x0950, + 0x0A70,0x0B70,0x0C70,0x0D70,0x0E70,0x0F70,0x1050,0x1150, + 0x1250,0x1350,0x1450,0x1550,0x1650,0x1750,0x1850,0x1950, + 0x1A70,0x1B70,0x1C70,0x1D70,0x1E70,0x1F70,0x2050,0x2150, + 0x2250,0x2350,0x2450,0x2550,0x2650,0x2750,0x2850,0x2950, + 0x2A70,0x2B70,0x2C70,0x2D70,0x2E70,0x2F70,0x3050,0x3150, + 0x3250,0x3350,0x3450,0x3550,0x3650,0x3750,0x3850,0x3950, + 0x3A70,0x3B70,0x3C70,0x3D70,0x3E70,0x3F70,0x4050,0x4150, + 0x4250,0x4350,0x4450,0x4550,0x4650,0x4750,0x4850,0x4950, + 0x4A70,0x4B70,0x4C70,0x4D70,0x4E70,0x4F70,0x5050,0x5150, + 0x5250,0x5350,0x5450,0x5550,0x5650,0x5750,0x5850,0x5950, + 0x5A70,0x5B70,0x5C70,0x5D70,0x5E70,0x5F70,0x6050,0x6150, + 0x6250,0x6350,0x6450,0x6550,0x6650,0x6750,0x6850,0x6950, + 0x6A70,0x6B70,0x6C70,0x6D70,0x6E70,0x6F70,0x7050,0x7150, + 0x7250,0x7350,0x7450,0x7550,0x7650,0x7750,0x7850,0x7950, + 0x7A70,0x7B70,0x7C70,0x7D70,0x7E70,0x7F70,0x8050,0x8150, + 0x8250,0x8350,0x8450,0x8550,0x8650,0x8750,0x8850,0x8950, + 0x8A70,0x8B70,0x8C70,0x8D70,0x8E70,0x8F70,0x9050,0x9150, + 0x9250,0x9350,0x9450,0x9550,0x9650,0x9750,0x9850,0x9950, +}; + +u8 ZeroTable[256] = { + 0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0 +}; + +#define GBSAVE_GAME_VERSION_1 1 +#define GBSAVE_GAME_VERSION_2 2 +#define GBSAVE_GAME_VERSION_3 3 +#define GBSAVE_GAME_VERSION_4 4 +#define GBSAVE_GAME_VERSION_5 5 +#define GBSAVE_GAME_VERSION_6 6 +#define GBSAVE_GAME_VERSION_7 7 +#define GBSAVE_GAME_VERSION_8 8 +#define GBSAVE_GAME_VERSION_9 9 +#define GBSAVE_GAME_VERSION_10 10 +#define GBSAVE_GAME_VERSION_11 11 +#define GBSAVE_GAME_VERSION GBSAVE_GAME_VERSION_11 + +int inline gbGetValue(int min,int max,int v) +{ + return (int)(min+(float)(max-min)*(2.0*(v/31.0)-(v/31.0)*(v/31.0))); +} + +void gbGenFilter() +{ + for (int r=0;r<32;r++) { + for (int g=0;g<32;g++) { + for (int b=0;b<32;b++) { + int nr=gbGetValue(gbGetValue(4,14,g), + gbGetValue(24,29,g),r)-4; + int ng=gbGetValue(gbGetValue(4+gbGetValue(0,5,r), + 14+gbGetValue(0,3,r),b), + gbGetValue(24+gbGetValue(0,3,r), + 29+gbGetValue(0,1,r),b),g)-4; + int nb=gbGetValue(gbGetValue(4+gbGetValue(0,5,r), + 14+gbGetValue(0,3,r),g), + gbGetValue(24+gbGetValue(0,3,r), + 29+gbGetValue(0,1,r),g),b)-4; + gbColorFilter[(b<<10)|(g<<5)|r]=(nb<<10)|(ng<<5)|nr; + } + } + } +} + +bool gbIsGameboyRom(char * file) +{ + if(strlen(file) > 4) { + char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".gb") == 0) + return true; + if(_stricmp(p, ".gbc") == 0) + return true; + if(_stricmp(p, ".cgb") == 0) + return true; + if(_stricmp(p, ".sgb") == 0) + return true; + } + } + + return false; +} + +void gbCopyMemory(u16 d, u16 s, int count) +{ + while(count) { + gbMemoryMap[d>>12][d & 0x0fff] = gbMemoryMap[s>>12][s & 0x0fff]; + s++; + d++; + count--; + } +} + +void gbDoHdma() +{ + + gbCopyMemory((gbHdmaDestination & 0x1ff0) | 0x8000, + gbHdmaSource & 0xfff0, + 0x10); + + gbHdmaDestination += 0x10; + if (gbHdmaDestination == 0xa000) + gbHdmaDestination = 0x8000; + + gbHdmaSource += 0x10; + if (gbHdmaSource == 0x8000) + gbHdmaSource = 0xa000; + + register_HDMA2 = gbHdmaSource & 0xff; + register_HDMA1 = gbHdmaSource>>8; + + register_HDMA4 = gbHdmaDestination & 0xff; + register_HDMA3 = gbHdmaDestination>>8; + + gbHdmaBytes -= 0x10; + gbMemory[0xff55] = --register_HDMA5; + if(register_HDMA5 == 0xff) + gbHdmaOn = 0; + +// We need to add the dmaClockticks for HDMA ! + if(gbSpeed) + gbDmaTicks = 17; + else + gbDmaTicks = 9; + + if (IFF & 0x80) + gbDmaTicks++; + +} + +// fix for Harley and Lego Racers +void gbCompareLYToLYC() +{ + if(register_LCDC & 0x80) { + if(register_LY == register_LYC) { + + // mark that we have a match + register_STAT |= 4; + + // check if we need an interrupt + if (register_STAT & 0x40) + { + // send LCD interrupt only if no interrupt 48h signal... + if (!gbInt48Signal) + { + register_IF |=2; + } + gbInt48Signal |= 8; + } + } + else // no match + { + register_STAT &= 0xfb; + gbInt48Signal &=~8; + } + } +} + +void gbWriteMemory(register u16 address, register u8 value) +{ + + if(address < 0x8000) { +#ifndef FINAL_VERSION + if(memorydebug && (address>0x3fff || address < 0x2000)) { + log("Memory register write %04x=%02x PC=%04x\n", + address, + value, + PC.W); + } + +#endif + if(mapper) + (*mapper)(address, value); + return; + + } + + if(address < 0xa000) { + // No access to Vram during mode 3 + // (used to emulate the gfx differences between GB & GBC-GBA/SP in Stunt Racer) + if ((gbLcdModeDelayed !=3) || + // This part is used to emulate a small difference between hardwares + // (check 8-in-1's arrow on GBA/GBC to verify it) + ((register_LY == 0) && ((gbHardware & 0xa) && (gbScreenOn==false) && + (register_LCDC & 0x80)) && + (gbLcdLYIncrementTicksDelayed ==(GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS)))) + gbMemoryMap[address>>12][address&0x0fff] = value; + return; + } + + // Used for the mirroring of 0xC000 in 0xE000 + if ((address >= 0xe000) && (address < 0xfe00)) + address &= ~0x2000; + + if(address < 0xc000) { +#ifndef FINAL_VERSION + if(memorydebug) { + log("Memory register write %04x=%02x PC=%04x\n", + address, + value, + PC.W); + } +#endif + + // Is that a correct fix ??? (it used to be 'if (mapper)')... + if(mapperRAM) + (*mapperRAM)(address, value); + return; + } + + + if(address < 0xfe00) { + gbMemoryMap[address>>12][address & 0x0fff] = value; + return; + } + + // OAM not accessible during mode 2 & 3. + if(address < 0xfea0) + { + if (((gbHardware & 0xa) && ((gbLcdMode | gbLcdModeDelayed) &2)) || + ((gbHardware & 5) && (((gbLcdModeDelayed == 2) && + (gbLcdTicksDelayed<=GBLCD_MODE_2_CLOCK_TICKS)) || + (gbLcdModeDelayed == 3)))) + return; + else + { + gbMemory[address] = value; + return; + } + } + + + + if((address > 0xfea0) && (address < 0xff00)){ // GBC allows reading/writing to that area + gbMemory[address] = value; + return; + } + + switch(address & 0x00ff) { + + case 0x00: { + gbMemory[0xff00] = ((gbMemory[0xff00] & 0xcf) | + (value & 0x30) | 0xc0); + if(gbSgbMode) { + gbSgbDoBitTransfer(value); + } + return; + } + + case 0x01: { + gbMemory[0xff01] = value; + return; + } + + // serial control + case 0x02: { + gbSerialOn = (value & 0x80); + gbMemory[0xff02] = value; + if(gbSerialOn) { + gbSerialTicks = GBSERIAL_CLOCK_TICKS; +#ifdef LINK_EMULATION + if(linkConnected) { + if(value & 1) { + linkSendByte(0x100|gbMemory[0xFF01]); + Sleep(5); + } + } +#endif + } + + gbSerialBits = 0; + return; + } + + case 0x04: { + // DIV register resets on any write + // (not totally perfect, but better than nothing) + gbMemory[0xff04] = register_DIV = 0; + gbDivTicks = GBDIV_CLOCK_TICKS; + // Another weird timer 'bug' : + // Writing to DIV register resets the internal timer, + // and can also increase TIMA/trigger an interrupt + // in some cases... + if (gbTimerOn && !(gbInternalTimer & (gbTimerClockTicks>>1))) + { + gbMemory[0xff05] = ++register_TIMA; + if(register_TIMA == 0) { + // timer overflow! + + // reload timer modulo + gbMemory[0xff05] = register_TIMA = register_TMA; + + // flag interrupt + gbMemory[0xff0f] = register_IF |= 4; + } + } + gbInternalTimer = 0xff; + return; + } + case 0x05: + gbMemory[0xff05] = register_TIMA = value; + return; + + case 0x06: + gbMemory[0xff06] = register_TMA = value; + return; + + // TIMER control + case 0x07: { + + gbTimerModeChange = (((value & 3) != (register_TAC&3)) && (value & register_TAC & 4)) ? true : false; + gbTimerOnChange = (((value ^ register_TAC) & 4) == 4) ? true : false; + + gbTimerOn = (value & 4) ? true : false; + + if (gbTimerOnChange || gbTimerModeChange) + { + gbTimerMode = value & 3; + + switch(gbTimerMode) { + case 0: + gbTimerClockTicks = GBTIMER_MODE_0_CLOCK_TICKS; + break; + case 1: + gbTimerClockTicks = GBTIMER_MODE_1_CLOCK_TICKS; + break; + case 2: + gbTimerClockTicks = GBTIMER_MODE_2_CLOCK_TICKS; + break; + case 3: + gbTimerClockTicks = GBTIMER_MODE_3_CLOCK_TICKS; + break; + } + } + + + // This looks weird, but this emulates a bug in which register_TIMA + // is increased when writing to register_TAC + // (This fixes Korodice's long-delay between menus bug). + + if (gbTimerOnChange || gbTimerModeChange) + { + bool temp = false; + + if ((gbTimerOn && !gbTimerModeChange) && (gbTimerMode & 2) && + !(gbInternalTimer & 0x80) && (gbInternalTimer & (gbTimerClockTicks>>1)) && + !(gbInternalTimer & (gbTimerClockTicks>>5))) + temp = true; + else if ((!gbTimerOn && !gbTimerModeChange && gbTimerOnChange ) && ((gbTimerTicks-1) < (gbTimerClockTicks>>1))) + temp = true; + else if (gbTimerOn && gbTimerModeChange && !gbTimerOnChange) + { + switch(gbTimerMode & 3) + { + case 0x00: + temp = false; + break; + case 0x01: + if (((gbInternalTimer & 0x82) == 2) && (gbTimerTicks>(clockTicks+1))) + temp = true; + break; + case 0x02: + if (((gbInternalTimer & 0x88) == 0x8) && (gbTimerTicks>(clockTicks+1))) + temp = true; + break; + case 0x03: + if (((gbInternalTimer & 0xA0) == 0x20) && (gbTimerTicks>(clockTicks+1))) + temp = true; + break; + } + } + + if (temp) + { + gbMemory[0xff05] = ++register_TIMA; + if((register_TIMA & 0xff) == 0) { + // timer overflow! + + // reload timer modulo + gbMemory[0xff05] = register_TIMA = register_TMA; + + // flag interrupt + gbMemory[0xff0f] = register_IF |= 4; + } + } + } + gbMemory[0xff07] = register_TAC = value; + return; + } + + case 0x0f: { + gbMemory[0xff0f] = register_IF = value; + //gbMemory[0xff0f] = register_IE |= value; + return; + } + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: { + if (gbMemory[NR52] & 0x80) { + SOUND_EVENT(address,value); + return; + } + } + + case 0x26: { + SOUND_EVENT(address,value); + return; + } + + 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: { + SOUND_EVENT(address,value); + //gbMemory[address] = value; + return; + } + + case 0x40: { + int lcdChange = (register_LCDC & 0x80) ^ (value & 0x80); + + // don't draw the window if it was not enabled and not being drawn before + if(!(register_LCDC & 0x20) && (value & 0x20) && gbWindowLine == -1 && + register_LY > register_WY) + gbWindowLine = 146; + // 007 fix : don't draw the first window's 1st line if it's enable 'too late' + // (ie. if register_LY == register_WY when enabling it) + // and move it to the next line + else if (!(register_LCDC & 0x20) && (value & 0x20) && (register_LY == register_WY)) + gbWindowLine = -2; + + + gbMemory[0xff40] = register_LCDC = value; + + + if(lcdChange) { + if((value & 0x80) && (!register_LCDCBusy)) { + + // if (!gbWhiteScreen && !gbSgbMask) + + // systemDrawScreen(); + + + + gbRegisterLYLCDCOffOn = (register_LY + 144) % 154; + + gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS - (gbSpeed ? 2 : 1); + gbLcdTicksDelayed = GBLCD_MODE_2_CLOCK_TICKS - (gbSpeed ? 1 : 0); + gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS - (gbSpeed ? 2 : 1); + gbLcdLYIncrementTicksDelayed = GBLY_INCREMENT_CLOCK_TICKS - (gbSpeed ? 1 : 0); + gbLcdMode = 2; + gbLcdModeDelayed = 2; + gbMemory[0xff41] = register_STAT = (register_STAT & 0xfc) | 2; + gbMemory[0xff44] = register_LY = 0x00; + gbInt48Signal = 0; + gbLYChangeHappened = false; + gbLCDChangeHappened = false; + gbWindowLine = 146; + oldRegister_WY = 146; + + // Fix for Namco Gallery Vol.2 + // (along with updating register_LCDC at the start of 'case 0x40') : + if(register_STAT & 0x20) + { + // send LCD interrupt only if no interrupt 48h signal... + if (!gbInt48Signal) + { + gbMemory[0xff0f] = register_IF |= 2; + } + gbInt48Signal |= 4; + } + gbCompareLYToLYC(); + + } else { + + register_LCDCBusy = clockTicks+6; + + //used to update the screen with white lines when it's off. + //(it looks strange, but it's pretty accurate) + + gbWhiteScreen = 0; + + gbScreenTicks = ((150-register_LY)*GBLY_INCREMENT_CLOCK_TICKS + + (49<<(gbSpeed ? 1 : 0))); + + // disable the screen rendering + gbScreenOn = false; + gbLcdTicks = 0; + gbLcdMode = 0; + gbLcdModeDelayed = 0; + gbMemory[0xff41] = register_STAT &= 0xfc; + gbInt48Signal = 0; + } + } + return; + } + + // STAT + case 0x41: { + //register_STAT = (register_STAT & 0x87) | + // (value & 0x7c); + gbMemory[0xff41] = register_STAT = (value & 0xf8) | (register_STAT & 0x07); // fix ? + // GB bug from Devrs FAQ + // Corrected : it happens if Lcd Mode<2, but also if LY == LYC whatever + // Lcd Mode is, and if !gbInt48Signal in all cases. The screen being off + // doesn't matter (the bug will still happen). + // That fixes 'Satoru Nakajima - F-1 Hero' crash bug. + + if((gbHardware & 5) && (((!gbInt48Signal) && (gbLcdMode<2) && (register_LCDC & 0x80)) || + (register_LY == register_LYC))) + { + gbMemory[0xff0f] = register_IF |=2; + } + + gbInt48Signal &= ((register_STAT>>3) & 0xF); + + if((register_LCDC & 0x80)) { + if ((register_STAT & 0x08) && (gbLcdMode == 0)) + { + if (!gbInt48Signal) + { + gbMemory[0xff0f] = register_IF |=2; + } + gbInt48Signal |= 1; + } + if ((register_STAT & 0x10) && (gbLcdMode == 1)) + { + if (!gbInt48Signal) + { + gbMemory[0xff0f] = register_IF |=2; + } + gbInt48Signal |= 2; + } + if ((register_STAT & 0x20) && (gbLcdMode == 2)) + { + if (!gbInt48Signal) + { + gbMemory[0xff0f] = register_IF |=2; + } + gbInt48Signal |= 4; + } + gbCompareLYToLYC(); + + gbMemory[0xff0f] = register_IF; + gbMemory[0xff41] = register_STAT; + + } + return; + } + + // SCY + case 0x42: { + int temp = -1; + + if ((gbLcdMode == 3) || (gbLcdModeDelayed == 3)) + temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - + gbLcdLYIncrementTicks); + + if (temp >=0) + { + for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) + if (temp < 300) + gbSCYLine[i] = value; + } + + else + memset(gbSCYLine, value, sizeof(gbSCYLine)); + + gbMemory[0xff42] = register_SCY = value; + return; + } + + // SCX + case 0x43: { + int temp = -1; + + if (gbLcdModeDelayed == 3) + temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - + gbLcdLYIncrementTicksDelayed); + + if (temp >=0) + { + for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) + if (temp < 300) + gbSCXLine[i] = value; + } + + else + memset(gbSCXLine, value, sizeof(gbSCXLine)); + + gbMemory[0xff43] = register_SCX = value; + return; + } + + // LY + case 0x44: { + // read only + return; + } + + // LYC + case 0x45: { + if (register_LYC != value) + { + gbMemory[0xff45] = register_LYC = value; + if(register_LCDC & 0x80) { + gbCompareLYToLYC(); + } + } + return; + } + + // DMA! + case 0x46: { + int source = value * 0x0100; + + gbCopyMemory(0xfe00, + source, + 0xa0); + gbMemory[0xff46] = register_DMA = value; + return; + } + + // BGP + case 0x47: { + + int temp = -1; + + gbMemory[0xff47] = value; + + if (gbLcdModeDelayed == 3) + temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - + gbLcdLYIncrementTicksDelayed); + + if (temp >=0) + { + for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) + if (temp < 300) + gbBgpLine[i] = value; + } + else + memset(gbBgpLine,value,sizeof(gbBgpLine)); + + gbBgp[0] = value & 0x03; + gbBgp[1] = (value & 0x0c)>>2; + gbBgp[2] = (value & 0x30)>>4; + gbBgp[3] = (value & 0xc0)>>6; + break; + } + + // OBP0 + case 0x48: { + int temp = -1; + + gbMemory[0xff48] = value; + + if (gbLcdModeDelayed == 3) + temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - + gbLcdLYIncrementTicksDelayed); + + if (temp >=0) + { + for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) + if (temp < 300) + gbObp0Line[i] = value; + } + else + memset(gbObp0Line,value,sizeof(gbObp0Line)); + + gbObp0[0] = value & 0x03; + gbObp0[1] = (value & 0x0c)>>2; + gbObp0[2] = (value & 0x30)>>4; + gbObp0[3] = (value & 0xc0)>>6; + break; + } + + // OBP1 + case 0x49: { + int temp = -1; + + gbMemory[0xff49] = value; + + if (gbLcdModeDelayed == 3) + temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - + gbLcdLYIncrementTicksDelayed); + + if (temp >=0) + { + for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) + if (temp < 300) + gbObp1Line[i] = value; + } + else + memset(gbObp1Line,value,sizeof(gbObp1Line)); + + gbObp1[0] = value & 0x03; + gbObp1[1] = (value & 0x0c)>>2; + gbObp1[2] = (value & 0x30)>>4; + gbObp1[3] = (value & 0xc0)>>6; + break; + } + + // WY + case 0x4a: + gbMemory[0xff4a] = register_WY = value; + if ((register_LY <= register_WY) && ((gbWindowLine < 0) || (gbWindowLine>=144))) + { + gbWindowLine = -1; + oldRegister_WY = register_WY; + } + return; + + // WX + case 0x4b: + gbMemory[0xff4b] = register_WX = value; + return; + + // KEY1 + case 0x4d: { + if(gbCgbMode) { + gbMemory[0xff4d] = (gbMemory[0xff4d] & 0x80) | (value & 1) | 0x7e; + return; + } + } + break; + + // VBK + case 0x4f: { + if(gbCgbMode) { + value = value & 1; + if(value == gbVramBank) + return; + + int vramAddress = value * 0x2000; + gbMemoryMap[0x08] = &gbVram[vramAddress]; + gbMemoryMap[0x09] = &gbVram[vramAddress + 0x1000]; + + gbVramBank = value; + register_VBK = value; + } + return; + } + break; + + // BOOTROM disable register (also gbCgbMode enabler if value & 0x10 ?) + case 0x50 : + { + if (useBios && inBios && !skipBios && (value & 1)) + { + gbMemoryMap[0x00] = &gbRom[0x0000]; + memcpy ((u8 *)(gbRom+0x100), (u8 *)(gbMemory + 0x100), 0xF00); + inBios = false; + } + } + + // HDMA1 + case 0x51: { + if(gbCgbMode) { + if(value > 0x7f && value < 0xa0) + value = 0; + + gbHdmaSource = (value << 8) | (gbHdmaSource & 0xf0); + + register_HDMA1 = value; + return; + } + } + break; + + // HDMA2 + case 0x52: { + if(gbCgbMode) { + value = value & 0xf0; + + gbHdmaSource = (gbHdmaSource & 0xff00) | (value); + + register_HDMA2 = value; + return; + } + } + break; + + // HDMA3 + case 0x53: { + if(gbCgbMode) { + value = value & 0x1f; + gbHdmaDestination = (value << 8) | (gbHdmaDestination & 0xf0); + gbHdmaDestination |= 0x8000; + register_HDMA3 = value; + return; + } + } + break; + + // HDMA4 + case 0x54: { + if(gbCgbMode) { + value = value & 0xf0; + gbHdmaDestination = (gbHdmaDestination & 0x1f00) | value; + gbHdmaDestination |= 0x8000; + register_HDMA4 = value; + return; + } + } + break; + + // HDMA5 + case 0x55: { + + if(gbCgbMode) { + gbHdmaBytes = 16 + (value & 0x7f) * 16; + if(gbHdmaOn) { + if(value & 0x80) { + gbMemory[0xff55] = register_HDMA5 = (value & 0x7f); + } else { + register_HDMA5 = 0xff; + gbHdmaOn = 0; + } + } else { + if(value & 0x80) { + gbHdmaOn = 1; + gbMemory[0xff55] = register_HDMA5 = value & 0x7f; + if(gbLcdModeDelayed == 0) + gbDoHdma(); + } else { + // we need to take the time it takes to complete the transfer into + // account... according to GB DEV FAQs, the setup time is the same + // for single and double speed, but the actual transfer takes the + // same time + if(gbSpeed) + gbDmaTicks = 2+16 * ((value & 0x7f) +1); + else + gbDmaTicks = 1+8 * ((value & 0x7f)+1); + + gbCopyMemory((gbHdmaDestination & 0x1ff0) | 0x8000, + gbHdmaSource & 0xfff0, + gbHdmaBytes); + gbHdmaDestination += gbHdmaBytes; + gbHdmaSource += gbHdmaBytes; + + gbMemory[0xff51] = register_HDMA1 = 0xff;// = (gbHdmaSource >> 8) & 0xff; + gbMemory[0xff52] = register_HDMA2 = 0xff;// = gbHdmaSource & 0xf0; + gbMemory[0xff53] = register_HDMA3 = 0xff;// = ((gbHdmaDestination - 0x8000) >> 8) & 0x1f; + gbMemory[0xff54] = register_HDMA4 = 0xff;// = gbHdmaDestination & 0xf0; + gbMemory[0xff55] = register_HDMA5 = 0xff; + } + } + return; + } + } + break; + + // BCPS + case 0x68: { + if(gbCgbMode) { + int paletteIndex = (value & 0x3f) >> 1; + int paletteHiLo = (value & 0x01); + + gbMemory[0xff68] = value; + + gbMemory[0xff69] = (paletteHiLo ? + (gbPalette[paletteIndex] >> 8) : + (gbPalette[paletteIndex] & 0x00ff)); + return; + } + } + break; + + // BCPD + case 0x69: { + if(gbCgbMode) { + int v = gbMemory[0xff68]; + int paletteIndex = (v & 0x3f) >> 1; + int paletteHiLo = (v & 0x01); + + // No access to gbPalette during mode 3 (Color Panel Demo) + if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || + (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || + ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || + ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) + { + gbMemory[0xff69] = value; + gbPalette[paletteIndex] = (paletteHiLo ? + ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : + ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; + } + + + if(gbMemory[0xff68] & 0x80) { + int index = ((gbMemory[0xff68] & 0x3f) + 1) & 0x3f; + + gbMemory[0xff68] = (gbMemory[0xff68] & 0x80) | index; + gbMemory[0xff69] = (index & 1 ? + (gbPalette[index>>1] >> 8) : + (gbPalette[index>>1] & 0x00ff)); + } + return; + } + } + break; + + // OCPS + case 0x6a: { + if(gbCgbMode) { + int paletteIndex = (value & 0x3f) >> 1; + int paletteHiLo = (value & 0x01); + + paletteIndex += 32; + + gbMemory[0xff6a] = value; + + gbMemory[0xff6b] = (paletteHiLo ? + (gbPalette[paletteIndex] >> 8) : + (gbPalette[paletteIndex] & 0x00ff)); + return; + } + } + break; + + // OCPD + case 0x6b: { + + if(gbCgbMode) { + int v = gbMemory[0xff6a]; + int paletteIndex = (v & 0x3f) >> 1; + int paletteHiLo = (v & 0x01); + + paletteIndex += 32; + + // No access to gbPalette during mode 3 (Color Panel Demo) + if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || + (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || + ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || + ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) + { + gbMemory[0xff6b] = value; + gbPalette[paletteIndex] = (paletteHiLo ? + ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : + ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; + } + + if(gbMemory[0xff6a] & 0x80) { + int index = ((gbMemory[0xff6a] & 0x3f) + 1) & 0x3f; + + gbMemory[0xff6a] = (gbMemory[0xff6a] & 0x80) | index; + + gbMemory[0xff6b] = (index & 1 ? + (gbPalette[(index>>1) + 32] >> 8) : + (gbPalette[(index>>1) + 32] & 0x00ff)); + } + return; + } + } + break; + + case 0x6c: { + gbMemory[0xff6c] = 0xfe | value; + return; + } + + + // SVBK + case 0x70: { + if(gbCgbMode) { + value = value & 7; + + int bank = value; + if(value == 0) + bank = 1; + + if(bank == gbWramBank) + return; + + int wramAddress = bank * 0x1000; + gbMemoryMap[0x0d] = &gbWram[wramAddress]; + + gbWramBank = bank; + gbMemory[0xff70] = register_SVBK = value; + return; + } + } + + case 0x75:{ + gbMemory[0xff75] = 0x8f | value; + return; + } + + case 0xff: { + gbMemory[0xffff] = register_IE = value; + return; + } + } + + if(address < 0xff80) + { + gbMemory[address] = value; + return; + } + + gbMemory[address] = value; +} + +u8 gbReadOpcode(register u16 address) +{ + if(gbCheatMap[address]) + return gbCheatRead(address); + + if(address < 0x8000) + return gbMemoryMap[address>>12][address&0x0fff]; + + if(address < 0xa000) + { + // A lot of 'ugly' checks... But only way to emulate this particular behaviour... + if (((gbHardware & 0xa) && ((gbLcdModeDelayed !=3) || ((register_LY == 0) && + (gbScreenOn==false) && (register_LCDC & 0x80)) && + (gbLcdLYIncrementTicksDelayed ==(GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS)))) || + ((gbHardware & 0x5) && (gbLcdModeDelayed !=3) && + ((gbLcdMode !=3) || ((register_LY == 0) && ((gbScreenOn==false) && + (register_LCDC & 0x80)) && + (gbLcdLYIncrementTicks ==(GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS)))))) + return gbMemoryMap[address>>12][address&0x0fff]; + return 0xff; + } + + // Used for the mirroring of 0xC000 in 0xE000 + if ((address >= 0xe000) && (address < 0xfe00)) + address &= ~0x2000; + + switch(address & 0xf000) { + case 0x0a: + case 0x0b: + if(mapperReadRAM) + return mapperReadRAM(address); + break; + case 0x0f: + if(address > 0xff00) { + switch(address & 0x00ff) { + case 0x02: + return (gbMemory[0xff02]); + case 0x03: + return (0xff); + case 0x04: + return register_DIV; + case 0x05: + return register_TIMA; + case 0x06: + return register_TMA; + case 0x07: + return (0xf8 | register_TAC); + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + return (0xff); + case 0x0f: + return (0xe0 | gbMemory[0xff0f]); + case 0x40: + return register_LCDC; + case 0x41: + // This is a GB/C only bug (ie. not GBA/SP). + if ((gbHardware & 7) && (gbLcdMode == 2) && (gbLcdModeDelayed == 1) && (!gbSpeed)) + return (0x80 | gbMemory[0xff41] & 0xFC); + else + return (0x80 | gbMemory[0xff41]); + case 0x42: + return register_SCY; + case 0x43: + return register_SCX; + case 0x44: + if (((gbHardware & 7) && ((gbLcdMode == 1) && (gbLcdTicks == 0x71))) || + (!(register_LCDC && 0x80))) + return 0; + else + return register_LY; + case 0x45: + return register_LYC; + case 0x46: + return register_DMA; + case 0x4a: + return register_WY; + case 0x4b: + return register_WX; + case 0x4c: + return 0xff; + case 0x4f: + return (0xfe | register_VBK); + case 0x51: + return register_HDMA1; + case 0x52: + return register_HDMA2; + case 0x53: + return register_HDMA3; + case 0x54: + return register_HDMA4; + case 0x55: + return register_HDMA5; + case 0x68: + case 0x6a: + if (gbCgbMode) + return (0x40 | gbMemory[address]); + else + return 0xc0; + case 0x69: + case 0x6b: + if (gbCgbMode) + { + // No access to gbPalette during mode 3 (Color Panel Demo) + if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || + (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || + ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || + ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) + return (gbMemory[address]); + else + return 0xff; + } + else + return 0xff; + case 0x70: + if (gbCgbMode) + return (0xf8 | register_SVBK); + else + return 0xff; + case 0xff: + return register_IE; + } + } + // OAM not accessible during mode 2 & 3. + if(((address >= 0xfe00) && (address<0xfea0)) && + ((gbLcdMode | gbLcdModeDelayed) &2)) + return 0xff; + break; + } + + if ((address >= 0xfea0) && (address < 0xff00)) + { + if (gbHardware & 1) + return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0x00 : 0xff ); + else if (gbHardware & 2) + return gbMemoryMap[address>>12][address & 0x0fff]; + else if (gbHardware & 4) + return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0xff : 0x00 ); + else if (gbHardware & 8) + return ((address & 0xf0) |((address & 0xf0)>>4)); + } + + return gbMemoryMap[address>>12][address & 0x0fff]; +} + +u8 gbReadMemory(register u16 address) +{ + if(gbCheatMap[address]) + return gbCheatRead(address); + + + if(address < 0x8000) + return gbMemoryMap[address>>12][address&0x0fff]; + + if(address < 0xa000) + { + // A lot of 'ugly' checks... But only way to emulate this particular behaviour... + if (((gbHardware & 0xa) && ((gbLcdModeDelayed !=3) || ((register_LY == 0) && + (gbScreenOn==false) && (register_LCDC & 0x80)) && + (gbLcdLYIncrementTicksDelayed ==(GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS)))) || + ((gbHardware & 0x5) && (gbLcdModeDelayed !=3) && + ((gbLcdMode !=3) || ((register_LY == 0) && ((gbScreenOn==false) && + (register_LCDC & 0x80)) && + (gbLcdLYIncrementTicks ==(GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS)))))) + return gbMemoryMap[address>>12][address&0x0fff]; + return 0xff; + } + + if ((address >= 0xe000) && (address < 0xfe00)) + address &= ~0x2000; + + if(address < 0xc000) { +#ifndef FINAL_VERSION + if(memorydebug) { + log("Memory register read %04x PC=%04x\n", + address, + PC.W); + } +#endif + + // for the 2kb ram limit (fixes crash in shawu's story + // but now its sram test fails, as the it expects 8kb and not 2kb... + // So use the 'genericflashcard' option to fix it). + if (address<=(0xa000+gbRamSizeMask)) + { + if(mapperReadRAM) + return mapperReadRAM(address); + return gbMemoryMap[address>>12][address & 0x0fff]; + } + return 0xff; + } + + if(address >= 0xff00) { + if ( address >= 0xFF10 && address <= 0xFF3F ) + return gbSoundRead( address ); + + switch(address & 0x00ff) { + case 0x00: + { + if(gbSgbMode) { + gbSgbReadingController |= 4; + gbSgbResetPacketState(); + } + + int b = gbMemory[0xff00]; + + if((b & 0x30) == 0x20) { + b &= 0xf0; + + int joy = 0; + if(gbSgbMode && gbSgbMultiplayer) { + switch(gbSgbNextController) { + case 0x0f: + joy = 0; + break; + case 0x0e: + joy = 1; + break; + case 0x0d: + joy = 2; + break; + case 0x0c: + joy = 3; + break; + default: + joy = 0; + } + } + int joystate = gbJoymask[joy]; + if(!(joystate & 128)) + b |= 0x08; + if(!(joystate & 64)) + b |= 0x04; + if(!(joystate & 32)) + b |= 0x02; + if(!(joystate & 16)) + b |= 0x01; + + gbMemory[0xff00] = b; + } else if((b & 0x30) == 0x10) { + b &= 0xf0; + + int joy = 0; + if(gbSgbMode && gbSgbMultiplayer) { + switch(gbSgbNextController) { + case 0x0f: + joy = 0; + break; + case 0x0e: + joy = 1; + break; + case 0x0d: + joy = 2; + break; + case 0x0c: + joy = 3; + break; + default: + joy = 0; + } + } + int joystate = gbJoymask[joy]; + if(!(joystate & 8)) + b |= 0x08; + if(!(joystate & 4)) + b |= 0x04; + if(!(joystate & 2)) + b |= 0x02; + if(!(joystate & 1)) + b |= 0x01; + + gbMemory[0xff00] = b; + } else { + if(gbSgbMode && gbSgbMultiplayer) { + gbMemory[0xff00] = 0xf0 | gbSgbNextController; + } else { + gbMemory[0xff00] = 0xff; + } + } + } + return gbMemory[0xff00]; + break; + case 0x01: + return gbMemory[0xff01]; + case 0x02: + return (gbMemory[0xff02]); + case 0x04: + return register_DIV; + case 0x05: + return register_TIMA; + case 0x06: + return register_TMA; + case 0x07: + return (0xf8 | register_TAC); + case 0x0f: + return (0xe0 | gbMemory[0xff0f]); + 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: + if ((gbMemory[NR30] & 0x80) && (gbMemory[NR34] & 0x80)) + return 0xFF; + else + return gbMemoryMap[address>>12][address & 0x0fff]; + case 0x40: + return register_LCDC; + case 0x41: + // This is a GB/C only bug (ie. not GBA/SP). + if ((gbHardware & 7) && (gbLcdMode == 2) && (gbLcdModeDelayed == 1) && (!gbSpeed)) + return (0x80 | gbMemory[0xff41] & 0xFC); + else + return (0x80 | gbMemory[0xff41]); + case 0x42: + return register_SCY; + case 0x43: + return register_SCX; + case 0x44: + if (((gbHardware & 7) && ((gbLcdMode == 1) && (gbLcdTicks == 0x71))) || + (!(register_LCDC && 0x80))) + return (0); + else + return register_LY; + case 0x45: + return register_LYC; + case 0x46: + return register_DMA; + case 0x4a: + return register_WY; + case 0x4b: + return register_WX; + case 0x4f: + return (0xfe | register_VBK); + case 0x51: + return register_HDMA1; + case 0x52: + return register_HDMA2; + case 0x53: + return register_HDMA3; + case 0x54: + return register_HDMA4; + case 0x55: + return register_HDMA5; + case 0x68: + case 0x6a: + if (gbCgbMode) + return (0x40 | gbMemory[address]); + else + return 0xc0; + case 0x69: + case 0x6b: + if (gbCgbMode) + { + // No access to gbPalette during mode 3 (Color Panel Demo) + if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || + (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || + ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || + ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) + return (gbMemory[address]); + else + return 0xff; + } + else + return 0xff; + case 0x70: + if (gbCgbMode) + return (0xf8 | register_SVBK); + else + return 0xff; + case 0xff: + return register_IE; + } + } + // OAM not accessible during mode 2 & 3. + if(((address >= 0xfe00) && (address<0xfea0)) && + (((gbLcdMode | gbLcdModeDelayed) &2) && + (!(gbSpeed && (gbHardware & 0x2) && !(gbLcdModeDelayed & 2) && (gbLcdMode == 2))) || + (gbSpeed && (gbHardware & 0x2) && (gbLcdModeDelayed == 0) && (gbLcdTicksDelayed == (GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]))))) + return 0xff; + + if ((address >= 0xfea0) && (address < 0xff00)) + { + if (gbHardware & 1) + return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0x00 : 0xff ); + else if (gbHardware & 2) + return gbMemoryMap[address>>12][address & 0x0fff]; + else if (gbHardware & 4) + return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0xff : 0x00 ); + else if (gbHardware & 8) + return ((address & 0xf0) |((address & 0xf0)>>4)); + } + + return gbMemoryMap[address>>12][address & 0x0fff]; +} + +void gbVblank_interrupt() +{ + gbCheatWrite(false); // Emulates GS codes. + gbMemory[0xff0f] = register_IF &= 0xfe; + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = 0x40; +} + +void gbLcd_interrupt() +{ + gbMemory[0xff0f] = register_IF &= 0xfd; + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = 0x48; +} + +void gbTimer_interrupt() +{ + gbMemory[0xff0f] = register_IF &= 0xfb; + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = 0x50; +} + +void gbSerial_interrupt() +{ + gbMemory[0xff0f] = register_IF &= 0xf7; + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = 0x58; +} + +void gbJoypad_interrupt() +{ + gbMemory[0xff0f] = register_IF &= 0xef; + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = 0x60; +} + +void gbSpeedSwitch() +{ + gbBlackScreen = true; + if(gbSpeed == 0) { + gbSpeed = 1; + GBLCD_MODE_0_CLOCK_TICKS = 51 * 2; + GBLCD_MODE_1_CLOCK_TICKS = 1140 * 2; + GBLCD_MODE_2_CLOCK_TICKS = 20 * 2; + GBLCD_MODE_3_CLOCK_TICKS = 43 * 2; + GBLY_INCREMENT_CLOCK_TICKS = 114 * 2; + GBDIV_CLOCK_TICKS = 64; + GBTIMER_MODE_0_CLOCK_TICKS = 256; + GBTIMER_MODE_1_CLOCK_TICKS = 4; + GBTIMER_MODE_2_CLOCK_TICKS = 16; + GBTIMER_MODE_3_CLOCK_TICKS = 64; + GBSERIAL_CLOCK_TICKS = 128 * 2; + gbLcdTicks *= 2; + gbLcdTicksDelayed *=2; + gbLcdTicksDelayed--; + gbLcdLYIncrementTicks *= 2; + gbLcdLYIncrementTicksDelayed *= 2; + gbLcdLYIncrementTicksDelayed--; + gbSerialTicks *= 2; + //SOUND_CLOCK_TICKS = soundQuality * 24 * 2; + //soundTicks *= 2; + gbLine99Ticks = 3; + } else { + gbSpeed = 0; + GBLCD_MODE_0_CLOCK_TICKS = 51; + GBLCD_MODE_1_CLOCK_TICKS = 1140; + GBLCD_MODE_2_CLOCK_TICKS = 20; + GBLCD_MODE_3_CLOCK_TICKS = 43; + GBLY_INCREMENT_CLOCK_TICKS = 114; + GBDIV_CLOCK_TICKS = 64; + GBTIMER_MODE_0_CLOCK_TICKS = 256; + GBTIMER_MODE_1_CLOCK_TICKS = 4; + GBTIMER_MODE_2_CLOCK_TICKS = 16; + GBTIMER_MODE_3_CLOCK_TICKS = 64; + GBSERIAL_CLOCK_TICKS = 128; + gbLcdTicks >>= 1; + gbLcdTicksDelayed++; + gbLcdTicksDelayed >>=1; + gbLcdLYIncrementTicks >>= 1; + gbLcdLYIncrementTicksDelayed++; + gbLcdLYIncrementTicksDelayed >>= 1; + gbSerialTicks /= 2; + //SOUND_CLOCK_TICKS = soundQuality * 24; + //soundTicks /= 2; + gbLine99Ticks = 1; + if (gbHardware & 8) + gbLine99Ticks++; + } + gbDmaTicks += (134)*GBLY_INCREMENT_CLOCK_TICKS + (37<<(gbSpeed ? 1 : 0)); +} + +bool CPUIsGBBios(const char * file) +{ + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".gb") == 0) + return true; + if(_stricmp(p, ".bin") == 0) + return true; + if(_stricmp(p, ".bios") == 0) + return true; + if(_stricmp(p, ".rom") == 0) + return true; + } + } + + return false; +} + +void gbCPUInit(const char *biosFileName, bool useBiosFile) +{ + useBios = false; + if (useBiosFile) + { + int size = 0x100; + if(utilLoad(biosFileName, + CPUIsGBBios, + bios, + size)) { + if(size == 0x100) + useBios = true; + else + systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file size")); + } + } +} + +void gbGetHardwareType() +{ + gbCgbMode = 0; + gbSgbMode = 0; + if(gbRom[0x143] & 0x80) { + if((gbEmulatorType == 0) || + gbEmulatorType == 1 || + gbEmulatorType == 4) { + gbCgbMode = 1; + } + } + + if((gbCgbMode == 0 ) && (gbRom[0x146] == 0x03)) { + if(gbEmulatorType == 0 || + gbEmulatorType == 2 || + gbEmulatorType == 5) + gbSgbMode = 1; + } + + gbHardware = 1; // GB + if (((gbCgbMode == 1) && (gbEmulatorType == 0)) || (gbEmulatorType == 1)) + gbHardware = 2; // GBC + else if (((gbSgbMode == 1) && (gbEmulatorType == 0)) || (gbEmulatorType == 2) || (gbEmulatorType == 5)) + gbHardware = 4; // SGB(2) + else if (gbEmulatorType == 4) + gbHardware = 8; // GBA + + gbGBCColorType = 0; + if (gbHardware & 8) // If GBA is selected, choose the GBA default settings. + gbGBCColorType = 2; // (0 = GBC, 1 = GBA, 2 = GBASP) +} + +void gbReset() +{ + gbGetHardwareType(); + + oldRegister_WY = 146; + gbInterruptLaunched = 0; + + if(gbCgbMode == 1) { + if (gbVram == NULL) + gbVram = (u8 *)malloc(0x4000); + if (gbWram == NULL) + gbWram = (u8 *)malloc(0x8000); + memset(gbVram,0,0x4000); + memset(gbPalette,0, 2*128); + } + else + { + if(gbVram != NULL) { + free(gbVram); + gbVram = NULL; + } + if(gbWram != NULL) { + free(gbWram); + gbWram = NULL; + } + } + + gbLYChangeHappened = false; + gbLCDChangeHappened = false; + gbBlackScreen = false; + gbInterruptWait = 0; + gbDmaTicks = 0; + clockTicks = 0; + + if(gbSpeed) { + gbSpeedSwitch(); + gbMemory[0xff4d] = 0; + } + + // clean Wram + // This kinda emulates the startup state of Wram on GB/C (not very accurate, + // but way closer to the reality than filling it with 00es or FFes). + // On GBA/GBASP, it's kinda filled with random data. + // In all cases, most of the 2nd bank is filled with 00s. + // The starting data are important for some 'buggy' games, like Buster Brothers or + // Karamuchou ha Oosawagi!. + if (gbMemory != NULL) + { + memset(gbMemory,0xff, 65536); + for (int temp = 0xC000; temp < 0xE000; temp++) + if ((temp & 0x8) ^((temp & 0x800)>>8)) + { + if ((gbHardware & 0x02) && (gbGBCColorType == 0)) + gbMemory[temp] = 0x0; + else + gbMemory[temp] = 0x0f; + } + + else + gbMemory[temp] = 0xff; + } + + + + // clean LineBuffer + if (gbLineBuffer != NULL) + memset(gbLineBuffer, 0, sizeof(gbLineBuffer)); + // clean Pix + if (pix != NULL) + memset(pix, 0, sizeof(pix)); + // clean Vram + if (gbVram != NULL) + memset(gbVram, 0, 0x4000); + // clean Wram 2 + // This kinda emulates the startup state of Wram on GBC (not very accurate, + // but way closer to the reality than filling it with 00es or FFes). + // On GBA/GBASP, it's kinda filled with random data. + // In all cases, most of the 2nd bank is filled with 00s. + // The starting data are important for some 'buggy' games, like Buster Brothers or + // Karamuchou ha Oosawagi! + if (gbWram != NULL) + { + for (int i = 0; i<8; i++) + if (i != 2) + memcpy ((u16 *)(gbWram+i*0x1000), (u16 *)(gbMemory+0xC000), 0x1000); + } + + memset(gbSCYLine,0,sizeof(gbSCYLine)); + memset(gbSCXLine,0,sizeof(gbSCXLine)); + memset(gbBgpLine,0xfc,sizeof(gbBgpLine)); + if (gbHardware & 5) + { + memset(gbObp0Line,0xff,sizeof(gbObp0Line)); + memset(gbObp1Line,0xff,sizeof(gbObp1Line)); + } + else + { + memset(gbObp0Line,0x0,sizeof(gbObp0Line)); + memset(gbObp1Line,0x0,sizeof(gbObp1Line)); + } + memset(gbSpritesTicks,0x0,sizeof(gbSpritesTicks)); + + SP.W = 0xfffe; + AF.W = 0x01b0; + BC.W = 0x0013; + DE.W = 0x00d8; + HL.W = 0x014d; + PC.W = 0x0100; + IFF = 0; + gbInt48Signal = 0; + + register_TIMA = 0; + register_TMA = 0; + register_TAC = 0; + gbMemory[0xff0f] = register_IF = 1; + gbMemory[0xff40] = register_LCDC = 0x91; + gbMemory[0xff47] = 0xfc; + + if (gbCgbMode) + gbMemory[0xff4d] = 0x7e; + else + gbMemory[0xff4d] = 0xff; + + if (!gbCgbMode) + gbMemory[0xff70] = gbMemory[0xff74] = 0xff; + + if (gbCgbMode) + gbMemory[0xff56] = 0x3e; + else + gbMemory[0xff56] = 0xff; + + register_SCY = 0; + register_SCX = 0; + register_LYC = 0; + register_DMA = 0xff; + register_WY = 0; + register_WX = 0; + register_VBK = 0; + register_HDMA1 = 0xff; + register_HDMA2 = 0xff; + register_HDMA3 = 0xff; + register_HDMA4 = 0xff; + register_HDMA5 = 0xff; + register_SVBK = 0; + register_IE = 0; + + if (gbCgbMode) + gbMemory[0xff02] = 0x7c; + else + gbMemory[0xff02] = 0x7e; + + gbMemory[0xff03] = 0xff; + int i; + for (i = 0x8; i<0xf; i++) + gbMemory[0xff00+i] = 0xff; + + gbMemory[0xff13] = 0xff; + gbMemory[0xff15] = 0xff; + gbMemory[0xff18] = 0xff; + gbMemory[0xff1d] = 0xff; + gbMemory[0xff1f] = 0xff; + + for (i = 0x27; i<0x30; i++) + gbMemory[0xff00+i] = 0xff; + + gbMemory[0xff4c] = 0xff; + gbMemory[0xff4e] = 0xff; + gbMemory[0xff50] = 0xff; + + for (i = 0x57; i<0x68; i++) + gbMemory[0xff00+i] = 0xff; + + for (i = 0x5d; i<0x70; i++) + gbMemory[0xff00+i] = 0xff; + + gbMemory[0xff71] = 0xff; + + for (i = 0x78; i<0x80; i++) + gbMemory[0xff00+i] = 0xff; + + if (gbHardware & 0xa) + { + + if (gbHardware & 2) + { + AF.W = 0x1180; + BC.W = 0x0000; + } + else + { + AF.W = 0x1100; + BC.W = 0x0100; // GBA/SP have B = 0x01 (which means GBC & GBA/SP bootrom are different !) + } + + gbMemory[0xff26] = 0xf1; + if (gbCgbMode) + { + + gbMemory[0xff31] = 0xff; + gbMemory[0xff33] = 0xff; + gbMemory[0xff35] = 0xff; + gbMemory[0xff37] = 0xff; + gbMemory[0xff39] = 0xff; + gbMemory[0xff3b] = 0xff; + gbMemory[0xff3d] = 0xff; + + gbMemory[0xff44] = register_LY = 0x90; + gbDivTicks = 0x19 + ((gbHardware & 2) >> 1); + gbInternalTimer = 0x58 + ((gbHardware & 2) >> 1); + gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS - + (register_LY-0x8F)*GBLY_INCREMENT_CLOCK_TICKS + 72 + ((gbHardware & 2) >> 1); + gbLcdLYIncrementTicks = 72 + ((gbHardware & 2) >> 1); + gbMemory[0xff04] = register_DIV = 0x1E; + } + else + { + gbMemory[0xff44] = register_LY = 0x94; + gbDivTicks = 0x22 + ((gbHardware & 2) >> 1); + gbInternalTimer = 0x61 + ((gbHardware & 2) >> 1); + gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS - + (register_LY-0x8F)*GBLY_INCREMENT_CLOCK_TICKS + 25 + ((gbHardware & 2) >> 1); + gbLcdLYIncrementTicks = 25 + ((gbHardware & 2) >> 1); + gbMemory[0xff04] = register_DIV = 0x26; + } + + + DE.W = 0xff56; + HL.W = 0x000d; + + register_HDMA5 = 0xff; + gbMemory[0xff68] = 0xc0; + gbMemory[0xff6a] = 0xc0; + + + gbMemory[0xff41] = register_STAT = 0x81; + gbLcdMode = 1; + } + else + { + if (gbHardware & 4) + { + if(gbEmulatorType == 5) + AF.W = 0xffb0; + else + AF.W = 0x01b0; + BC.W = 0x0013; + DE.W = 0x00d8; + HL.W = 0x014d; + } + gbDivTicks = 14; + gbInternalTimer = gbDivTicks--; + gbMemory[0xff04] = register_DIV = 0xAB; + gbMemory[0xff41] = register_STAT = 0x85; + gbMemory[0xff44] = register_LY = 0x00; + gbLcdTicks = 15; + gbLcdLYIncrementTicks = 114+gbLcdTicks; + gbLcdMode = 1; + + // used for the handling of the gb Boot Rom + if ((gbHardware & 5) && (bios != NULL) && useBios && !skipBios) + { + memcpy ((u8 *)(gbMemory), (u8 *)(gbRom), 0x1000); + memcpy ((u8 *)(gbMemory), (u8 *)(bios), 0x100); + gbWhiteScreen = 0; + + gbInternalTimer = 0x3e; + gbDivTicks = 0x3f; + gbMemory[0xff04] = register_DIV = 0x00; + PC.W = 0x0000; + register_LCDC = 0x11; + gbScreenOn = false; + gbLcdTicks = 0; + gbLcdMode = 0; + gbLcdModeDelayed = 0; + gbMemory[0xff41] = register_STAT &= 0xfc; + gbInt48Signal = 0; + gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS; + } + } + + gbLine99Ticks = 1; + if (gbHardware & 8) + gbLine99Ticks++; + + gbLcdModeDelayed = gbLcdMode; + gbLcdTicksDelayed = gbLcdTicks+1; + gbLcdLYIncrementTicksDelayed = gbLcdLYIncrementTicks+1; + + + gbTimerModeChange = false; + gbTimerOnChange = false; + gbTimerOn = false; + + if(gbCgbMode) { + for (int i = 0; i<0x20; i++) + gbPalette[i] = 0x7fff; + + // This is just to show that the starting values of the OBJ palettes are different + // between the 3 consoles, and that they 'kinda' stay the same at each reset + // (they can slightly change, somehow (randomly?)). + // You can check the effects of gbGBCColorType on the "Vila Caldan Color" gbc demo. + // Note that you could also check the Div register to check on which system the game + // is running (GB,GBC and GBA(SP) have different startup values). + // Unfortunatly, I don't have any SGB system, so I can't get their starting values. + + if (gbGBCColorType == 0) // GBC Hardware + { + gbPalette[0x20] = 0x0600; + gbPalette[0x21] = 0xfdf3; + gbPalette[0x22] = 0x041c; + gbPalette[0x23] = 0xf5db; + gbPalette[0x24] = 0x4419; + gbPalette[0x25] = 0x57ea; + gbPalette[0x26] = 0x2808; + gbPalette[0x27] = 0x9b75; + gbPalette[0x28] = 0x129b; + gbPalette[0x29] = 0xfce0; + gbPalette[0x2a] = 0x22da; + gbPalette[0x2b] = 0x4ac5; + gbPalette[0x2c] = 0x2d71; + gbPalette[0x2d] = 0xf0c2; + gbPalette[0x2e] = 0x5137; + gbPalette[0x2f] = 0x2d41; + gbPalette[0x30] = 0x6b2d; + gbPalette[0x31] = 0x2215; + gbPalette[0x32] = 0xbe0a; + gbPalette[0x33] = 0xc053; + gbPalette[0x34] = 0xfe5f; + gbPalette[0x35] = 0xe000; + gbPalette[0x36] = 0xbe10; + gbPalette[0x37] = 0x914d; + gbPalette[0x38] = 0x7f91; + gbPalette[0x39] = 0x02b5; + gbPalette[0x3a] = 0x77ac; + gbPalette[0x3b] = 0x14e5; + gbPalette[0x3c] = 0xcf89; + gbPalette[0x3d] = 0xa03d; + gbPalette[0x3e] = 0xfd50; + gbPalette[0x3f] = 0x91ff; + } + else if (gbGBCColorType == 1) // GBA Hardware + { + gbPalette[0x20] = 0xbe00; + gbPalette[0x21] = 0xfdfd; + gbPalette[0x22] = 0xbd69; + gbPalette[0x23] = 0x7baf; + gbPalette[0x24] = 0xf5ff; + gbPalette[0x25] = 0x3f8f; + gbPalette[0x26] = 0xcee5; + gbPalette[0x27] = 0x5bf7; + gbPalette[0x28] = 0xb35b; + gbPalette[0x29] = 0xef97; + gbPalette[0x2a] = 0xef9f; + gbPalette[0x2b] = 0x97f7; + gbPalette[0x2c] = 0x82bf; + gbPalette[0x2d] = 0x9f3d; + gbPalette[0x2e] = 0xddde; + gbPalette[0x2f] = 0xbad5; + gbPalette[0x30] = 0x3cba; + gbPalette[0x31] = 0xdfd7; + gbPalette[0x32] = 0xedea; + gbPalette[0x33] = 0xfeda; + gbPalette[0x34] = 0xf7f9; + gbPalette[0x35] = 0xfdee; + gbPalette[0x36] = 0x6d2f; + gbPalette[0x37] = 0xf0e6; + gbPalette[0x38] = 0xf7f0; + gbPalette[0x39] = 0xf296; + gbPalette[0x3a] = 0x3bf1; + gbPalette[0x3b] = 0xe211; + gbPalette[0x3c] = 0x69ba; + gbPalette[0x3d] = 0x3d0d; + gbPalette[0x3e] = 0xdfd3; + gbPalette[0x3f] = 0xa6ba; + } + else if (gbGBCColorType == 2) // GBASP Hardware + { + gbPalette[0x20] = 0x9c00; + gbPalette[0x21] = 0x6340; + gbPalette[0x22] = 0x10c6; + gbPalette[0x23] = 0xdb97; + gbPalette[0x24] = 0x7622; + gbPalette[0x25] = 0x3e57; + gbPalette[0x26] = 0x2e12; + gbPalette[0x27] = 0x95c3; + gbPalette[0x28] = 0x1095; + gbPalette[0x29] = 0x488c; + gbPalette[0x2a] = 0x8241; + gbPalette[0x2b] = 0xde8c; + gbPalette[0x2c] = 0xfabc; + gbPalette[0x2d] = 0x0e81; + gbPalette[0x2e] = 0x7675; + gbPalette[0x2f] = 0xfdec; + gbPalette[0x30] = 0xddfd; + gbPalette[0x31] = 0x5995; + gbPalette[0x32] = 0x066a; + gbPalette[0x33] = 0xed1e; + gbPalette[0x34] = 0x1e84; + gbPalette[0x35] = 0x1d14; + gbPalette[0x36] = 0x11c3; + gbPalette[0x37] = 0x2749; + gbPalette[0x38] = 0xa727; + gbPalette[0x39] = 0x6266; + gbPalette[0x3a] = 0xe27b; + gbPalette[0x3b] = 0xe3fc; + gbPalette[0x3c] = 0x1f76; + gbPalette[0x3d] = 0xf158; + gbPalette[0x3e] = 0x468e; + gbPalette[0x3f] = 0xa540; + } + } else { + if(gbSgbMode) { + for(int i = 0; i < 8; i++) + gbPalette[i] = systemGbPalette[gbPaletteOption*8+i]; + + } + for(int i = 0; i < 8; i++) + gbPalette[i] = systemGbPalette[gbPaletteOption*8+i]; + } + + GBTIMER_MODE_0_CLOCK_TICKS = 256; + GBTIMER_MODE_1_CLOCK_TICKS = 4; + GBTIMER_MODE_2_CLOCK_TICKS = 16; + GBTIMER_MODE_3_CLOCK_TICKS = 64; + + GBLY_INCREMENT_CLOCK_TICKS = 114; + gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS; + gbTimerClockTicks = GBTIMER_MODE_0_CLOCK_TICKS; + gbSerialTicks = 0; + gbSerialBits = 0; + gbSerialOn = 0; + gbWindowLine = -1; + gbTimerOn = false; + gbTimerMode = 0; + gbSpeed = 0; + gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; + + if(gbCgbMode) { + gbSpeed = 0; + gbHdmaOn = 0; + gbHdmaSource = 0x99d0; + gbHdmaDestination = 0x99d0; + gbVramBank = 0; + gbWramBank = 1; + + } + + // used to clean the borders + if (gbSgbMode) + { + gbSgbResetFlag = true; + gbSgbReset(); + if (gbBorderOn) + gbSgbRenderBorder(); + gbSgbResetFlag = false; + } + + for(i = 0; i < 4; i++) + gbBgp[i] = gbObp0[i] = gbObp1[i] = i; + + memset(&gbDataMBC1,0, sizeof(gbDataMBC1)); + gbDataMBC1.mapperROMBank = 1; + + gbDataMBC2.mapperRAMEnable = 0; + gbDataMBC2.mapperROMBank = 1; + + memset(&gbDataMBC3,0, 6 * sizeof(int)); + gbDataMBC3.mapperROMBank = 1; + + memset(&gbDataMBC5, 0, sizeof(gbDataMBC5)); + gbDataMBC5.mapperROMBank = 1; + + memset(&gbDataHuC1, 0, sizeof(gbDataHuC1)); + gbDataHuC1.mapperROMBank = 1; + + memset(&gbDataHuC3, 0, sizeof(gbDataHuC3)); + gbDataHuC3.mapperROMBank = 1; + + memset(&gbDataTAMA5,0, 26*sizeof(int)); + gbDataTAMA5.mapperROMBank = 1; + + memset(&gbDataMMM01,0, sizeof(gbDataMMM01)); + gbDataMMM01.mapperROMBank = 1; + + if (useBios && !skipBios && (gbHardware & 5)) + { + gbMemoryMap[0x00] = &gbMemory[0x0000]; + inBios = true; + } + else + { + gbMemoryMap[0x00] = &gbRom[0x0000]; + inBios = false; + } + + gbMemoryMap[0x01] = &gbRom[0x1000]; + gbMemoryMap[0x02] = &gbRom[0x2000]; + gbMemoryMap[0x03] = &gbRom[0x3000]; + gbMemoryMap[0x04] = &gbRom[0x4000]; + gbMemoryMap[0x05] = &gbRom[0x5000]; + gbMemoryMap[0x06] = &gbRom[0x6000]; + gbMemoryMap[0x07] = &gbRom[0x7000]; + if(gbCgbMode) { + gbMemoryMap[0x08] = &gbVram[0x0000]; + gbMemoryMap[0x09] = &gbVram[0x1000]; + gbMemoryMap[0x0a] = &gbMemory[0xa000]; + gbMemoryMap[0x0b] = &gbMemory[0xb000]; + gbMemoryMap[0x0c] = &gbMemory[0xc000]; + gbMemoryMap[0x0d] = &gbWram[0x1000]; + gbMemoryMap[0x0e] = &gbMemory[0xe000]; + gbMemoryMap[0x0f] = &gbMemory[0xf000]; + } else { + gbMemoryMap[0x08] = &gbMemory[0x8000]; + gbMemoryMap[0x09] = &gbMemory[0x9000]; + gbMemoryMap[0x0a] = &gbMemory[0xa000]; + gbMemoryMap[0x0b] = &gbMemory[0xb000]; + gbMemoryMap[0x0c] = &gbMemory[0xc000]; + gbMemoryMap[0x0d] = &gbMemory[0xd000]; + gbMemoryMap[0x0e] = &gbMemory[0xe000]; + gbMemoryMap[0x0f] = &gbMemory[0xf000]; + } + + if(gbRam) { + gbMemoryMap[0x0a] = &gbRam[0x0000]; + gbMemoryMap[0x0b] = &gbRam[0x1000]; + } + + gbSoundReset(); + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + gbLastTime = systemGetClock(); + gbFrameCount = 0; + + gbScreenOn = true; + gbSystemMessage = false; + + gbCheatWrite(true); // Emulates GS codes. + +} + +void gbWriteSaveMBC1(const char * name) +{ + if (gbRam) + { + FILE *gzFile = fopen(name,"wb"); + + if(gzFile == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + (gbRamSizeMask+1), + gzFile); + + fclose(gzFile); + } +} + +void gbWriteSaveMBC2(const char * name) +{ + if (gbRam) + { + FILE *file = fopen(name, "wb"); + + if(file == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(&gbMemory[0xa000], + 1, + 256, + file); + + fclose(file); + } +} + +void gbWriteSaveMBC3(const char * name, bool extendedSave) +{ + if (gbRam || extendedSave) + { + FILE *gzFile = fopen(name,"wb"); + if (gbRam) + { + + if(gzFile == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + (gbRamSizeMask+1), + gzFile); + } + + if(extendedSave) + fwrite(&gbDataMBC3.mapperSeconds, + 1, + 10*sizeof(int) + sizeof(time_t), + gzFile); + + fclose(gzFile); + } +} + +void gbWriteSaveMBC5(const char * name) +{ + if (gbRam) + { + FILE *gzFile = fopen(name,"wb"); + + if(gzFile == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + (gbRamSizeMask+1), + gzFile); + + fclose(gzFile); + } +} + +void gbWriteSaveMBC7(const char * name) +{ + if (gbRam) + { + FILE *file = fopen(name, "wb"); + + if(file == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(&gbMemory[0xa000], + 1, + 256, + file); + + fclose(file); + } +} + +void gbWriteSaveTAMA5(const char * name, bool extendedSave) +{ + FILE *gzFile = fopen(name,"wb"); + + if(gzFile == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + if (gbRam) + fwrite(gbRam, + 1, + (gbRamSizeMask+1), + gzFile); + + fwrite(gbTAMA5ram, + 1, + (gbTAMA5ramSize), + gzFile); + + if(extendedSave) + fwrite(&gbDataTAMA5.mapperSeconds, + 1, + 14*sizeof(int) + sizeof(time_t), + gzFile); + + fclose(gzFile); +} + +void gbWriteSaveMMM01(const char * name) +{ + if (gbRam) + { + FILE *gzFile = fopen(name,"wb"); + + if(gzFile == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + (gbRamSizeMask+1), + gzFile); + + fclose(gzFile); + } +} + + +bool gbReadSaveMBC1(const char * name) +{ + if (gbRam) + { + gzFile gzFile = gzopen(name, "rb"); + + if(gzFile == NULL) { + return false; + } + + int read = gzread(gzFile, + gbRam, + (gbRamSizeMask+1)); + + if(read != (gbRamSizeMask+1)) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gzclose(gzFile); + gbBatteryError = true; + return false; + } + + // Also checks if the battery file it bigger than gbRamSizeMask+1 ! + u8 data[1]; + data[0] = 0; + + read = gzread(gzFile, + data, + 1); + if(read >0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gzclose(gzFile); + gbBatteryError = true; + return false; + } + + gzclose(gzFile); + return true; + } + else + return false; +} + + +bool gbReadSaveMBC2(const char * name) +{ + if (gbRam) + { + FILE *file = fopen(name, "rb"); + + if(file == NULL) { + return false; + } + + size_t read = fread(&gbMemory[0xa000], + 1, + 256, + file); + + if(read != 256) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + fclose(file); + gbBatteryError = true; + return false; + } + + // Also checks if the battery file it bigger than gbRamSizeMask+1 ! + u8 data[1]; + data[0] = 0; + + read = fread(&data[0], + 1, + 1, + file); + if(read > 0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + fclose(file); + gbBatteryError = true; + return false; + } + + fclose(file); + return true; + } + else + return false; +} + +bool gbReadSaveMBC3(const char * name) +{ + gzFile gzFile = gzopen(name, "rb"); + + if(gzFile == NULL) { + return false; + } + + int read = 0; + + if (gbRam) + read = gzread(gzFile, + gbRam, + (gbRamSizeMask+1)); + else + read = (gbRamSizeMask+1); + + + bool res = true; + + if(read != (gbRamSizeMask+1)) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gbBatteryError = true; + res = false; + } else if ((gbRomType == 0xf) || (gbRomType == 0x10)){ + read = gzread(gzFile, + &gbDataMBC3.mapperSeconds, + sizeof(int)*10 + sizeof(time_t)); + + if(read != (sizeof(int)*10 + sizeof(time_t)) && read != 0) { + systemMessage(MSG_FAILED_TO_READ_RTC,N_("Failed to read RTC from save game %s (continuing)"), + name); + res = false; + } + else if (read == 0) + { + systemMessage(MSG_FAILED_TO_READ_RTC,N_("Failed to read RTC from save game %s (continuing)"), + name); + res = false; + } + else + { + // Also checks if the battery file it bigger than gbRamSizeMask+1+RTC ! + u8 data[1]; + data[0] = 0; + + read = gzread(gzFile, + data, + 1); + if(read >0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gbBatteryError = true; + res = false; + } + } + } + + gzclose(gzFile); + return res; +} + +bool gbReadSaveMBC5(const char * name) +{ + if (gbRam) + { + gzFile gzFile = gzopen(name, "rb"); + + if(gzFile == NULL) { + return false; + } + + int read = gzread(gzFile, + gbRam, + (gbRamSizeMask+1)); + + if(read != (gbRamSizeMask+1)) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gzclose(gzFile); + gbBatteryError = true; + return false; + } + + + // Also checks if the battery file it bigger than gbRamSizeMask+1 ! + u8 data[1]; + data[0] = 0; + + read = gzread(gzFile, + data, + 1); + if(read >0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gzclose(gzFile); + gbBatteryError = true; + return false; + } + + gzclose(gzFile); + return true; + } + else + return false; +} + +bool gbReadSaveMBC7(const char * name) +{ + if (gbRam) + { + FILE *file = fopen(name, "rb"); + + if(file == NULL) { + return false; + } + + size_t read = fread(&gbMemory[0xa000], + 1, + 256, + file); + + if(read != 256) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + fclose(file); + gbBatteryError = true; + return false; + } + + // Also checks if the battery file it bigger than gbRamSizeMask+1 ! + u8 data[1]; + data[0] = 0; + + read = fread(&data[0], + 1, + 1, + file); + if(read > 0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + fclose(file); + gbBatteryError = true; + return false; + } + + fclose(file); + return true; + } + else + return false; +} + +bool gbReadSaveTAMA5(const char * name) +{ + gzFile gzFile = gzopen(name, "rb"); + + if(gzFile == NULL) { + return false; + } + + int read = 0; + + if (gbRam) + read = gzread(gzFile, + gbRam, + (gbRamSizeMask+1)); + else + read = gbRamSizeMask; + + read += gzread(gzFile, + gbTAMA5ram, + gbTAMA5ramSize); + + bool res = true; + + if(read != (gbRamSizeMask+gbTAMA5ramSize+1)) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gbBatteryError = true; + res = false; + } else { + read = gzread(gzFile, + &gbDataTAMA5.mapperSeconds, + sizeof(int)*14 + sizeof(time_t)); + + if(read != (sizeof(int)*14 + sizeof(time_t)) && read != 0) { + systemMessage(MSG_FAILED_TO_READ_RTC,N_("Failed to read RTC from save game %s (continuing)"), + name); + res = false; + } + else if (read == 0) + { + systemMessage(MSG_FAILED_TO_READ_RTC,N_("Failed to read RTC from save game %s (continuing)"), + name); + res = false; + } + else + { + // Also checks if the battery file it bigger than gbRamSizeMask+1+RTC ! + u8 data[1]; + data[0] = 0; + + read = gzread(gzFile, + data, + 1); + if(read >0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gbBatteryError = true; + res = false; + } + } + } + + gzclose(gzFile); + return res; +} + + +bool gbReadSaveMMM01(const char * name) +{ + if (gbRam) + { + gzFile gzFile = gzopen(name, "rb"); + + if(gzFile == NULL) { + return false; + } + + int read = gzread(gzFile, + gbRam, + (gbRamSizeMask+1)); + + if(read != (gbRamSizeMask+1)) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gzclose(gzFile); + gbBatteryError = true; + return false; + } + + // Also checks if the battery file it bigger than gbRamSizeMask+1 ! + u8 data[1]; + data[0] = 0; + + read = gzread(gzFile, + data, + 1); + if(read >0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gzclose(gzFile); + gbBatteryError = true; + return false; + } + + gzclose(gzFile); + return true; + } + else + return false; +} + +void gbInit() +{ + gbGenFilter(); + gbSgbInit(); + + gbMemory = (u8 *)malloc(65536); + + pix = (u8 *)calloc(1,4*257*226); + + gbLineBuffer = (u16 *)malloc(160 * sizeof(u16)); +} + +bool gbWriteBatteryFile(const char *file, bool extendedSave) +{ + if(gbBattery) { + switch(gbRomType) { + case 0x03: + gbWriteSaveMBC1(file); + break; + case 0x06: + gbWriteSaveMBC2(file); + break; + case 0x0d: + gbWriteSaveMMM01(file); + break; + case 0x0f: + case 0x10: + gbWriteSaveMBC3(file, extendedSave); + break; + case 0x13: + case 0xfc: + gbWriteSaveMBC3(file, false); + case 0x1b: + case 0x1e: + gbWriteSaveMBC5(file); + break; + case 0x22: + gbWriteSaveMBC7(file); + break; + case 0xfd: + gbWriteSaveTAMA5(file, extendedSave); + break; + case 0xff: + gbWriteSaveMBC1(file); + break; + } + } + return true; +} + +bool gbWriteBatteryFile(const char *file) +{ + if (!gbBatteryError) + { + gbWriteBatteryFile(file, true); + return true; + } + else return false; +} + +bool gbReadBatteryFile(const char *file) +{ + bool res = false; + if(gbBattery) { + switch(gbRomType) { + case 0x03: + res = gbReadSaveMBC1(file); + break; + case 0x06: + res = gbReadSaveMBC2(file); + break; + case 0x0d: + res = gbReadSaveMMM01(file); + break; + case 0x0f: + case 0x10: + if(!gbReadSaveMBC3(file)) { + time(&gbDataMBC3.mapperLastTime); + struct tm *lt; + lt = localtime(&gbDataMBC3.mapperLastTime); + gbDataMBC3.mapperSeconds = lt->tm_sec; + gbDataMBC3.mapperMinutes = lt->tm_min; + gbDataMBC3.mapperHours = lt->tm_hour; + gbDataMBC3.mapperDays = lt->tm_yday & 255; + gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) | + (lt->tm_yday > 255 ? 1: 0); + res = false; + break; + } + res = true; + break; + case 0x13: + case 0xfc: + res = gbReadSaveMBC3(file); + case 0x1b: + case 0x1e: + res = gbReadSaveMBC5(file); + break; + case 0x22: + res = gbReadSaveMBC7(file); + case 0xfd: + if(!gbReadSaveTAMA5(file)) { + u8 gbDaysinMonth [12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + time(&gbDataTAMA5.mapperLastTime); + struct tm *lt; + lt = localtime(&gbDataTAMA5.mapperLastTime); + gbDataTAMA5.mapperSeconds = lt->tm_sec; + gbDataTAMA5.mapperMinutes = lt->tm_min; + gbDataTAMA5.mapperHours = lt->tm_hour; + gbDataTAMA5.mapperDays = 1; + gbDataTAMA5.mapperMonths = 1; + gbDataTAMA5.mapperYears = 1970; + int days = lt->tm_yday+365*3; + while (days) + { + gbDataTAMA5.mapperDays++; + days--; + if (gbDataTAMA5.mapperDays>gbDaysinMonth[gbDataTAMA5.mapperMonths-1]) + { + gbDataTAMA5.mapperDays = 1; + gbDataTAMA5.mapperMonths++; + if (gbDataTAMA5.mapperMonths>12) + { + gbDataTAMA5.mapperMonths = 1; + gbDataTAMA5.mapperYears++; + if ((gbDataTAMA5.mapperYears & 3) == 0) + gbDaysinMonth[1] = 29; + else + gbDaysinMonth[1] = 28; + } + } + } + gbDataTAMA5.mapperControl = (gbDataTAMA5.mapperControl & 0xfe) | + (lt->tm_yday > 255 ? 1: 0); + res = false; + break; + } + res = true; + break; + case 0xff: + res = gbReadSaveMBC1(file); + break; + } + } + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + return res; +} + +bool gbReadGSASnapshot(const char *fileName) +{ + FILE *file = fopen(fileName, "rb"); + + if(!file) { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); + return false; + } + + fseek(file, 0x4, SEEK_SET); + char buffer[16]; + char buffer2[16]; + fread(buffer, 1, 15, file); + buffer[15] = 0; + memcpy(buffer2, &gbRom[0x134], 15); + buffer2[15] = 0; + if(memcmp(buffer, buffer2, 15)) { + systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, + N_("Cannot import snapshot for %s. Current game is %s"), + buffer, + buffer2); + fclose(file); + return false; + } + fseek(file, 0x13, SEEK_SET); + size_t read = 0; + int toRead = 0; + switch(gbRomType) { + case 0x03: + case 0x0f: + case 0x10: + case 0x13: + case 0x1b: + case 0x1e: + case 0xff: + read = fread(gbRam, 1, (gbRamSizeMask+1), file); + toRead = (gbRamSizeMask+1); + break; + case 0x06: + case 0x22: + read = fread(&gbMemory[0xa000],1,256,file); + toRead = 256; + break; + default: + systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, + N_("Unsupported snapshot file %s"), + fileName); + fclose(file); + return false; + } + fclose(file); + gbReset(); + return true; +} + +variable_desc gbSaveGameStruct[] = { + { &PC.W, sizeof(u16) }, + { &SP.W, sizeof(u16) }, + { &AF.W, sizeof(u16) }, + { &BC.W, sizeof(u16) }, + { &DE.W, sizeof(u16) }, + { &HL.W, sizeof(u16) }, + { &IFF, sizeof(u8) }, + { &GBLCD_MODE_0_CLOCK_TICKS, sizeof(int) }, + { &GBLCD_MODE_1_CLOCK_TICKS, sizeof(int) }, + { &GBLCD_MODE_2_CLOCK_TICKS, sizeof(int) }, + { &GBLCD_MODE_3_CLOCK_TICKS, sizeof(int) }, + { &GBDIV_CLOCK_TICKS, sizeof(int) }, + { &GBLY_INCREMENT_CLOCK_TICKS, sizeof(int) }, + { &GBTIMER_MODE_0_CLOCK_TICKS, sizeof(int) }, + { &GBTIMER_MODE_1_CLOCK_TICKS, sizeof(int) }, + { &GBTIMER_MODE_2_CLOCK_TICKS, sizeof(int) }, + { &GBTIMER_MODE_3_CLOCK_TICKS, sizeof(int) }, + { &GBSERIAL_CLOCK_TICKS, sizeof(int) }, + { &GBSYNCHRONIZE_CLOCK_TICKS, sizeof(int) }, + { &gbDivTicks, sizeof(int) }, + { &gbLcdMode, sizeof(int) }, + { &gbLcdTicks, sizeof(int) }, + { &gbLcdLYIncrementTicks, sizeof(int) }, + { &gbTimerTicks, sizeof(int) }, + { &gbTimerClockTicks, sizeof(int) }, + { &gbSerialTicks, sizeof(int) }, + { &gbSerialBits, sizeof(int) }, + { &gbInt48Signal, sizeof(int) }, + { &gbInterruptWait, sizeof(int) }, + { &gbSynchronizeTicks, sizeof(int) }, + { &gbTimerOn, sizeof(int) }, + { &gbTimerMode, sizeof(int) }, + { &gbSerialOn, sizeof(int) }, + { &gbWindowLine, sizeof(int) }, + { &gbCgbMode, sizeof(int) }, + { &gbVramBank, sizeof(int) }, + { &gbWramBank, sizeof(int) }, + { &gbHdmaSource, sizeof(int) }, + { &gbHdmaDestination, sizeof(int) }, + { &gbHdmaBytes, sizeof(int) }, + { &gbHdmaOn, sizeof(int) }, + { &gbSpeed, sizeof(int) }, + { &gbSgbMode, sizeof(int) }, + { ®ister_DIV, sizeof(u8) }, + { ®ister_TIMA, sizeof(u8) }, + { ®ister_TMA, sizeof(u8) }, + { ®ister_TAC, sizeof(u8) }, + { ®ister_IF, sizeof(u8) }, + { ®ister_LCDC, sizeof(u8) }, + { ®ister_STAT, sizeof(u8) }, + { ®ister_SCY, sizeof(u8) }, + { ®ister_SCX, sizeof(u8) }, + { ®ister_LY, sizeof(u8) }, + { ®ister_LYC, sizeof(u8) }, + { ®ister_DMA, sizeof(u8) }, + { ®ister_WY, sizeof(u8) }, + { ®ister_WX, sizeof(u8) }, + { ®ister_VBK, sizeof(u8) }, + { ®ister_HDMA1, sizeof(u8) }, + { ®ister_HDMA2, sizeof(u8) }, + { ®ister_HDMA3, sizeof(u8) }, + { ®ister_HDMA4, sizeof(u8) }, + { ®ister_HDMA5, sizeof(u8) }, + { ®ister_SVBK, sizeof(u8) }, + { ®ister_IE , sizeof(u8) }, + { &gbBgp[0], sizeof(u8) }, + { &gbBgp[1], sizeof(u8) }, + { &gbBgp[2], sizeof(u8) }, + { &gbBgp[3], sizeof(u8) }, + { &gbObp0[0], sizeof(u8) }, + { &gbObp0[1], sizeof(u8) }, + { &gbObp0[2], sizeof(u8) }, + { &gbObp0[3], sizeof(u8) }, + { &gbObp1[0], sizeof(u8) }, + { &gbObp1[1], sizeof(u8) }, + { &gbObp1[2], sizeof(u8) }, + { &gbObp1[3], sizeof(u8) }, + { NULL, 0 } +}; + + +static bool gbWriteSaveState(gzFile gzFile) +{ + + utilWriteInt(gzFile, GBSAVE_GAME_VERSION); + + utilGzWrite(gzFile, &gbRom[0x134], 15); + + utilWriteInt(gzFile, useBios); + utilWriteInt(gzFile, inBios); + + utilWriteData(gzFile, gbSaveGameStruct); + + utilGzWrite(gzFile, &IFF, 2); + + if(gbSgbMode) { + gbSgbSaveGame(gzFile); + } + + utilGzWrite(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); + utilGzWrite(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); + utilGzWrite(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); + utilGzWrite(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); + utilGzWrite(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); + utilGzWrite(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); + utilGzWrite(gzFile, &gbDataTAMA5, sizeof(gbDataTAMA5)); + if (gbTAMA5ram != NULL) + utilGzWrite(gzFile, gbTAMA5ram, gbTAMA5ramSize); + utilGzWrite(gzFile, &gbDataMMM01, sizeof(gbDataMMM01)); + + utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16)); + + utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000); + + if(gbRamSize && gbRam) { + utilWriteInt(gzFile, gbRamSize); + utilGzWrite(gzFile, gbRam, gbRamSize); + } + + if(gbCgbMode) { + utilGzWrite(gzFile, gbVram, 0x4000); + utilGzWrite(gzFile, gbWram, 0x8000); + } + + gbSoundSaveGame(gzFile); + + gbCheatsSaveGame(gzFile); + + utilWriteInt(gzFile, gbLcdModeDelayed); + utilWriteInt(gzFile, gbLcdTicksDelayed); + utilWriteInt(gzFile, gbLcdLYIncrementTicksDelayed); + utilWriteInt(gzFile, gbSpritesTicks[299]); + utilWriteInt(gzFile, gbTimerModeChange); + utilWriteInt(gzFile, gbTimerOnChange); + utilWriteInt(gzFile, gbHardware); + utilWriteInt(gzFile, gbBlackScreen); + utilWriteInt(gzFile, oldRegister_WY); + utilWriteInt(gzFile, gbWindowLine); + utilWriteInt(gzFile, inUseRegister_WY); + utilWriteInt(gzFile, gbScreenOn); + return true; +} + +bool gbWriteMemSaveState(char *memory, int available) +{ + gzFile gzFile = utilMemGzOpen(memory, available, "w"); + + if(gzFile == NULL) { + return false; + } + + bool res = gbWriteSaveState(gzFile); + + long pos = utilGzMemTell(gzFile)+8; + + if(pos >= (available)) + res = false; + + utilGzClose(gzFile); + + return res; +} + +bool gbWriteSaveState(const char *name) +{ + gzFile gzFile = utilGzOpen(name,"wb"); + + if(gzFile == NULL) + return false; + + bool res = gbWriteSaveState(gzFile); + + utilGzClose(gzFile); + return res; +} + +static bool gbReadSaveState(gzFile gzFile) +{ + int version = utilReadInt(gzFile); + + if(version > GBSAVE_GAME_VERSION || version < 0) { + systemMessage(MSG_UNSUPPORTED_VB_SGM, + N_("Unsupported VisualBoy save game version %d"), version); + return false; + } + + u8 romname[20]; + + utilGzRead(gzFile, romname, 15); + + if(memcmp(&gbRom[0x134], romname, 15) != 0) { + systemMessage(MSG_CANNOT_LOAD_SGM_FOR, + N_("Cannot load save game for %s. Playing %s"), + romname, &gbRom[0x134]); + return false; + } + + + bool ub = false; + bool ib = false; + + if (version >= 11) + { + ub = utilReadInt(gzFile) ? true : false; + ib = utilReadInt(gzFile) ? true : false; + + if((ub != useBios) && (ib)) { + if(useBios) + systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS, + N_("Save game is not using the BIOS files")); + else + systemMessage(MSG_SAVE_GAME_USING_BIOS, + N_("Save game is using the BIOS file")); + return false; + } + } + + gbReset(); + + inBios = ib; + + utilReadData(gzFile, gbSaveGameStruct); + + + // Correct crash when loading color gameboy save in regular gameboy type. + if (!gbCgbMode) + { + if(gbVram != NULL) { + free(gbVram); + gbVram = NULL; + } + if(gbWram != NULL) { + free(gbWram); + gbWram = NULL; + } + } + else + { + if(gbVram == NULL) + gbVram = (u8 *)malloc(0x4000); + if(gbWram == NULL) + gbWram = (u8 *)malloc(0x8000); + memset(gbVram,0,0x4000); + memset(gbPalette,0, 2*128); + } + + + + if(version >= GBSAVE_GAME_VERSION_7) { + utilGzRead(gzFile, &IFF, 2); + } + + if(gbSgbMode) { + gbSgbReadGame(gzFile, version); + } else { + gbSgbMask = 0; // loading a game at the wrong time causes no display + } + if (version<11) + utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1) - sizeof(int)); + else + utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); + utilGzRead(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); + if(version < GBSAVE_GAME_VERSION_4) + // prior to version 4, there was no adjustment for the time the game + // was last played, so we have less to read. This needs update if the + // structure changes again. + utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)-sizeof(time_t)); + else + utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); + utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); + utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); + utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); + if (version>=11) + { + utilGzRead(gzFile, &gbDataTAMA5, sizeof(gbDataTAMA5)); + if (gbTAMA5ram != NULL) + utilGzRead(gzFile, gbTAMA5ram, gbTAMA5ramSize); + utilGzRead(gzFile, &gbDataMMM01, sizeof(gbDataMMM01)); + } + + if(version < GBSAVE_GAME_VERSION_5) { + utilGzRead(gzFile, pix, 256*224*sizeof(u16)); + } + memset(pix, 0, 257*226*sizeof(u32)); + + if(version < GBSAVE_GAME_VERSION_6) { + utilGzRead(gzFile, gbPalette, 64 * sizeof(u16)); + } else + utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); + + if (version < 11) + utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); + + if(version < GBSAVE_GAME_VERSION_10) { + if(!gbCgbMode && !gbSgbMode) { + for(int i = 0; i < 8; i++) + gbPalette[i] = systemGbPalette[gbPaletteOption*8+i]; + } + } + + utilGzRead(gzFile, &gbMemory[0x8000], 0x8000); + + if(gbRamSize && gbRam) { + if (version < 11) + utilGzRead(gzFile, gbRam, gbRamSize); + else + { + int ramSize = utilReadInt(gzFile); + utilGzRead(gzFile, gbRam, (gbRamSize>ramSize) ? ramSize : gbRamSize); + if (ramSize>gbRamSize) + gzseek(gzFile,ramSize-gbRamSize,SEEK_CUR); + } + } + + memset(gbSCYLine, register_SCY, sizeof(gbSCYLine)); + memset(gbSCXLine, register_SCX, sizeof(gbSCXLine)); + memset(gbBgpLine, (gbBgp[0] | (gbBgp[1]<<2) | (gbBgp[2]<<4) | + (gbBgp[3]<<6)), sizeof(gbBgpLine)); + memset(gbObp0Line, (gbObp0[0] | (gbObp0[1]<<2) | (gbObp0[2]<<4) | + (gbObp0[3]<<6)), sizeof(gbObp0Line)); + memset(gbObp1Line, (gbObp1[0] | (gbObp1[1]<<2) | (gbObp1[2]<<4) | + (gbObp1[3]<<6)), sizeof(gbObp1Line)); + memset(gbSpritesTicks, 0x0, sizeof(gbSpritesTicks)); + + if (inBios) + { + gbMemoryMap[0x00] = &gbMemory[0x0000]; + memcpy ((u8 *)(gbMemory), (u8 *)(gbRom), 0x1000); + memcpy ((u8 *)(gbMemory), (u8 *)(bios), 0x100); + } + else + gbMemoryMap[0x00] = &gbRom[0x0000]; + gbMemoryMap[0x01] = &gbRom[0x1000]; + gbMemoryMap[0x02] = &gbRom[0x2000]; + gbMemoryMap[0x03] = &gbRom[0x3000]; + gbMemoryMap[0x04] = &gbRom[0x4000]; + gbMemoryMap[0x05] = &gbRom[0x5000]; + gbMemoryMap[0x06] = &gbRom[0x6000]; + gbMemoryMap[0x07] = &gbRom[0x7000]; + gbMemoryMap[0x08] = &gbMemory[0x8000]; + gbMemoryMap[0x09] = &gbMemory[0x9000]; + gbMemoryMap[0x0a] = &gbMemory[0xa000]; + gbMemoryMap[0x0b] = &gbMemory[0xb000]; + gbMemoryMap[0x0c] = &gbMemory[0xc000]; + gbMemoryMap[0x0d] = &gbMemory[0xd000]; + gbMemoryMap[0x0e] = &gbMemory[0xe000]; + gbMemoryMap[0x0f] = &gbMemory[0xf000]; + + switch(gbRomType) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + // MBC 1 + memoryUpdateMapMBC1(); + break; + case 0x05: + case 0x06: + // MBC2 + memoryUpdateMapMBC2(); + break; + case 0x0b: + case 0x0c: + case 0x0d: + // MMM01 + memoryUpdateMapMMM01(); + break; + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + // MBC 3 + memoryUpdateMapMBC3(); + break; + case 0x19: + case 0x1a: + case 0x1b: + // MBC5 + memoryUpdateMapMBC5(); + break; + case 0x1c: + case 0x1d: + case 0x1e: + // MBC 5 Rumble + memoryUpdateMapMBC5(); + break; + case 0x22: + // MBC 7 + memoryUpdateMapMBC7(); + break; + case 0x56: + // GS3 + memoryUpdateMapGS3(); + break; + case 0xfd: + // TAMA5 + memoryUpdateMapTAMA5(); + break; + case 0xfe: + // HuC3 + memoryUpdateMapHuC3(); + break; + case 0xff: + // HuC1 + memoryUpdateMapHuC1(); + break; + } + + if(gbCgbMode) { + utilGzRead(gzFile, gbVram, 0x4000); + utilGzRead(gzFile, gbWram, 0x8000); + + int value = register_SVBK; + if(value == 0) + value = 1; + + gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000]; + gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000]; + gbMemoryMap[0x0d] = &gbWram[value * 0x1000]; + } + + gbSoundReadGame(version, gzFile); + + if (gbCgbMode && gbSgbMode) { + gbSgbMode = 0; + } + + if(gbBorderOn && !gbSgbMask) { + gbSgbRenderBorder(); + } + + systemDrawScreen(); + + if(version > GBSAVE_GAME_VERSION_1) + gbCheatsReadGame(gzFile, version); + + if (version<11) + { + gbWriteMemory(0xff00, 0); + gbMemory[0xff04] = register_DIV; + gbMemory[0xff05] = register_TIMA; + gbMemory[0xff06] = register_TMA; + gbMemory[0xff07] = register_TAC; + gbMemory[0xff40] = register_LCDC; + gbMemory[0xff42] = register_SCY; + gbMemory[0xff43] = register_SCX; + gbMemory[0xff44] = register_LY; + gbMemory[0xff45] = register_LYC; + gbMemory[0xff46] = register_DMA; + gbMemory[0xff4a] = register_WY; + gbMemory[0xff4b] = register_WX; + gbMemory[0xff4f] = register_VBK; + gbMemory[0xff51] = register_HDMA1; + gbMemory[0xff52] = register_HDMA2; + gbMemory[0xff53] = register_HDMA3; + gbMemory[0xff54] = register_HDMA4; + gbMemory[0xff55] = register_HDMA5; + gbMemory[0xff70] = register_SVBK; + gbMemory[0xffff] = register_IE; + GBDIV_CLOCK_TICKS = 64; + + if (gbSpeed) + gbDivTicks /=2; + + if ((gbLcdMode == 0) && (register_STAT & 8)) + gbInt48Signal |= 1; + if ((gbLcdMode == 1) && (register_STAT & 0x10)) + gbInt48Signal |= 2; + if ((gbLcdMode == 2) && (register_STAT & 0x20)) + gbInt48Signal |= 4; + if ((register_LY==register_LYC) && (register_STAT & 0x40)) + gbInt48Signal |= 8; + + gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS; + + if (gbLcdMode == 2) + gbLcdLYIncrementTicks-=GBLCD_MODE_2_CLOCK_TICKS-gbLcdTicks; + else if (gbLcdMode == 3) + gbLcdLYIncrementTicks -=GBLCD_MODE_2_CLOCK_TICKS+GBLCD_MODE_3_CLOCK_TICKS-gbLcdTicks; + else if (gbLcdMode == 0) + gbLcdLYIncrementTicks =gbLcdTicks; + else if (gbLcdMode == 1) + { + gbLcdLYIncrementTicks = gbLcdTicks % GBLY_INCREMENT_CLOCK_TICKS; + if (register_LY == 0x99) + gbLcdLYIncrementTicks =gbLine99Ticks; + else if (register_LY == 0) + gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; + } + + gbLcdModeDelayed = gbLcdMode; + gbLcdTicksDelayed = gbLcdTicks--; + gbLcdLYIncrementTicksDelayed = gbLcdLYIncrementTicks--; + gbInterruptWait = 0; + memset(gbSpritesTicks,0,sizeof(gbSpritesTicks)); + } + else + { + gbLcdModeDelayed = utilReadInt(gzFile); + gbLcdTicksDelayed = utilReadInt(gzFile); + gbLcdLYIncrementTicksDelayed = utilReadInt(gzFile); + gbSpritesTicks[299] = utilReadInt(gzFile) & 0xff; + gbTimerModeChange = (utilReadInt(gzFile) ? true : false); + gbTimerOnChange = (utilReadInt(gzFile) ? true : false); + gbHardware = utilReadInt(gzFile); + gbBlackScreen = (utilReadInt(gzFile) ? true : false); + oldRegister_WY = utilReadInt(gzFile); + gbWindowLine = utilReadInt(gzFile); + inUseRegister_WY = utilReadInt(gzFile); + gbScreenOn = (utilReadInt(gzFile) ? true : false); + } + + if (gbSpeed) + gbLine99Ticks *= 2; + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + return true; +} + +bool gbReadMemSaveState(char *memory, int available) +{ + gzFile gzFile = utilMemGzOpen(memory, available, "r"); + + bool res = gbReadSaveState(gzFile); + + utilGzClose(gzFile); + + return res; +} + +bool gbReadSaveState(const char *name) +{ + gzFile gzFile = utilGzOpen(name,"rb"); + + if(gzFile == NULL) { + return false; + } + + bool res = gbReadSaveState(gzFile); + + utilGzClose(gzFile); + + return res; +} + +bool gbWritePNGFile(const char *fileName) +{ + if(gbBorderOn) + return utilWritePNGFile(fileName, 256, 224, pix); + return utilWritePNGFile(fileName, 160, 144, pix); +} + +bool gbWriteBMPFile(const char *fileName) +{ + if(gbBorderOn) + return utilWriteBMPFile(fileName, 256, 224, pix); + return utilWriteBMPFile(fileName, 160, 144, pix); +} + +void gbCleanUp() +{ + if(gbRam != NULL) { + free(gbRam); + gbRam = NULL; + } + + if(gbRom != NULL) { + free(gbRom); + gbRom = NULL; + } + + if(gbMemory != NULL) { + free(gbMemory); + gbMemory = NULL; + } + + if(gbLineBuffer != NULL) { + free(gbLineBuffer); + gbLineBuffer = NULL; + } + + if(pix != NULL) { + free(pix); + pix = NULL; + } + + gbSgbShutdown(); + + if(gbVram != NULL) { + free(gbVram); + gbVram = NULL; + } + + if(gbWram != NULL) { + free(gbWram); + gbWram = NULL; + } + + if(gbTAMA5ram != NULL) { + free(gbTAMA5ram); + gbTAMA5ram = NULL; + } + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; +} + +bool gbLoadRom(const char *szFile) +{ + int size = 0; + + if(gbRom != NULL) { + gbCleanUp(); + } + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + gbRom = utilLoad(szFile, + utilIsGBImage, + NULL, + size); + if(!gbRom) + return false; + + gbRomSize = size; + + gbBatteryError = false; + + if(bios != NULL) { + free(bios); + bios = NULL; + } + bios = (u8 *)calloc(1,0x100); + + return gbUpdateSizes(); +} + +bool gbUpdateSizes() +{ + if(gbRom[0x148] > 8) { + systemMessage(MSG_UNSUPPORTED_ROM_SIZE, + N_("Unsupported rom size %02x"), gbRom[0x148]); + return false; + } + + if(gbRomSize < gbRomSizes[gbRom[0x148]]) { + gbRom = (u8 *)realloc(gbRom, gbRomSizes[gbRom[0x148]]); + for (int i = gbRomSize; igbRomSizes[gbRom[0x148]]) && (genericflashcardEnable)) + { + gbRomSize = gbRomSize>>16; + gbRom[0x148] = 0; + if (gbRomSize) + { + while (!((gbRomSize & 1) || (gbRom[0x148] == 7))) + { + gbRom[0x148]++; + gbRomSize>>=1; + } + gbRom[0x148]++; + } + gbRom = (u8 *)realloc(gbRom, gbRomSizes[gbRom[0x148]]); + } + gbRomSize = gbRomSizes[gbRom[0x148]]; + gbRomSizeMask = gbRomSizesMasks[gbRom[0x148]]; + + + // The 'genericflashcard' option allows some PD to work. + // However, the setting is dangerous (if you let in enabled + // and play a normal game, it might just break everything). + // That's why it is not saved in the emulator options. + // Also I added some checks in VBA to make sure your saves will not be + // overwritten if you wrongly enable this option for a game + // you already played (and vice-versa, ie. if you forgot to + // enable the option for a game you played with it enabled, like Shawu Story). + u8 ramsize = genericflashcardEnable ? 5 : gbRom[0x149]; + gbRom[0x149] = ramsize; + + if ((gbRom[2] == 0x6D) && (gbRom[5] == 0x47) && (gbRom[6] == 0x65) && (gbRom[7] == 0x6E) && + (gbRom[8] == 0x69) && (gbRom[9] == 0x65) && (gbRom[0xA] == 0x28) && (gbRom[0xB] == 0x54)) + { + gbCheatingDevice = 1; // GameGenie + for (int i = 0; i < 0x20; i++) // Cleans GG hardware registers + gbRom[0x4000+i] = 0; + } + else if (((gbRom[0x104] == 0x44) && (gbRom[0x156] == 0xEA) && (gbRom[0x158] == 0x7F) && + (gbRom[0x159] == 0xEA) && (gbRom[0x15B] == 0x7F)) || ((gbRom[0x165] == 0x3E) && + (gbRom[0x166] == 0xD9) && (gbRom[0x16D] == 0xE1) && (gbRom[0x16E] == 0x7F))) + gbCheatingDevice = 2; // GameShark + else gbCheatingDevice = 0; + + if(ramsize > 5) { + systemMessage(MSG_UNSUPPORTED_RAM_SIZE, + N_("Unsupported ram size %02x"), gbRom[0x149]); + return false; + } + + gbRamSize = gbRamSizes[ramsize]; + gbRamSizeMask = gbRamSizesMasks[ramsize]; + + if(gbRamSize) { + gbRam = (u8 *)malloc(gbRamSize); + memset(gbRam, 0xff, gbRamSize); + } + + + gbRomType = gbRom[0x147]; + if (genericflashcardEnable) + { + /*if (gbRomType<2) + gbRomType =3; + else if ((gbRomType == 0xc) || (gbRomType == 0xf) || (gbRomType == 0x12) || + (gbRomType == 0x16) || (gbRomType == 0x1a) || (gbRomType == 0x1d)) + gbRomType++; + else if ((gbRomType == 0xb) || (gbRomType == 0x11) || (gbRomType == 0x15) || + (gbRomType == 0x19) || (gbRomType == 0x1c)) + gbRomType+=2; + else if ((gbRomType == 0x5) || (gbRomType == 0x6)) + gbRomType = 0x1a;*/ + gbRomType = 0x1b; + } + else if (gbCheatingDevice == 1) + gbRomType = 0x55; + else if (gbCheatingDevice == 2) + gbRomType = 0x56; + + gbRom[0x147] = gbRomType; + + mapperReadRAM = NULL; + + switch(gbRomType) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + // MBC 1 + mapper = mapperMBC1ROM; + mapperRAM = mapperMBC1RAM; + mapperReadRAM = mapperMBC1ReadRAM; + break; + case 0x05: + case 0x06: + // MBC2 + mapper = mapperMBC2ROM; + mapperRAM = mapperMBC2RAM; + gbRamSize = 0x200; + gbRamSizeMask = 0x1ff; + break; + case 0x0b: + case 0x0c: + case 0x0d: + // MMM01 + mapper = mapperMMM01ROM; + mapperRAM = mapperMMM01RAM; + break; + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0xfc: + // MBC 3 + mapper = mapperMBC3ROM; + mapperRAM = mapperMBC3RAM; + mapperReadRAM = mapperMBC3ReadRAM; + break; + case 0x19: + case 0x1a: + case 0x1b: + // MBC5 + mapper = mapperMBC5ROM; + mapperRAM = mapperMBC5RAM; + mapperReadRAM = mapperMBC5ReadRAM; + break; + case 0x1c: + case 0x1d: + case 0x1e: + // MBC 5 Rumble + mapper = mapperMBC5ROM; + mapperRAM = mapperMBC5RAM; + mapperReadRAM = mapperMBC5ReadRAM; + break; + case 0x22: + // MBC 7 + mapper = mapperMBC7ROM; + mapperRAM = mapperMBC7RAM; + mapperReadRAM = mapperMBC7ReadRAM; + break; + // GG (GameGenie) + case 0x55: + mapper = mapperGGROM; + break; + case 0x56: + // GS (GameShark) + mapper = mapperGS3ROM; + break; + case 0xfd: + // TAMA5 + if (gbRam!= NULL) + { + free(gbRam); + gbRam = NULL; + } + + ramsize = 3; + gbRamSize = gbRamSizes[3]; + gbRamSizeMask = gbRamSizesMasks[3]; + gbRam = (u8 *)malloc(gbRamSize); + memset(gbRam, 0x0, gbRamSize); + + gbTAMA5ramSize = 0x100; + + if (gbTAMA5ram == NULL) + gbTAMA5ram = (u8 *)malloc(gbTAMA5ramSize); + memset(gbTAMA5ram, 0x0, gbTAMA5ramSize); + + mapperRAM = mapperTAMA5RAM; + mapperReadRAM = mapperTAMA5ReadRAM; + mapperUpdateClock = memoryUpdateTAMA5Clock; + break; + case 0xfe: + // HuC3 + mapper = mapperHuC3ROM; + mapperRAM = mapperHuC3RAM; + mapperReadRAM = mapperHuC3ReadRAM; + break; + case 0xff: + // HuC1 + mapper = mapperHuC1ROM; + mapperRAM = mapperHuC1RAM; + break; + default: + systemMessage(MSG_UNKNOWN_CARTRIDGE_TYPE, + N_("Unknown cartridge type %02x"), gbRomType); + return false; + } + + switch(gbRomType) { + case 0x03: + case 0x06: + case 0x0f: + case 0x10: + case 0x13: + case 0x1b: + case 0x1d: + case 0x1e: + case 0x22: + case 0xfd: + case 0xff: + gbBattery = 1; + break; + } + + gbInit(); + + //gbReset(); + + switch(gbRomType) { + case 0x1c: + case 0x1d: + case 0x1e: + gbDataMBC5.isRumbleCartridge = 1; + } + + return true; +} + +int gbGetNextEvent (int clockTicks) +{ + if (register_LCDC & 0x80) + { + if(gbLcdTicks < clockTicks) + clockTicks = gbLcdTicks; + + if(gbLcdTicksDelayed < clockTicks) + clockTicks = gbLcdTicksDelayed; + + if(gbLcdLYIncrementTicksDelayed < clockTicks) + clockTicks = gbLcdLYIncrementTicksDelayed; + } + + if(gbLcdLYIncrementTicks < clockTicks) + clockTicks = gbLcdLYIncrementTicks; + + if(gbSerialOn && (gbSerialTicks < clockTicks)) + clockTicks = gbSerialTicks; + + if(gbTimerOn && (((gbInternalTimer) & gbTimerMask[gbTimerMode])+1 < clockTicks)) + clockTicks = ((gbInternalTimer) & gbTimerMask[gbTimerMode])+1; + + //if(soundTicks && (soundTicks < clockTicks)) + // clockTicks = soundTicks; + + if ((clockTicks<=0) || (gbInterruptWait)) + clockTicks = 1; + + return clockTicks; +} + +void gbDrawLine() +{ + switch(systemColorDepth) { + case 16: + { + u16 * dest = (u16 *)pix + + (gbBorderLineSkip+2) * (register_LY + gbBorderRowSkip+1) + + gbBorderColumnSkip; + for(int x = 0; x < 160; ) { + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + } + if(gbBorderOn) + dest += gbBorderColumnSkip; + *dest++ = 0; // for filters that read one pixel more + } + break; + + case 24: + { + u8 *dest = (u8 *)pix + + 3*(gbBorderLineSkip * (register_LY + gbBorderRowSkip) + + gbBorderColumnSkip); + for(int x = 0; x < 160;) { + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest+= 3; + } + } + break; + + case 32: + { + u32 * dest = (u32 *)pix + + (gbBorderLineSkip+1) * (register_LY + gbBorderRowSkip+1) + + gbBorderColumnSkip; + for(int x = 0; x < 160;) { + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + } + } + break; + } +} + +void gbEmulate(int ticksToStop) +{ + gbRegister tempRegister; + u8 tempValue; + s8 offset; + + clockTicks = 0; + gbDmaTicks = 0; + + register int opcode = 0; + + int opcode1 = 0; + int opcode2 = 0; + bool execute = false; + + while(1) { +#ifndef FINAL_VERSION + if(systemDebug) { + if(!(IFF & 0x80)) { + if(systemDebug > 1) { + sprintf(gbBuffer,"PC=%04x AF=%04x BC=%04x DE=%04x HL=%04x SP=%04x I=%04x\n", + PC.W, AF.W, BC.W, DE.W,HL.W,SP.W,IFF); + } else { + sprintf(gbBuffer,"PC=%04x I=%02x\n", PC.W, IFF); + } + log(gbBuffer); + } + } +#endif + + u16 oldPCW = PC.W; + + if(IFF & 0x80) { + if(register_LCDC & 0x80) { + clockTicks = gbLcdTicks; + } else + clockTicks = 1000; + + clockTicks = gbGetNextEvent(clockTicks); + + /*if(gbLcdTicksDelayed < clockTicks) + clockTicks = gbLcdTicksDelayed; + + if(gbLcdLYIncrementTicksDelayed < clockTicks) + clockTicks = gbLcdLYIncrementTicksDelayed; + + if(gbLcdLYIncrementTicks < clockTicks) + clockTicks = gbLcdLYIncrementTicks; + + if(gbSerialOn && (gbSerialTicks < clockTicks)) + clockTicks = gbSerialTicks; + + if(gbTimerOn && (((gbInternalTimer) & gbTimerMask[gbTimerMode])+1 < clockTicks)) + clockTicks = ((gbInternalTimer) & gbTimerMask[gbTimerMode])+1; + + if(soundTicks && (soundTicks < clockTicks)) + clockTicks = soundTicks; + + if ((clockTicks<=0) || (gbInterruptWait)) + clockTicks = 1;*/ + + } else { + + // First we apply the clockTicks, then we execute the opcodes. + opcode1 = 0; + opcode2 = 0; + execute = true; + + opcode2 = opcode1 = opcode = gbReadOpcode(PC.W++); + + // If HALT state was launched while IME = 0 and (register_IF & register_IE & 0x1F), + // PC.W is not incremented for the first byte of the next instruction. + if (IFF & 2) + { + PC.W--; + IFF &= ~2; + } + + clockTicks = gbCycles[opcode]; + + switch(opcode) { + case 0xCB: + // extended opcode + opcode2 = opcode = gbReadOpcode(PC.W++); + clockTicks = gbCyclesCB[opcode]; + break; + } + gbOldClockTicks = clockTicks-1; + gbIntBreak = 1; + } + + + if(!emulating) + return; + + // For 'breakpoint' support (opcode 0xFC is considered as a breakpoint) + if ((clockTicks==0) && execute) + { + PC.W = oldPCW; + return; + } + + + if (!(IFF & 0x80)) + clockTicks = 1; + + gbRedoLoop: + + + + if (gbInterruptWait) + gbInterruptWait = 0; + else + gbInterruptLaunched = 0; + + + // Used for the EI/DI instruction's delay. + if (IFF & 0x38) + { + int tempIFF = (IFF >> 4) & 3; + + if (tempIFF <=clockTicks) + { + tempIFF = 0; + IFF |=1; + } + else + tempIFF -= clockTicks; + IFF = (IFF & 0xCF) | (tempIFF <<4); + + if (IFF & 0x08) + IFF &= 0x82; + } + + + if (register_LCDCBusy) + { + register_LCDCBusy-=clockTicks; + if (register_LCDCBusy<0) + register_LCDCBusy = 0; + } + + + if(gbSgbMode) { + if(gbSgbPacketTimeout) { + gbSgbPacketTimeout -= clockTicks; + + if(gbSgbPacketTimeout <= 0) + gbSgbResetPacketState(); + } + } + + ticksToStop -= clockTicks; + + // DIV register emulation + gbDivTicks -= clockTicks; + while(gbDivTicks <= 0) { + gbMemory[0xff04] = ++register_DIV; + gbDivTicks += GBDIV_CLOCK_TICKS; + } + + if(register_LCDC & 0x80) { + // LCD stuff + + gbLcdTicks -= clockTicks; + gbLcdTicksDelayed -= clockTicks; + gbLcdLYIncrementTicks -= clockTicks; + gbLcdLYIncrementTicksDelayed -= clockTicks; + + + // our counters are off, see what we need to do + + // This looks (and kinda is) complicated, however this + // is the only way I found to emulate properly the way + // the real hardware operates... + while(((gbLcdTicks <= 0) && (gbLCDChangeHappened == false)) || + ((gbLcdTicksDelayed <= 0) && (gbLCDChangeHappened == true)) || + ((gbLcdLYIncrementTicks <= 0) && (gbLYChangeHappened == false)) || + ((gbLcdLYIncrementTicksDelayed<=0) && (gbLYChangeHappened == true))) + { + + if ((gbLcdLYIncrementTicks <= 0) && (!gbLYChangeHappened)) + { + gbLYChangeHappened = true; + gbMemory[0xff44] = register_LY = (register_LY + 1) % 154; + + if (register_LY == 0x91) + { + /* if (IFF & 0x80) + gbScreenOn = !gbScreenOn; + else*/ if (register_LCDC & 0x80) + gbScreenOn = true; + } + + gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; + + if (gbLcdMode == 1) + { + + if(register_LY == 153) + gbLcdLYIncrementTicks -= GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; + else if(register_LY == 0) + gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; + } + + // GB only 'bug' : Halt state is broken one tick before LY==LYC interrupt + // is reflected in the registers. + if ((gbHardware & 5) && (IFF & 0x80) && (register_LY == register_LYC) + && (register_STAT & 0x40) && (register_LY != 0)) + { + if (!((gbLcdModeDelayed != 1) && (register_LY==0))) + { + gbInt48Signal &= ~9; + gbCompareLYToLYC(); + gbLYChangeHappened = false; + gbMemory[0xff41] = register_STAT; + gbMemory[0xff0f] = register_IF; + } + + gbLcdLYIncrementTicksDelayed += GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks+1; + } + } + + + if ((gbLcdTicks <= 0) && (!gbLCDChangeHappened)) + { + gbLCDChangeHappened = true; + + switch(gbLcdMode) + { + case 0: + { + // H-Blank + // check if we reached the V-Blank period + if(register_LY == 144) { + // Yes, V-Blank + // set the LY increment counter + if (gbHardware & 0x5) + { + register_IF |= 1; // V-Blank interrupt + } + + gbInt48Signal &= ~6; + if(register_STAT & 0x10) + { + // send LCD interrupt only if no interrupt 48h signal... + if ((!(gbInt48Signal & 1)) && ((!(gbInt48Signal & 8)) || (gbHardware & 0x0a))) + { + register_IF |=2; + gbInterruptLaunched |= 2; + if (gbHardware & 0xa) + gbInterruptWait = 1; + } + gbInt48Signal |= 2; + } + gbInt48Signal &= ~1; + + gbLcdTicks += GBLCD_MODE_1_CLOCK_TICKS; + gbLcdMode = 1; + + } else { + // go the the OAM being accessed mode + gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; + gbLcdMode = 2; + + gbInt48Signal &= ~6; + if(register_STAT & 0x20) + { + // send LCD interrupt only if no interrupt 48h signal... + if (!gbInt48Signal) + { + register_IF |= 2; + gbInterruptLaunched |= 2; + } + gbInt48Signal |= 4; + } + gbInt48Signal &= ~1; + } + } + break; + case 1: + { + // V-Blank + // next mode is OAM being accessed mode + gbInt48Signal &= ~5; + if(register_STAT & 0x20) + { + // send LCD interrupt only if no interrupt 48h signal... + if (!gbInt48Signal) + { + register_IF |= 2; + gbInterruptLaunched |= 2; + if ((gbHardware & 0xa) && (IFF & 0x80)) + gbInterruptWait = 1; + } + gbInt48Signal |= 4; + } + gbInt48Signal &= ~2; + + gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; + + gbLcdMode = 2; + register_LY = 0x00; + + } + break; + case 2: + { + + // OAM being accessed mode + // next mode is OAM and VRAM in use + if ((gbScreenOn) && (register_LCDC & 0x80)) + { + gbDrawSprites(false); + // Used to add a one tick delay when a window line is drawn. + //(fixes a part of Carmaggedon problem) + if((register_LCDC & 0x01 || gbCgbMode) && (register_LCDC & 0x20) && + (gbWindowLine != -2)) { + + int inUseRegister_WY = 0; + int tempgbWindowLine = gbWindowLine; + + if ((tempgbWindowLine == -1) || (tempgbWindowLine>144)) + { + inUseRegister_WY = oldRegister_WY; + if (register_LY>oldRegister_WY) + tempgbWindowLine = 146; + } + + int wy = inUseRegister_WY; + + if(register_LY >= inUseRegister_WY) { + + if (tempgbWindowLine == -1) + tempgbWindowLine = 0; + + int wx = register_WX; + wx -= 7; + if (wx<0) + wx = 0; + + if((wx <= 159) && (tempgbWindowLine <= 143)) + for (int i = wx; i<300; i++) + if (gbSpeed) + gbSpritesTicks[i]+=3; + else + gbSpritesTicks[i]+=1; + } + } + } + + gbInt48Signal &= ~7; + + gbLcdTicks += GBLCD_MODE_3_CLOCK_TICKS+gbSpritesTicks[299]; + gbLcdMode = 3; + } + break; + case 3: + { + // OAM and VRAM in use + // next mode is H-Blank + + + gbInt48Signal &= ~7; + if(register_STAT & 0x08) + { + // send LCD interrupt only if no interrupt 48h signal... + if (!(gbInt48Signal & 8)) + { + register_IF |= 2; + if ((gbHardware & 0xa) && (IFF & 0x80)) + gbInterruptWait = 1; + } + gbInt48Signal |= 1; + } + + gbLcdTicks += GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]; + + gbLcdMode = 0; + + // No HDMA during HALT ! + if(gbHdmaOn && (!(IFF & 0x80) || (register_IE & register_IF & 0x1f))) { + gbDoHdma(); + } + + } + break; + } + } + + + if ((gbLcdTicksDelayed <= 0) && (gbLCDChangeHappened)) { + int framesToSkip = systemFrameSkip; + if(speedup) + framesToSkip = 9; // try 6 FPS during speedup + //gbLcdTicksDelayed = gbLcdTicks+1; + gbLCDChangeHappened = false; + switch(gbLcdModeDelayed) { + case 0: + { + // H-Blank + + memset(gbSCYLine,gbSCYLine[299],sizeof(gbSCYLine)); + memset(gbSCXLine,gbSCXLine[299],sizeof(gbSCXLine)); + memset(gbBgpLine,gbBgpLine[299],sizeof(gbBgpLine)); + memset(gbObp0Line,gbObp0Line[299],sizeof(gbObp0Line)); + memset(gbObp1Line,gbObp1Line[299],sizeof(gbObp1Line)); + memset(gbSpritesTicks,gbSpritesTicks[299],sizeof(gbSpritesTicks)); + + if (gbWindowLine <0) + oldRegister_WY = register_WY; + // check if we reached the V-Blank period + if(register_LY == 144) { + // Yes, V-Blank + // set the LY increment counter + + if(register_LCDC & 0x80) { + if (gbHardware & 0xa) + { + + register_IF |= 1; // V-Blank interrupt + gbInterruptLaunched |=1; + } + + + } + + gbLcdTicksDelayed += GBLCD_MODE_1_CLOCK_TICKS; + gbLcdModeDelayed = 1; + + gbFrameCount++; + systemFrame(); + + if((gbFrameCount % 10) == 0) + system10Frames(60); + + if(gbFrameCount >= 60) { + u32 currentTime = systemGetClock(); + if(currentTime != gbLastTime) + systemShowSpeed(100000/(currentTime - gbLastTime)); + else + systemShowSpeed(0); + gbLastTime = currentTime; + gbFrameCount = 0; + } + + if(systemReadJoypads()) { + // read joystick + if(gbSgbMode && gbSgbMultiplayer) { + if(gbSgbFourPlayers) { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + gbJoymask[2] = systemReadJoypad(2); + gbJoymask[3] = systemReadJoypad(3); + } else { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + } + } else { + gbJoymask[0] = systemReadJoypad(-1); + } + } + int newmask = gbJoymask[0] & 255; + + if(gbRomType == 0x22) { + systemUpdateMotionSensor(); + } + + if(newmask) + { + gbMemory[0xff0f] |= 16; + } + + + newmask = (gbJoymask[0] >> 10); + + speedup = (newmask & 1) ? true : false; + gbCapture = (newmask & 2) ? true : false; + + if(gbCapture && !gbCapturePrevious) { + gbCaptureNumber++; + systemScreenCapture(gbCaptureNumber); + } + gbCapturePrevious = gbCapture; + + if(gbFrameSkipCount >= framesToSkip) { + + if(!gbSgbMask) + { + if (gbBorderOn) + gbSgbRenderBorder(); + //if (gbScreenOn) + systemDrawScreen(); + } + gbFrameSkipCount = 0; + } else + gbFrameSkipCount++; + + } else { + // go the the OAM being accessed mode + gbLcdTicksDelayed += GBLCD_MODE_2_CLOCK_TICKS; + gbLcdModeDelayed = 2; + gbInt48Signal &= ~3; + } + } + break; + case 1: + { + // V-Blank + // next mode is OAM being accessed mode + + // gbScreenOn = true; + + oldRegister_WY = register_WY; + + gbLcdTicksDelayed += GBLCD_MODE_2_CLOCK_TICKS; + gbLcdModeDelayed = 2; + + // reset the window line + gbWindowLine = -1; + } + break; + case 2: + { + // OAM being accessed mode + // next mode is OAM and VRAM in use + gbLcdTicksDelayed += GBLCD_MODE_3_CLOCK_TICKS+gbSpritesTicks[299]; + gbLcdModeDelayed = 3; + } + break; + case 3: + { + + // OAM and VRAM in use + // next mode is H-Blank + if((register_LY < 144) && (register_LCDC & 0x80) && gbScreenOn) { + if(!gbSgbMask) { + if(gbFrameSkipCount >= framesToSkip) { + if (!gbBlackScreen) + { + gbRenderLine(); + gbDrawSprites(true); + } + else if (gbBlackScreen) + { + u16 color = gbColorOption ? gbColorFilter[0] : 0; + if (!gbCgbMode) + color = gbColorOption ? gbColorFilter[gbPalette[3] & 0x7FFF] : + gbPalette[3] & 0x7FFF; + for(int i = 0; i < 160; i++) + { + gbLineMix[i] = color; + gbLineBuffer[i] = 0; + } + } + gbDrawLine(); + } + } + } + gbLcdTicksDelayed += GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]; + gbLcdModeDelayed = 0; + } + break; + } + } + + if ((gbLcdLYIncrementTicksDelayed <= 0) && (gbLYChangeHappened == true)) + { + + gbLYChangeHappened = false; + + if (!((gbLcdMode != 1) && (register_LY==0))) + { + { + gbInt48Signal &= ~8; + gbCompareLYToLYC(); + if ((gbInt48Signal == 8) && (!((register_LY == 0) && (gbHardware & 1)))) + gbInterruptLaunched |= 2; + if ((gbHardware & (gbSpeed ? 8 : 2)) && (register_LY==0) && ((register_STAT & 0x44) == 0x44) && (gbLcdLYIncrementTicksDelayed==0)) + { + gbInterruptWait = 1; + + } + } + } + gbLcdLYIncrementTicksDelayed += GBLY_INCREMENT_CLOCK_TICKS; + + if (gbLcdModeDelayed == 1) + { + + if(register_LY == 153) + gbLcdLYIncrementTicksDelayed -= GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; + else if(register_LY == 0) + gbLcdLYIncrementTicksDelayed += GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; + } + gbMemory[0xff0f] = register_IF; + gbMemory[0xff41] = register_STAT; + } + } + gbMemory[0xff0f] = register_IF; + gbMemory[0xff41] = register_STAT = (register_STAT & 0xfc) | gbLcdModeDelayed; + } + else + { + + // Used to update the screen with white lines when it's off. + // (it looks strange, but it's kinda accurate :p) + // You can try the Mario Demo Vx.x for exemple + // (check the bottom 2 lines while moving) + if (!gbWhiteScreen) + { + gbScreenTicks -= clockTicks; + gbLcdLYIncrementTicks -= clockTicks; + while (gbLcdLYIncrementTicks <=0) + { + register_LY = ((register_LY+1)%154); + gbLcdLYIncrementTicks+=GBLY_INCREMENT_CLOCK_TICKS; + } + if (gbScreenTicks <= 0) + { + gbWhiteScreen = 1; + u8 register_LYLcdOff = ((register_LY+154)%154); + for (register_LY=0;register_LY <= 0x90;register_LY++) + { + u16 color = gbColorOption ? gbColorFilter[0x7FFF] : + 0x7FFF; + if (!gbCgbMode) + color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : + gbPalette[0] & 0x7FFF; + for(int i = 0; i < 160; i++) + { + gbLineMix[i] = color; + gbLineBuffer[i] = 0; + } + gbDrawLine(); + } + register_LY = register_LYLcdOff; + } + } + + if (gbWhiteScreen) + { + gbLcdLYIncrementTicks -= clockTicks; + + while (gbLcdLYIncrementTicks <=0) + { + register_LY = ((register_LY+1)%154); + gbLcdLYIncrementTicks+=GBLY_INCREMENT_CLOCK_TICKS; + if (register_LY<144) + { + + u16 color = gbColorOption ? gbColorFilter[0x7FFF] : + 0x7FFF; + if (!gbCgbMode) + color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : + gbPalette[0] & 0x7FFF; + for(int i = 0; i < 160; i++) + { + gbLineMix[i] = color; + gbLineBuffer[i] = 0; + } + gbDrawLine(); + } + else if ((register_LY==144) && (!systemFrameSkip)) + { + int framesToSkip = systemFrameSkip; + if(speedup) + framesToSkip = 9; // try 6 FPS during speedup + if((gbFrameSkipCount >= framesToSkip) || (gbWhiteScreen == 1)) { + gbWhiteScreen = 2; + + if(!gbSgbMask) + { + if (gbBorderOn) + gbSgbRenderBorder(); + //if (gbScreenOn) + systemDrawScreen(); + } + } + if(systemReadJoypads()) { + // read joystick + if(gbSgbMode && gbSgbMultiplayer) { + if(gbSgbFourPlayers) { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + gbJoymask[2] = systemReadJoypad(2); + gbJoymask[3] = systemReadJoypad(3); + } else { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + } + } else { + gbJoymask[0] = systemReadJoypad(-1); + } + } + gbFrameCount++; + + systemFrame(); + + if((gbFrameCount % 10) == 0) + system10Frames(60); + + if(gbFrameCount >= 60) { + u32 currentTime = systemGetClock(); + if(currentTime != gbLastTime) + systemShowSpeed(100000/(currentTime - gbLastTime)); + else + systemShowSpeed(0); + gbLastTime = currentTime; + gbFrameCount = 0; + } + } + } + } + } + + gbMemory[0xff41] = register_STAT; + + // serial emulation + if(gbSerialOn) { +#ifdef LINK_EMULATION + if(linkConnected) { + gbSerialTicks -= clockTicks; + + while(gbSerialTicks <= 0) { + // increment number of shifted bits + gbSerialBits++; + linkProc(); + if(gbSerialOn && (gbMemory[0xff02] & 1)) { + if(gbSerialBits == 8) { + gbSerialBits = 0; + gbMemory[0xff01] = 0xff; + gbMemory[0xff02] &= 0x7f; + gbSerialOn = 0; + gbMemory[0xff0f] = register_IF |= 8; + gbSerialTicks = 0; + } + } + gbSerialTicks += GBSERIAL_CLOCK_TICKS; + } + } else { +#endif + if(gbMemory[0xff02] & 1) { + gbSerialTicks -= clockTicks; + + // overflow + while(gbSerialTicks <= 0) { + // shift serial byte to right and put a 1 bit in its place + // gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1); + // increment number of shifted bits + gbSerialBits++; + if(gbSerialBits == 8) { + // end of transmission + if(gbSerialFunction) // external device + gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); + else + gbMemory[0xff01] = 0xff; + gbSerialTicks = 0; + gbMemory[0xff02] &= 0x7f; + gbSerialOn = 0; + gbMemory[0xff0f] = register_IF |= 8; + gbSerialBits = 0; + } else + gbSerialTicks += GBSERIAL_CLOCK_TICKS; + } + } +#ifdef LINK_EMULATION + } +#endif + } + + + soundTicks -= clockTicks; + if ( !gbSpeed ) + soundTicks -= clockTicks; + + while(soundTicks < 0) { + soundTicks += SOUND_CLOCK_TICKS; + + gbSoundTick(); + } + + + // timer emulation + + if(gbTimerOn) { + gbTimerTicks= ((gbInternalTimer) & gbTimerMask[gbTimerMode])+1-clockTicks; + + while(gbTimerTicks <= 0) { + register_TIMA++; + // timer overflow! + if((register_TIMA & 0xff) == 0) { + // reload timer modulo + register_TIMA = register_TMA; + // flag interrupt + gbMemory[0xff0f] = register_IF |= 4; + } + gbTimerTicks += gbTimerClockTicks; + } + gbTimerOnChange = false; + gbTimerModeChange = false; + + gbMemory[0xff05] = register_TIMA; + + } + + gbInternalTimer -= clockTicks; + while (gbInternalTimer<0) + gbInternalTimer+=0x100; + + /* + if(soundOffFlag) { + if(synchronize && !speedup) { + synchronizeTicks -= clockTicks; + + while(synchronizeTicks < 0) { + synchronizeTicks += SYNCHRONIZE_CLOCK_TICKS; + + DWORD now = timeGetTime(); + gbElapsedTime += (now - timeNow); + + if(gbElapsedTime < 50) { + DWORD diff = 50 - gbElapsedTime; + Sleep(diff); + timeNow = timeGetTime(); + elapsedTime = timeNow - now - diff; + if((int)elapsedTime < 0) + elapsedTime = 0; + } else { + timeNow = timeGetTime(); + elapsedTime = 0; + } + } + } + } + */ + + clockTicks = 0; + + if (gbIntBreak == 1) + { + gbIntBreak = 0; + if ((register_IE & register_IF & gbInterruptLaunched & 0x3) && + ((IFF & 0x81) == 1) && (!gbInterruptWait) && (execute)) + { + gbIntBreak = 2; + PC.W = oldPCW; + execute = false; + gbOldClockTicks = 0; + } + if (gbOldClockTicks) + { + clockTicks = gbOldClockTicks; + gbOldClockTicks = 0; + goto gbRedoLoop; + } + } + + // Executes the opcode(s), and apply the instruction's remaining clockTicks (if any). + if (execute) + { + switch(opcode1) { + case 0xCB: + // extended opcode + switch(opcode2) { +#include "gbCodesCB.h" + } + break; +#include "gbCodes.h" + } + execute = false; + + if (clockTicks) + { + gbDmaTicks += clockTicks; + clockTicks = 0; + } + } + + if (gbDmaTicks) + { + clockTicks = gbGetNextEvent(gbDmaTicks); + + if (clockTicks<=gbDmaTicks) + gbDmaTicks -= clockTicks; + else + { + clockTicks = gbDmaTicks; + gbDmaTicks = 0; + } + + goto gbRedoLoop; + } + + + // Remove the 'if an IE is pending' flag if IE has finished being executed. + if ((IFF & 0x40) && !(IFF & 0x30)) + IFF &= 0x81; + + + + if ((register_IE & register_IF & 0x1f) && (IFF & 0x81) && (!gbInterruptWait)) + { + + if (IFF & 1) + { + // Add 5 ticks for the interrupt execution time + gbDmaTicks += 5; + + if (gbIntBreak == 2) + { + gbDmaTicks--; + gbIntBreak = 0; + } + + + if(register_IF & register_IE & 1) + gbVblank_interrupt(); + else if(register_IF & register_IE & 2) + gbLcd_interrupt(); + else if(register_IF & register_IE & 4) + gbTimer_interrupt(); + else if(register_IF & register_IE & 8) + gbSerial_interrupt(); + else if(register_IF & register_IE & 16) + gbJoypad_interrupt(); + } + + IFF &= ~0x81; + } + + if (IFF & 0x08) + IFF &=~0x79; + + // Used to apply the interrupt's execution time. + if (gbDmaTicks) + { + clockTicks = gbGetNextEvent(gbDmaTicks); + + if (clockTicks<=gbDmaTicks) + gbDmaTicks -= clockTicks; + else + { + clockTicks = gbDmaTicks; + gbDmaTicks = 0; + } + goto gbRedoLoop; + } + + + gbBlackScreen = false; + + if((ticksToStop <= 0)) { + if(!(register_LCDC & 0x80)) { + if(systemReadJoypads()) { + // read joystick + if(gbSgbMode && gbSgbMultiplayer) { + if(gbSgbFourPlayers) { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + gbJoymask[2] = systemReadJoypad(2); + gbJoymask[3] = systemReadJoypad(3); + } else { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + } + } else { + gbJoymask[0] = systemReadJoypad(-1); + } + } + } + return; + } + } +} + +struct EmulatedSystem GBSystem = { + // emuMain + gbEmulate, + // emuReset + gbReset, + // emuCleanUp + gbCleanUp, + // emuReadBattery + gbReadBatteryFile, + // emuWriteBattery + gbWriteBatteryFile, + // emuReadState + gbReadSaveState, + // emuWriteState + gbWriteSaveState, + // emuReadMemState + gbReadMemSaveState, + // emuWriteMemState + gbWriteMemSaveState, + // emuWritePNG + gbWritePNGFile, + // emuWriteBMP + gbWriteBMPFile, + // emuUpdateCPSR + NULL, + // emuHasDebugger + false, + // emuCount +#ifdef FINAL_VERSION + 70000/4, +#else + 1000, +#endif +}; diff --git a/src/dmg/gb.h b/src/dmg/gb.h index 1ae77248..26099f14 100644 --- a/src/dmg/gb.h +++ b/src/dmg/gb.h @@ -1,64 +1,64 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005-2006 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef VBA_GB_GB_H -#define VBA_GB_GB_H - -#define C_FLAG 0x10 -#define H_FLAG 0x20 -#define N_FLAG 0x40 -#define Z_FLAG 0x80 - -typedef union { - struct { -#ifdef WORDS_BIGENDIAN - u8 B1, B0; -#else - u8 B0,B1; -#endif - } B; - u16 W; -} gbRegister; - -extern bool gbLoadRom(const char *); -extern void gbEmulate(int); -extern void gbWriteMemory(register u16, register u8); -extern void gbDrawLine(); -extern bool gbIsGameboyRom(const char *); -extern void gbSoundReset(); -extern void gbSoundSetQuality(int); -extern void gbGetHardwareType(); -extern void gbReset(); -extern void gbCleanUp(); -extern void gbCPUInit(const char *,bool); -extern bool gbWriteBatteryFile(const char *); -extern bool gbWriteBatteryFile(const char *, bool); -extern bool gbReadBatteryFile(const char *); -extern bool gbWriteSaveState(const char *); -extern bool gbWriteMemSaveState(char *, int); -extern bool gbReadSaveState(const char *); -extern bool gbReadMemSaveState(char *, int); -extern void gbSgbRenderBorder(); -extern bool gbWritePNGFile(const char *); -extern bool gbWriteBMPFile(const char *); -extern bool gbReadGSASnapshot(const char *); - -extern struct EmulatedSystem GBSystem; - -#endif +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef VBA_GB_GB_H +#define VBA_GB_GB_H + +#define C_FLAG 0x10 +#define H_FLAG 0x20 +#define N_FLAG 0x40 +#define Z_FLAG 0x80 + +typedef union { + struct { +#ifdef WORDS_BIGENDIAN + u8 B1, B0; +#else + u8 B0,B1; +#endif + } B; + u16 W; +} gbRegister; + +extern bool gbLoadRom(const char *); +extern void gbEmulate(int); +extern void gbWriteMemory(register u16, register u8); +extern void gbDrawLine(); +extern bool gbIsGameboyRom(const char *); +extern void gbSoundReset(); +extern void gbSoundSetQuality(int); +extern void gbGetHardwareType(); +extern void gbReset(); +extern void gbCleanUp(); +extern void gbCPUInit(const char *,bool); +extern bool gbWriteBatteryFile(const char *); +extern bool gbWriteBatteryFile(const char *, bool); +extern bool gbReadBatteryFile(const char *); +extern bool gbWriteSaveState(const char *); +extern bool gbWriteMemSaveState(char *, int); +extern bool gbReadSaveState(const char *); +extern bool gbReadMemSaveState(char *, int); +extern void gbSgbRenderBorder(); +extern bool gbWritePNGFile(const char *); +extern bool gbWriteBMPFile(const char *); +extern bool gbReadGSASnapshot(const char *); + +extern struct EmulatedSystem GBSystem; + +#endif diff --git a/src/dmg/gbCheats.cpp b/src/dmg/gbCheats.cpp index e7c44282..2463d282 100644 --- a/src/dmg/gbCheats.cpp +++ b/src/dmg/gbCheats.cpp @@ -1,522 +1,522 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include -#include -#include -#include - -#include "../System.h" -#include "../NLS.h" -#include "../Util.h" - -#include "gbCheats.h" -#include "gbGlobals.h" -#include "gb.h" - -gbCheat gbCheatList[100]; -int gbCheatNumber = 0; -int gbNextCheat = 0; -bool gbCheatMap[0x10000]; - -extern bool cheatsEnabled; - -#define GBCHEAT_IS_HEX(a) ( ((a)>='A' && (a) <='F') || ((a) >='0' && (a) <= '9')) -#define GBCHEAT_HEX_VALUE(a) ( (a) >= 'A' ? (a) - 'A' + 10 : (a) - '0') - -void gbCheatUpdateMap() -{ - memset(gbCheatMap, 0, 0x10000); - - for(int i = 0; i < gbCheatNumber; i++) { - if(gbCheatList[i].enabled) - gbCheatMap[gbCheatList[i].address] = true; - } -} - -void gbCheatsSaveGame(gzFile gzFile) -{ - utilWriteInt(gzFile, gbCheatNumber); - if(gbCheatNumber>0) - utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber); -} - -void gbCheatsReadGame(gzFile gzFile, int version) -{ - if(version <= 8) { - int gbGgOn = utilReadInt(gzFile); - - if(gbGgOn) { - int n = utilReadInt(gzFile); - gbXxCheat tmpCheat; - for(int i = 0; i < n; i++) { - utilGzRead(gzFile,&tmpCheat, sizeof(gbXxCheat)); - gbAddGgCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc); - } - } - - int gbGsOn = utilReadInt(gzFile); - - if(gbGsOn) { - int n = utilReadInt(gzFile); - gbXxCheat tmpCheat; - for(int i = 0; i < n; i++) { - utilGzRead(gzFile,&tmpCheat, sizeof(gbXxCheat)); - gbAddGsCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc); - } - } - } else { - gbCheatNumber = utilReadInt(gzFile); - - if(gbCheatNumber>0) { - utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber); - } - } - - gbCheatUpdateMap(); -} - -void gbCheatsSaveCheatList(const char *file) -{ - if(gbCheatNumber == 0) - return; - FILE *f = fopen(file, "wb"); - if(f == NULL) - return; - int version = 1; - fwrite(&version, 1, sizeof(version), f); - int type = 1; - fwrite(&type, 1, sizeof(type), f); - fwrite(&gbCheatNumber, 1, sizeof(gbCheatNumber), f); - fwrite(gbCheatList, 1, sizeof(gbCheatList), f); - fclose(f); -} - -bool gbCheatsLoadCheatList(const char *file) -{ - gbCheatNumber = 0; - - gbCheatUpdateMap(); - - int count = 0; - - FILE *f = fopen(file, "rb"); - - if(f == NULL) - return false; - - int version = 0; - - if(fread(&version, 1, sizeof(version), f) != sizeof(version)) { - fclose(f); - return false; - } - - if(version != 1) { - systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION, - N_("Unsupported cheat list version %d"), version); - fclose(f); - return false; - } - - int type = 0; - if(fread(&type, 1, sizeof(type), f) != sizeof(type)) { - fclose(f); - return false; - } - - if(type != 1) { - systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE, - N_("Unsupported cheat list type %d"), type); - fclose(f); - return false; - } - - if(fread(&count, 1, sizeof(count), f) != sizeof(count)) { - fclose(f); - return false; - } - - if(fread(gbCheatList, 1, sizeof(gbCheatList), f) != sizeof(gbCheatList)) { - fclose(f); - return false; - } - - gbCheatNumber = count; - gbCheatUpdateMap(); - - return true; -} - -bool gbVerifyGsCode(const char *code) -{ - size_t len = strlen(code); - - if(len == 0) - return true; - - if(len != 8) - return false; - - for(int i = 0; i < 8; i++) - if(!GBCHEAT_IS_HEX(code[i])) - return false; - - int address = GBCHEAT_HEX_VALUE(code[6]) << 12 | - GBCHEAT_HEX_VALUE(code[7]) << 8 | - GBCHEAT_HEX_VALUE(code[4]) << 4 | - GBCHEAT_HEX_VALUE(code[5]); - - return true; -} - -bool gbAddGsCheat(const char *code, const char *desc) -{ - if(gbCheatNumber > 99) { - systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS, - N_("Maximum number of cheats reached.")); - return false; - } - - if(!gbVerifyGsCode(code)) { - systemMessage(MSG_INVALID_GAMESHARK_CODE, - N_("Invalid GameShark code: %s"), code); - return false; - } - - int i = gbCheatNumber; - - strcpy(gbCheatList[i].cheatCode, code); - strcpy(gbCheatList[i].cheatDesc, desc); - - gbCheatList[i].code = GBCHEAT_HEX_VALUE(code[0]) << 4 | - GBCHEAT_HEX_VALUE(code[1]); - - gbCheatList[i].value = GBCHEAT_HEX_VALUE(code[2]) << 4 | - GBCHEAT_HEX_VALUE(code[3]); - - gbCheatList[i].address = GBCHEAT_HEX_VALUE(code[6]) << 12 | - GBCHEAT_HEX_VALUE(code[7]) << 8 | - GBCHEAT_HEX_VALUE(code[4]) << 4 | - GBCHEAT_HEX_VALUE(code[5]); - - gbCheatList[i].compare = 0; - - gbCheatList[i].enabled = true; - - int gsCode = gbCheatList[i].code; - - if ((gsCode !=1) && ((gsCode & 0xF0) !=0x80) && ((gsCode & 0xF0) !=0x90) && - ((gsCode & 0xF0) !=0xA0) && ((gsCode) !=0xF0) && ((gsCode) !=0xF1)) - systemMessage(MSG_WRONG_GAMESHARK_CODE, - N_("Wrong GameShark code type : %s"), code); - else if (((gsCode & 0xF0) ==0xA0) || ((gsCode) ==0xF0) || ((gsCode) ==0xF1)) - systemMessage(MSG_UNSUPPORTED_GAMESHARK_CODE, - N_("Unsupported GameShark code type : %s"), code); - - gbCheatNumber++; - - return true; -} - -bool gbVerifyGgCode(const char *code) -{ - size_t len = strlen(code); - - if(len != 11 && - len != 7 && - len != 6 && - len != 0) - return false; - - if(len == 0) - return true; - - if(!GBCHEAT_IS_HEX(code[0])) - return false; - if(!GBCHEAT_IS_HEX(code[1])) - return false; - if(!GBCHEAT_IS_HEX(code[2])) - return false; - if(code[3] != '-') - return false; - if(!GBCHEAT_IS_HEX(code[4])) - return false; - if(!GBCHEAT_IS_HEX(code[5])) - return false; - if(!GBCHEAT_IS_HEX(code[6])) - return false; - if(code[7] != 0) { - if(code[7] != '-') - return false; - if(code[8] != 0) { - if(!GBCHEAT_IS_HEX(code[8])) - return false; - if(!GBCHEAT_IS_HEX(code[9])) - return false; - if(!GBCHEAT_IS_HEX(code[10])) - return false; - } - } - - // int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) + - // GBCHEAT_HEX_VALUE(code[1]); - - int address = (GBCHEAT_HEX_VALUE(code[2]) << 8) + - (GBCHEAT_HEX_VALUE(code[4]) << 4) + - (GBCHEAT_HEX_VALUE(code[5])) + - ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12); - - if(address >= 0x8000 && address <= 0x9fff) - return false; - - if(address >= 0xc000) - return false; - - if(code[7] == 0 || code[8] == '0') - return true; - - int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) + - (GBCHEAT_HEX_VALUE(code[10])); - compare = compare ^ 0xff; - compare = (compare >> 2) | ( (compare << 6) & 0xc0); - compare ^= 0x45; - - int cloak = (GBCHEAT_HEX_VALUE(code[8])) ^ (GBCHEAT_HEX_VALUE(code[9])); - - if(cloak >=1 && cloak <= 7) - return false; - - return true; -} - -bool gbAddGgCheat(const char *code, const char *desc) -{ - if(gbCheatNumber > 99) { - systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS, - N_("Maximum number of cheats reached.")); - return false; - } - - if(!gbVerifyGgCode(code)) { - systemMessage(MSG_INVALID_GAMEGENIE_CODE, - N_("Invalid GameGenie code: %s"), code); - return false; - } - - int i = gbCheatNumber; - - size_t len = strlen(code); - - strcpy(gbCheatList[i].cheatCode, code); - strcpy(gbCheatList[i].cheatDesc, desc); - - gbCheatList[i].code = 0x101; - gbCheatList[i].value = (GBCHEAT_HEX_VALUE(code[0]) << 4) + - GBCHEAT_HEX_VALUE(code[1]); - - gbCheatList[i].address = (GBCHEAT_HEX_VALUE(code[2]) << 8) + - (GBCHEAT_HEX_VALUE(code[4]) << 4) + - (GBCHEAT_HEX_VALUE(code[5])) + - ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12); - - gbCheatList[i].compare = 0; - - if(len != 7 && len != 8) { - - int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) + - (GBCHEAT_HEX_VALUE(code[10])); - compare = compare ^ 0xff; - compare = (compare >> 2) | ( (compare << 6) & 0xc0); - compare ^= 0x45; - - gbCheatList[i].compare = compare; - //gbCheatList[i].code = 0; - gbCheatList[i].code = 0x100; // fix for compare value - - } - - - gbCheatList[i].enabled = true; - - gbCheatMap[gbCheatList[i].address] = true; - - gbCheatNumber++; - - return true; -} - -void gbCheatRemove(int i) -{ - if(i < 0 || i >= gbCheatNumber) { - systemMessage(MSG_INVALID_CHEAT_TO_REMOVE, - N_("Invalid cheat to remove %d"), i); - return; - } - - if((i+1) < gbCheatNumber) { - memcpy(&gbCheatList[i], &gbCheatList[i+1], sizeof(gbCheat)* - (gbCheatNumber-i-1)); - } - - gbCheatNumber--; - - gbCheatUpdateMap(); -} - -void gbCheatRemoveAll() -{ - gbCheatNumber = 0; - gbCheatUpdateMap(); -} - -void gbCheatEnable(int i) -{ - if(i >=0 && i < gbCheatNumber) { - if(!gbCheatList[i].enabled) { - gbCheatList[i].enabled = true; - gbCheatUpdateMap(); - } - } -} - -void gbCheatDisable(int i) -{ - if(i >=0 && i < gbCheatNumber) { - if(gbCheatList[i].enabled) { - gbCheatList[i].enabled = false; - gbCheatUpdateMap(); - } - } -} - -bool gbCheatReadGSCodeFile(const char *fileName) -{ - FILE *file = fopen(fileName, "rb"); - - if(!file) { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); - return false; - } - - fseek(file, 0x18, SEEK_SET); - int count = 0; - fread(&count, 1, 2, file); - int dummy = 0; - gbCheatRemoveAll(); - char desc[13]; - char code[9]; - int i; - for(i = 0; i < count; i++) { - fread(&dummy, 1, 2, file); - fread(desc, 1, 12, file); - desc[12] = 0; - fread(code, 1, 8, file); - code[8] = 0; - gbAddGsCheat(code, desc); - } - - for(i = 0; i < gbCheatNumber; i++) - gbCheatDisable(i); - - fclose(file); - return true; -} - -// Used to emulated GG codes -u8 gbCheatRead(u16 address) -{ - if(!cheatsEnabled) - return gbMemoryMap[address>>12][address & 0xFFF]; - - for(int i = 0; i < gbCheatNumber; i++) { - if(gbCheatList[i].enabled && gbCheatList[i].address == address) { - switch(gbCheatList[i].code) { - case 0x100: // GameGenie support - if(gbMemoryMap[address>>12][address&0xFFF] == gbCheatList[i].compare) - return gbCheatList[i].value; - break; - case 0x101: // GameGenie 6 digits code support - return gbCheatList[i].value; - break; - } - } - } - return gbMemoryMap[address>>12][address&0xFFF]; -} - - -// Used to emulate GS codes. -void gbCheatWrite(bool reboot) -{ - if(cheatsEnabled) - { - u16 address = 0; - - if (gbNextCheat >= gbCheatNumber) - gbNextCheat = 0; - - for(int i = gbNextCheat; i < gbCheatNumber; i++) { - if(gbCheatList[i].enabled) { - address = gbCheatList[i].address; - if ((!reboot) && (address >= 0x8000) && !((address>=0xA000) && (address<0xC000))) - { // These codes are executed one per one, at each Vblank - switch(gbCheatList[i].code) { - case 0x01: - gbWriteMemory(address, gbCheatList[i].value); - gbNextCheat = i+1; - return; - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9A: - case 0x9B: - case 0x9C: - case 0x9D: - case 0x9E: - case 0x9F: - int oldbank = gbMemory[0xff70]; - gbWriteMemory(0xff70, gbCheatList[i].code & 0xf); - gbWriteMemory(address, gbCheatList[i].value); - gbWriteMemory(0xff70, oldbank); - gbNextCheat = i+1; - return; - } - } - else // These codes are only executed when the game is booted - { - switch(gbCheatList[i].code & 0xF0) { - case 0x80: - gbWriteMemory(0x0000, 0x0A); - gbWriteMemory(0x4000, gbCheatList[i].value & 0xF); - gbWriteMemory(address, gbCheatList[i].value); - gbNextCheat = i+1; - return; - } - } - } - } - } -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include +#include +#include + +#include "../System.h" +#include "../NLS.h" +#include "../Util.h" + +#include "gbCheats.h" +#include "gbGlobals.h" +#include "gb.h" + +gbCheat gbCheatList[100]; +int gbCheatNumber = 0; +int gbNextCheat = 0; +bool gbCheatMap[0x10000]; + +extern bool cheatsEnabled; + +#define GBCHEAT_IS_HEX(a) ( ((a)>='A' && (a) <='F') || ((a) >='0' && (a) <= '9')) +#define GBCHEAT_HEX_VALUE(a) ( (a) >= 'A' ? (a) - 'A' + 10 : (a) - '0') + +void gbCheatUpdateMap() +{ + memset(gbCheatMap, 0, 0x10000); + + for(int i = 0; i < gbCheatNumber; i++) { + if(gbCheatList[i].enabled) + gbCheatMap[gbCheatList[i].address] = true; + } +} + +void gbCheatsSaveGame(gzFile gzFile) +{ + utilWriteInt(gzFile, gbCheatNumber); + if(gbCheatNumber>0) + utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber); +} + +void gbCheatsReadGame(gzFile gzFile, int version) +{ + if(version <= 8) { + int gbGgOn = utilReadInt(gzFile); + + if(gbGgOn) { + int n = utilReadInt(gzFile); + gbXxCheat tmpCheat; + for(int i = 0; i < n; i++) { + utilGzRead(gzFile,&tmpCheat, sizeof(gbXxCheat)); + gbAddGgCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc); + } + } + + int gbGsOn = utilReadInt(gzFile); + + if(gbGsOn) { + int n = utilReadInt(gzFile); + gbXxCheat tmpCheat; + for(int i = 0; i < n; i++) { + utilGzRead(gzFile,&tmpCheat, sizeof(gbXxCheat)); + gbAddGsCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc); + } + } + } else { + gbCheatNumber = utilReadInt(gzFile); + + if(gbCheatNumber>0) { + utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber); + } + } + + gbCheatUpdateMap(); +} + +void gbCheatsSaveCheatList(const char *file) +{ + if(gbCheatNumber == 0) + return; + FILE *f = fopen(file, "wb"); + if(f == NULL) + return; + int version = 1; + fwrite(&version, 1, sizeof(version), f); + int type = 1; + fwrite(&type, 1, sizeof(type), f); + fwrite(&gbCheatNumber, 1, sizeof(gbCheatNumber), f); + fwrite(gbCheatList, 1, sizeof(gbCheatList), f); + fclose(f); +} + +bool gbCheatsLoadCheatList(const char *file) +{ + gbCheatNumber = 0; + + gbCheatUpdateMap(); + + int count = 0; + + FILE *f = fopen(file, "rb"); + + if(f == NULL) + return false; + + int version = 0; + + if(fread(&version, 1, sizeof(version), f) != sizeof(version)) { + fclose(f); + return false; + } + + if(version != 1) { + systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION, + N_("Unsupported cheat list version %d"), version); + fclose(f); + return false; + } + + int type = 0; + if(fread(&type, 1, sizeof(type), f) != sizeof(type)) { + fclose(f); + return false; + } + + if(type != 1) { + systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE, + N_("Unsupported cheat list type %d"), type); + fclose(f); + return false; + } + + if(fread(&count, 1, sizeof(count), f) != sizeof(count)) { + fclose(f); + return false; + } + + if(fread(gbCheatList, 1, sizeof(gbCheatList), f) != sizeof(gbCheatList)) { + fclose(f); + return false; + } + + gbCheatNumber = count; + gbCheatUpdateMap(); + + return true; +} + +bool gbVerifyGsCode(const char *code) +{ + size_t len = strlen(code); + + if(len == 0) + return true; + + if(len != 8) + return false; + + for(int i = 0; i < 8; i++) + if(!GBCHEAT_IS_HEX(code[i])) + return false; + + int address = GBCHEAT_HEX_VALUE(code[6]) << 12 | + GBCHEAT_HEX_VALUE(code[7]) << 8 | + GBCHEAT_HEX_VALUE(code[4]) << 4 | + GBCHEAT_HEX_VALUE(code[5]); + + return true; +} + +bool gbAddGsCheat(const char *code, const char *desc) +{ + if(gbCheatNumber > 99) { + systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS, + N_("Maximum number of cheats reached.")); + return false; + } + + if(!gbVerifyGsCode(code)) { + systemMessage(MSG_INVALID_GAMESHARK_CODE, + N_("Invalid GameShark code: %s"), code); + return false; + } + + int i = gbCheatNumber; + + strcpy(gbCheatList[i].cheatCode, code); + strcpy(gbCheatList[i].cheatDesc, desc); + + gbCheatList[i].code = GBCHEAT_HEX_VALUE(code[0]) << 4 | + GBCHEAT_HEX_VALUE(code[1]); + + gbCheatList[i].value = GBCHEAT_HEX_VALUE(code[2]) << 4 | + GBCHEAT_HEX_VALUE(code[3]); + + gbCheatList[i].address = GBCHEAT_HEX_VALUE(code[6]) << 12 | + GBCHEAT_HEX_VALUE(code[7]) << 8 | + GBCHEAT_HEX_VALUE(code[4]) << 4 | + GBCHEAT_HEX_VALUE(code[5]); + + gbCheatList[i].compare = 0; + + gbCheatList[i].enabled = true; + + int gsCode = gbCheatList[i].code; + + if ((gsCode !=1) && ((gsCode & 0xF0) !=0x80) && ((gsCode & 0xF0) !=0x90) && + ((gsCode & 0xF0) !=0xA0) && ((gsCode) !=0xF0) && ((gsCode) !=0xF1)) + systemMessage(MSG_WRONG_GAMESHARK_CODE, + N_("Wrong GameShark code type : %s"), code); + else if (((gsCode & 0xF0) ==0xA0) || ((gsCode) ==0xF0) || ((gsCode) ==0xF1)) + systemMessage(MSG_UNSUPPORTED_GAMESHARK_CODE, + N_("Unsupported GameShark code type : %s"), code); + + gbCheatNumber++; + + return true; +} + +bool gbVerifyGgCode(const char *code) +{ + size_t len = strlen(code); + + if(len != 11 && + len != 7 && + len != 6 && + len != 0) + return false; + + if(len == 0) + return true; + + if(!GBCHEAT_IS_HEX(code[0])) + return false; + if(!GBCHEAT_IS_HEX(code[1])) + return false; + if(!GBCHEAT_IS_HEX(code[2])) + return false; + if(code[3] != '-') + return false; + if(!GBCHEAT_IS_HEX(code[4])) + return false; + if(!GBCHEAT_IS_HEX(code[5])) + return false; + if(!GBCHEAT_IS_HEX(code[6])) + return false; + if(code[7] != 0) { + if(code[7] != '-') + return false; + if(code[8] != 0) { + if(!GBCHEAT_IS_HEX(code[8])) + return false; + if(!GBCHEAT_IS_HEX(code[9])) + return false; + if(!GBCHEAT_IS_HEX(code[10])) + return false; + } + } + + // int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) + + // GBCHEAT_HEX_VALUE(code[1]); + + int address = (GBCHEAT_HEX_VALUE(code[2]) << 8) + + (GBCHEAT_HEX_VALUE(code[4]) << 4) + + (GBCHEAT_HEX_VALUE(code[5])) + + ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12); + + if(address >= 0x8000 && address <= 0x9fff) + return false; + + if(address >= 0xc000) + return false; + + if(code[7] == 0 || code[8] == '0') + return true; + + int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) + + (GBCHEAT_HEX_VALUE(code[10])); + compare = compare ^ 0xff; + compare = (compare >> 2) | ( (compare << 6) & 0xc0); + compare ^= 0x45; + + int cloak = (GBCHEAT_HEX_VALUE(code[8])) ^ (GBCHEAT_HEX_VALUE(code[9])); + + if(cloak >=1 && cloak <= 7) + return false; + + return true; +} + +bool gbAddGgCheat(const char *code, const char *desc) +{ + if(gbCheatNumber > 99) { + systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS, + N_("Maximum number of cheats reached.")); + return false; + } + + if(!gbVerifyGgCode(code)) { + systemMessage(MSG_INVALID_GAMEGENIE_CODE, + N_("Invalid GameGenie code: %s"), code); + return false; + } + + int i = gbCheatNumber; + + size_t len = strlen(code); + + strcpy(gbCheatList[i].cheatCode, code); + strcpy(gbCheatList[i].cheatDesc, desc); + + gbCheatList[i].code = 0x101; + gbCheatList[i].value = (GBCHEAT_HEX_VALUE(code[0]) << 4) + + GBCHEAT_HEX_VALUE(code[1]); + + gbCheatList[i].address = (GBCHEAT_HEX_VALUE(code[2]) << 8) + + (GBCHEAT_HEX_VALUE(code[4]) << 4) + + (GBCHEAT_HEX_VALUE(code[5])) + + ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12); + + gbCheatList[i].compare = 0; + + if(len != 7 && len != 8) { + + int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) + + (GBCHEAT_HEX_VALUE(code[10])); + compare = compare ^ 0xff; + compare = (compare >> 2) | ( (compare << 6) & 0xc0); + compare ^= 0x45; + + gbCheatList[i].compare = compare; + //gbCheatList[i].code = 0; + gbCheatList[i].code = 0x100; // fix for compare value + + } + + + gbCheatList[i].enabled = true; + + gbCheatMap[gbCheatList[i].address] = true; + + gbCheatNumber++; + + return true; +} + +void gbCheatRemove(int i) +{ + if(i < 0 || i >= gbCheatNumber) { + systemMessage(MSG_INVALID_CHEAT_TO_REMOVE, + N_("Invalid cheat to remove %d"), i); + return; + } + + if((i+1) < gbCheatNumber) { + memcpy(&gbCheatList[i], &gbCheatList[i+1], sizeof(gbCheat)* + (gbCheatNumber-i-1)); + } + + gbCheatNumber--; + + gbCheatUpdateMap(); +} + +void gbCheatRemoveAll() +{ + gbCheatNumber = 0; + gbCheatUpdateMap(); +} + +void gbCheatEnable(int i) +{ + if(i >=0 && i < gbCheatNumber) { + if(!gbCheatList[i].enabled) { + gbCheatList[i].enabled = true; + gbCheatUpdateMap(); + } + } +} + +void gbCheatDisable(int i) +{ + if(i >=0 && i < gbCheatNumber) { + if(gbCheatList[i].enabled) { + gbCheatList[i].enabled = false; + gbCheatUpdateMap(); + } + } +} + +bool gbCheatReadGSCodeFile(const char *fileName) +{ + FILE *file = fopen(fileName, "rb"); + + if(!file) { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); + return false; + } + + fseek(file, 0x18, SEEK_SET); + int count = 0; + fread(&count, 1, 2, file); + int dummy = 0; + gbCheatRemoveAll(); + char desc[13]; + char code[9]; + int i; + for(i = 0; i < count; i++) { + fread(&dummy, 1, 2, file); + fread(desc, 1, 12, file); + desc[12] = 0; + fread(code, 1, 8, file); + code[8] = 0; + gbAddGsCheat(code, desc); + } + + for(i = 0; i < gbCheatNumber; i++) + gbCheatDisable(i); + + fclose(file); + return true; +} + +// Used to emulated GG codes +u8 gbCheatRead(u16 address) +{ + if(!cheatsEnabled) + return gbMemoryMap[address>>12][address & 0xFFF]; + + for(int i = 0; i < gbCheatNumber; i++) { + if(gbCheatList[i].enabled && gbCheatList[i].address == address) { + switch(gbCheatList[i].code) { + case 0x100: // GameGenie support + if(gbMemoryMap[address>>12][address&0xFFF] == gbCheatList[i].compare) + return gbCheatList[i].value; + break; + case 0x101: // GameGenie 6 digits code support + return gbCheatList[i].value; + break; + } + } + } + return gbMemoryMap[address>>12][address&0xFFF]; +} + + +// Used to emulate GS codes. +void gbCheatWrite(bool reboot) +{ + if(cheatsEnabled) + { + u16 address = 0; + + if (gbNextCheat >= gbCheatNumber) + gbNextCheat = 0; + + for(int i = gbNextCheat; i < gbCheatNumber; i++) { + if(gbCheatList[i].enabled) { + address = gbCheatList[i].address; + if ((!reboot) && (address >= 0x8000) && !((address>=0xA000) && (address<0xC000))) + { // These codes are executed one per one, at each Vblank + switch(gbCheatList[i].code) { + case 0x01: + gbWriteMemory(address, gbCheatList[i].value); + gbNextCheat = i+1; + return; + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + int oldbank = gbMemory[0xff70]; + gbWriteMemory(0xff70, gbCheatList[i].code & 0xf); + gbWriteMemory(address, gbCheatList[i].value); + gbWriteMemory(0xff70, oldbank); + gbNextCheat = i+1; + return; + } + } + else // These codes are only executed when the game is booted + { + switch(gbCheatList[i].code & 0xF0) { + case 0x80: + gbWriteMemory(0x0000, 0x0A); + gbWriteMemory(0x4000, gbCheatList[i].value & 0xF); + gbWriteMemory(address, gbCheatList[i].value); + gbNextCheat = i+1; + return; + } + } + } + } + } +} diff --git a/src/dmg/gbCheats.h b/src/dmg/gbCheats.h index f0ad8b26..42e53c6f 100644 --- a/src/dmg/gbCheats.h +++ b/src/dmg/gbCheats.h @@ -1,62 +1,62 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef __VBA_GB_GBCHEATS_H -#define __VBA_GB_GBCHEATS_H - -#include "../System.h" - -struct gbXxCheat { - char cheatDesc[100]; - char cheatCode[20]; -}; - -struct gbCheat { - char cheatCode[20]; - char cheatDesc[32]; - u16 address; - int code; - u8 compare; - u8 value; - bool enabled; -}; - -void gbCheatsSaveGame(gzFile); -void gbCheatsReadGame(gzFile, int); -void gbCheatsSaveCheatList(const char *); -bool gbCheatsLoadCheatList(const char *); -bool gbCheatReadGSCodeFile(const char *); - -bool gbAddGsCheat(const char *, const char*); -bool gbAddGgCheat(const char *, const char*); -void gbCheatRemove(int); -void gbCheatRemoveAll(); -void gbCheatEnable(int); -void gbCheatDisable(int); -u8 gbCheatRead(u16); -void gbCheatWrite(bool); -bool gbVerifyGsCode(const char *code); -bool gbVerifyGgCode(const char *code); - - -extern int gbCheatNumber; -extern gbCheat gbCheatList[100]; -extern bool gbCheatMap[0x10000]; -#endif - +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __VBA_GB_GBCHEATS_H +#define __VBA_GB_GBCHEATS_H + +#include "../System.h" + +struct gbXxCheat { + char cheatDesc[100]; + char cheatCode[20]; +}; + +struct gbCheat { + char cheatCode[20]; + char cheatDesc[32]; + u16 address; + int code; + u8 compare; + u8 value; + bool enabled; +}; + +void gbCheatsSaveGame(gzFile); +void gbCheatsReadGame(gzFile, int); +void gbCheatsSaveCheatList(const char *); +bool gbCheatsLoadCheatList(const char *); +bool gbCheatReadGSCodeFile(const char *); + +bool gbAddGsCheat(const char *, const char*); +bool gbAddGgCheat(const char *, const char*); +void gbCheatRemove(int); +void gbCheatRemoveAll(); +void gbCheatEnable(int); +void gbCheatDisable(int); +u8 gbCheatRead(u16); +void gbCheatWrite(bool); +bool gbVerifyGsCode(const char *code); +bool gbVerifyGgCode(const char *code); + + +extern int gbCheatNumber; +extern gbCheat gbCheatList[100]; +extern bool gbCheatMap[0x10000]; +#endif + diff --git a/src/dmg/gbCodes.h b/src/dmg/gbCodes.h index ff364ee1..5cbae965 100644 --- a/src/dmg/gbCodes.h +++ b/src/dmg/gbCodes.h @@ -1,1460 +1,1460 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005-2006 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - case 0x00: - // NOP - break; - case 0x01: - // LD BC, NNNN - BC.B.B0=gbReadOpcode(PC.W++); - BC.B.B1=gbReadOpcode(PC.W++); - break; - case 0x02: - // LD (BC),A - gbWriteMemory(BC.W,AF.B.B1); - break; - case 0x03: - // INC BC - BC.W++; - break; - case 0x04: - // INC B - BC.B.B1++; - AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B1]| (BC.B.B1&0x0F? 0:H_FLAG); - break; - case 0x05: - // DEC B - BC.B.B1--; - AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B1]| - ((BC.B.B1&0x0F)==0x0F? H_FLAG:0); - break; - case 0x06: - // LD B, NN - BC.B.B1=gbReadOpcode(PC.W++); - break; - case 0x07: - // RLCA - tempValue=AF.B.B1&0x80? C_FLAG:0; - AF.B.B1=(AF.B.B1<<1)|(AF.B.B1>>7); - AF.B.B0=tempValue; - break; - case 0x08: - // LD (NNNN), SP - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W++); - gbWriteMemory(tempRegister.W++,SP.B.B0); - gbWriteMemory(tempRegister.W,SP.B.B1); - break; - case 0x09: - // ADD HL,BC - tempRegister.W=(HL.W+BC.W)&0xFFFF; - AF.B.B0= (AF.B.B0 & Z_FLAG)| ((HL.W^BC.W^tempRegister.W)&0x1000? H_FLAG:0)| - (((long)HL.W+(long)BC.W)&0x10000? C_FLAG:0); - HL.W=tempRegister.W; - break; - case 0x0a: - // LD A,(BC) - AF.B.B1=gbReadMemory(BC.W); - break; - case 0x0b: - // DEC BC - BC.W--; - break; - case 0x0c: - // INC C - BC.B.B0++; - AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B0]| (BC.B.B0&0x0F? 0:H_FLAG); - break; - case 0x0d: - // DEC C - BC.B.B0--; - AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B0]| - ((BC.B.B0&0x0F)==0x0F? H_FLAG:0); - break; - case 0x0e: - // LD C, NN - BC.B.B0=gbReadOpcode(PC.W++); - break; - case 0x0f: - // RRCA - tempValue=AF.B.B1&0x01; - AF.B.B1=(AF.B.B1>>1)|(tempValue? 0x80:0); - AF.B.B0=(tempValue<<4); - break; - case 0x10: - // STOP - opcode = gbReadOpcode(PC.W++); - if(gbCgbMode) { - if(gbMemory[0xff4d] & 1) { - - gbSpeedSwitch(); - //clockTicks += 228*144-(gbSpeed ? 62 : 63); - - if(gbSpeed == 0) - gbMemory[0xff4d] = 0x00; - else - gbMemory[0xff4d] = 0x80; - } - } - break; - case 0x11: - // LD DE, NNNN - DE.B.B0=gbReadOpcode(PC.W++); - DE.B.B1=gbReadOpcode(PC.W++); - break; - case 0x12: - // LD (DE),A - gbWriteMemory(DE.W,AF.B.B1); - break; - case 0x13: - // INC DE - DE.W++; - break; - case 0x14: - // INC D - DE.B.B1++; - AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B1]| (DE.B.B1&0x0F? 0:H_FLAG); - break; - case 0x15: - // DEC D - DE.B.B1--; - AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B1]| - ((DE.B.B1&0x0F)==0x0F? H_FLAG:0); - break; - case 0x16: - // LD D,NN - DE.B.B1=gbReadOpcode(PC.W++); - break; - case 0x17: - // RLA - tempValue=AF.B.B1&0x80? C_FLAG:0; - AF.B.B1=(AF.B.B1<<1)|((AF.B.B0&C_FLAG)>>4); - AF.B.B0=tempValue; - break; - case 0x18: - // JR NN - PC.W+=(s8)gbReadOpcode(PC.W)+1; - break; - case 0x19: - // ADD HL,DE - tempRegister.W=(HL.W+DE.W)&0xFFFF; - AF.B.B0= (AF.B.B0 & Z_FLAG)| ((HL.W^DE.W^tempRegister.W)&0x1000? H_FLAG:0)| - (((long)HL.W+(long)DE.W)&0x10000? C_FLAG:0); - HL.W=tempRegister.W; - break; - case 0x1a: - // LD A,(DE) - AF.B.B1=gbReadMemory(DE.W); - break; - case 0x1b: - // DEC DE - DE.W--; - break; - case 0x1c: - // INC E - DE.B.B0++; - AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B0]| (DE.B.B0&0x0F? 0:H_FLAG); - break; - case 0x1d: - // DEC E - DE.B.B0--; - AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B0]| - ((DE.B.B0&0x0F)==0x0F? H_FLAG:0); - break; - case 0x1e: - // LD E,NN - DE.B.B0=gbReadOpcode(PC.W++); - break; - case 0x1f: - // RRA - tempValue=AF.B.B1&0x01; - AF.B.B1=(AF.B.B1>>1)|(AF.B.B0&C_FLAG? 0x80:0); - AF.B.B0=(tempValue<<4); - break; - case 0x20: - // JR NZ,NN - if(AF.B.B0&Z_FLAG) - PC.W++; - else { - PC.W+=(s8)gbReadOpcode(PC.W)+1; - clockTicks++; - } - break; - case 0x21: - // LD HL,NNNN - HL.B.B0=gbReadOpcode(PC.W++); - HL.B.B1=gbReadOpcode(PC.W++); - break; - case 0x22: - // LDI (HL),A - gbWriteMemory(HL.W++,AF.B.B1); - break; - case 0x23: - // INC HL - HL.W++; - break; - case 0x24: - // INC H - HL.B.B1++; - AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B1]| (HL.B.B1&0x0F? 0:H_FLAG); - break; - case 0x25: - // DEC H - HL.B.B1--; - AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B1]| - ((HL.B.B1&0x0F)==0x0F? H_FLAG:0); - break; - case 0x26: - // LD H,NN - HL.B.B1=gbReadOpcode(PC.W++); - break; - case 0x27: - // DAA - tempRegister.W=AF.B.B1; - if(AF.B.B0&C_FLAG) tempRegister.W|=256; - if(AF.B.B0&H_FLAG) tempRegister.W|=512; - if(AF.B.B0&N_FLAG) tempRegister.W|=1024; - AF.W=DAATable[tempRegister.W]; - break; - case 0x28: - // JR Z,NN - if(AF.B.B0&Z_FLAG) { - PC.W+=(s8)gbReadOpcode(PC.W)+1; - clockTicks++; - } else - PC.W++; - break; - case 0x29: - // ADD HL,HL - tempRegister.W=(HL.W+HL.W)&0xFFFF; AF.B.B0= (AF.B.B0 & Z_FLAG)| - ((HL.W^HL.W^tempRegister.W)&0x1000? H_FLAG:0)| - (((long)HL.W+(long)HL.W)&0x10000? C_FLAG:0); - HL.W=tempRegister.W; - break; - case 0x2a: - // LDI A,(HL) - AF.B.B1 = gbReadMemory(HL.W++); - break; - case 0x2b: - // DEC HL - HL.W--; - break; - case 0x2c: - // INC L - HL.B.B0++; - AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B0]| (HL.B.B0&0x0F? 0:H_FLAG); - break; - case 0x2d: - // DEC L - HL.B.B0--; - AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B0]| - ((HL.B.B0&0x0F)==0x0F? H_FLAG:0); - break; - case 0x2e: - // LD L,NN - HL.B.B0=gbReadOpcode(PC.W++); - break; - case 0x2f: - // CPL - AF.B.B1 ^= 255; - AF.B.B0|=N_FLAG|H_FLAG; - break; - case 0x30: - // JR NC,NN - if(AF.B.B0&C_FLAG) - PC.W++; - else { - PC.W+=(s8)gbReadOpcode(PC.W)+1; - clockTicks++; - } - break; - case 0x31: - // LD SP,NNNN - SP.B.B0=gbReadOpcode(PC.W++); - SP.B.B1=gbReadOpcode(PC.W++); - break; - case 0x32: - // LDD (HL),A - gbWriteMemory(HL.W--,AF.B.B1); - break; - case 0x33: - // INC SP - SP.W++; - break; - case 0x34: - // INC (HL) - tempValue=gbReadMemory(HL.W)+1; - AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[tempValue]| (tempValue&0x0F? 0:H_FLAG); - gbWriteMemory(HL.W,tempValue); - break; - case 0x35: - // DEC (HL) - tempValue=gbReadMemory(HL.W)-1; - AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[tempValue]| - ((tempValue&0x0F)==0x0F? H_FLAG:0);gbWriteMemory(HL.W,tempValue); - break; - case 0x36: - // LD (HL),NN - gbWriteMemory(HL.W,gbReadOpcode(PC.W++)); - break; - case 0x37: - // SCF - AF.B.B0 = AF.B.B0 & Z_FLAG | C_FLAG; - break; -case 0x38: - // JR C,NN - if(AF.B.B0&C_FLAG) { - PC.W+=(s8)gbReadOpcode(PC.W)+1; - clockTicks ++; - } else - PC.W++; - break; - case 0x39: - // ADD HL,SP - tempRegister.W=(HL.W+SP.W)&0xFFFF; - AF.B.B0= (AF.B.B0 & Z_FLAG)| ((HL.W^SP.W^tempRegister.W)&0x1000? H_FLAG:0)| - (((long)HL.W+(long)SP.W)&0x10000? C_FLAG:0); - HL.W=tempRegister.W; - break; - case 0x3a: - // LDD A,(HL) - AF.B.B1 = gbReadMemory(HL.W--); - break; - case 0x3b: - // DEC SP - SP.W--; - break; - case 0x3c: - // INC A - AF.B.B1++; - AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[AF.B.B1]| (AF.B.B1&0x0F? 0:H_FLAG); - break; - case 0x3d: - // DEC A - AF.B.B1--; - AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[AF.B.B1]| - ((AF.B.B1&0x0F)==0x0F? H_FLAG:0); - break; - case 0x3e: - // LD A,NN - AF.B.B1=gbReadOpcode(PC.W++); - break; - case 0x3f: - // CCF - AF.B.B0^=C_FLAG;AF.B.B0&=~(N_FLAG|H_FLAG); - break; - case 0x40: - // LD B,B - BC.B.B1=BC.B.B1; - break; - case 0x41: - // LD B,C - BC.B.B1=BC.B.B0; - break; - case 0x42: - // LD B,D - BC.B.B1=DE.B.B1; - break; - case 0x43: - // LD B,E - BC.B.B1=DE.B.B0; - break; - case 0x44: - // LD B,H - BC.B.B1=HL.B.B1; - break; - case 0x45: - // LD B,L - BC.B.B1=HL.B.B0; - break; - case 0x46: - // LD B,(HL) - BC.B.B1=gbReadMemory(HL.W); - break; - case 0x47: - // LD B,A - BC.B.B1=AF.B.B1; - break; - case 0x48: - // LD C,B - BC.B.B0=BC.B.B1; - break; - case 0x49: - // LD C,C - BC.B.B0=BC.B.B0; - break; - case 0x4a: - // LD C,D - BC.B.B0=DE.B.B1; - break; - case 0x4b: - // LD C,E - BC.B.B0=DE.B.B0; - break; - case 0x4c: - // LD C,H - BC.B.B0=HL.B.B1; - break; - case 0x4d: - // LD C,L - BC.B.B0=HL.B.B0; - break; - case 0x4e: - // LD C,(HL) - BC.B.B0=gbReadMemory(HL.W); - break; - case 0x4f: - // LD C,A - BC.B.B0=AF.B.B1; - break; - case 0x50: - // LD D,B - DE.B.B1=BC.B.B1; - break; - case 0x51: - // LD D,C - DE.B.B1=BC.B.B0; - break; - case 0x52: - // LD D,D - DE.B.B1=DE.B.B1; - break; - case 0x53: - // LD D,E - DE.B.B1=DE.B.B0; - break; - case 0x54: - // LD D,H - DE.B.B1=HL.B.B1; - break; - case 0x55: - // LD D,L - DE.B.B1=HL.B.B0; - break; - case 0x56: - // LD D,(HL) - DE.B.B1=gbReadMemory(HL.W); - break; - case 0x57: - // LD D,A - DE.B.B1=AF.B.B1; - break; - case 0x58: - // LD E,B - DE.B.B0=BC.B.B1; - break; - case 0x59: - // LD E,C - DE.B.B0=BC.B.B0; - break; - case 0x5a: - // LD E,D - DE.B.B0=DE.B.B1; - break; - case 0x5b: - // LD E,E - DE.B.B0=DE.B.B0; - break; - case 0x5c: - // LD E,H - DE.B.B0=HL.B.B1; - break; - case 0x5d: - // LD E,L - DE.B.B0=HL.B.B0; - break; - case 0x5e: - // LD E,(HL) - DE.B.B0=gbReadMemory(HL.W); - break; - case 0x5f: - // LD E,A - DE.B.B0=AF.B.B1; - break; - case 0x60: - // LD H,B - HL.B.B1=BC.B.B1; - break; - case 0x61: - // LD H,C - HL.B.B1=BC.B.B0; - break; - case 0x62: - // LD H,D - HL.B.B1=DE.B.B1; - break; - case 0x63: - // LD H,E - HL.B.B1=DE.B.B0; - break; - case 0x64: - // LD H,H - HL.B.B1=HL.B.B1; - break; - case 0x65: - // LD H,L - HL.B.B1=HL.B.B0; - break; - case 0x66: - // LD H,(HL) - HL.B.B1=gbReadMemory(HL.W); - break; - case 0x67: - // LD H,A - HL.B.B1=AF.B.B1; - break; - case 0x68: - // LD L,B - HL.B.B0=BC.B.B1; - break; - case 0x69: - // LD L,C - HL.B.B0=BC.B.B0; - break; - case 0x6a: - // LD L,D - HL.B.B0=DE.B.B1; - break; - case 0x6b: - // LD L,E - HL.B.B0=DE.B.B0; - break; - case 0x6c: - // LD L,H - HL.B.B0=HL.B.B1; - break; - case 0x6d: - // LD L,L - HL.B.B0=HL.B.B0; - break; - case 0x6e: - // LD L,(HL) - HL.B.B0=gbReadMemory(HL.W); - break; - case 0x6f: - // LD L,A - HL.B.B0=AF.B.B1; - break; - case 0x70: - // LD (HL),B - gbWriteMemory(HL.W,BC.B.B1); - break; - case 0x71: - // LD (HL),C - gbWriteMemory(HL.W,BC.B.B0); - break; - case 0x72: - // LD (HL),D - gbWriteMemory(HL.W,DE.B.B1); - break; - case 0x73: - // LD (HL),E - gbWriteMemory(HL.W,DE.B.B0); - break; - case 0x74: - // LD (HL),H - gbWriteMemory(HL.W,HL.B.B1); - break; - case 0x75: - // LD (HL),L - gbWriteMemory(HL.W,HL.B.B0); - break; - case 0x76: - // HALT - // If an EI is pending, the interrupts are triggered before Halt state !! - // Fix Torpedo Range's intro. - if (IFF & 0x40) - { - IFF &= ~0x70; - IFF |=1; - PC.W--; - } - else - { - // if (IE & IF) and interrupts are disabeld, - // Halt is cancelled. - if ((register_IE & register_IF & 0x1f) && !(IFF & 1)) - { - IFF|=2; - } - else - IFF |= 0x80; - } - break; - case 0x77: - // LD (HL),A - gbWriteMemory(HL.W,AF.B.B1); - break; - case 0x78: - // LD A,B - AF.B.B1=BC.B.B1; - break; - case 0x79: - // LD A,C - AF.B.B1=BC.B.B0; - break; - case 0x7a: - // LD A,D - AF.B.B1=DE.B.B1; - break; - case 0x7b: - // LD A,E - AF.B.B1=DE.B.B0; - break; - case 0x7c: - // LD A,H - AF.B.B1=HL.B.B1; - break; - case 0x7d: - // LD A,L - AF.B.B1=HL.B.B0; - break; - case 0x7e: - // LD A,(HL) - AF.B.B1=gbReadMemory(HL.W); - break; - case 0x7f: - // LD A,A - AF.B.B1=AF.B.B1; - break; - case 0x80: - // ADD B - tempRegister.W=AF.B.B1+BC.B.B1; - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x81: - // ADD C - tempRegister.W=AF.B.B1+BC.B.B0; - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10 ? H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x82: - // ADD D - tempRegister.W=AF.B.B1+DE.B.B1; - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x83: - // ADD E - tempRegister.W=AF.B.B1+DE.B.B0; - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10 ? H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x84: - // ADD H - tempRegister.W=AF.B.B1+HL.B.B1; - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x85: - // ADD L - tempRegister.W=AF.B.B1+HL.B.B0; - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10 ? H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x86: - // ADD (HL) - tempValue=gbReadMemory(HL.W); - tempRegister.W=AF.B.B1+tempValue; - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10 ? H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x87: - // ADD A - tempRegister.W=AF.B.B1+AF.B.B1; - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^AF.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x88: - // ADC B: - tempRegister.W=AF.B.B1+BC.B.B1+(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x89: - // ADC C - tempRegister.W=AF.B.B1+BC.B.B0+(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x8a: - // ADC D - tempRegister.W=AF.B.B1+DE.B.B1+(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x8b: - // ADC E - tempRegister.W=AF.B.B1+DE.B.B0+(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x8c: - // ADC H - tempRegister.W=AF.B.B1+HL.B.B1+(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); AF.B.B1=tempRegister.B.B0; - break; - case 0x8d: - // ADC L - tempRegister.W=AF.B.B1+HL.B.B0+(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x8e: - // ADC (HL) - tempValue=gbReadMemory(HL.W); - tempRegister.W=AF.B.B1+tempValue+(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x8f: - // ADC A - tempRegister.W=AF.B.B1+AF.B.B1+(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^AF.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x90: - // SUB B - tempRegister.W=AF.B.B1-BC.B.B1; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x91: - // SUB C - tempRegister.W=AF.B.B1-BC.B.B0; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x92: - // SUB D - tempRegister.W=AF.B.B1-DE.B.B1; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x93: - // SUB E - tempRegister.W=AF.B.B1-DE.B.B0; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x94: - // SUB H - tempRegister.W=AF.B.B1-HL.B.B1; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x95: - // SUB L - tempRegister.W=AF.B.B1-HL.B.B0; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x96: - // SUB (HL) - tempValue=gbReadMemory(HL.W); - tempRegister.W=AF.B.B1-tempValue; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x97: - // SUB A - AF.B.B1=0; - AF.B.B0=N_FLAG|Z_FLAG; - break; - case 0x98: - // SBC B - tempRegister.W=AF.B.B1-BC.B.B1-(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x99: - // SBC C - tempRegister.W=AF.B.B1-BC.B.B0-(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x9a: - // SBC D - tempRegister.W=AF.B.B1-DE.B.B1-(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x9b: - // SBC E - tempRegister.W=AF.B.B1-DE.B.B0-(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x9c: - // SBC H - tempRegister.W=AF.B.B1-HL.B.B1-(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x9d: - // SBC L - tempRegister.W=AF.B.B1-HL.B.B0-(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x9e: - // SBC (HL) - tempValue=gbReadMemory(HL.W); - tempRegister.W=AF.B.B1-tempValue-(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0x9f: - // SBC A - tempRegister.W=AF.B.B1-AF.B.B1-(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^AF.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0xa0: - // AND B - AF.B.B1&=BC.B.B1; - AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; - break; - case 0xa1: - // AND C - AF.B.B1&=BC.B.B0; - AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; - break; - case 0xa2: - // AND_D - AF.B.B1&=DE.B.B1; - AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; - break; - case 0xa3: - // AND E - AF.B.B1&=DE.B.B0; - AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; - break; - case 0xa4: - // AND H - AF.B.B1&=HL.B.B1; - AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; - break; - case 0xa5: - // AND L - AF.B.B1&=HL.B.B0; - AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; - break; - case 0xa6: - // AND (HL) - tempValue=gbReadMemory(HL.W); - AF.B.B1&=tempValue; - AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; - break; - case 0xa7: - // AND A - AF.B.B1&=AF.B.B1; - AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; - break; - case 0xa8: - // XOR B - AF.B.B1^=BC.B.B1; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xa9: - // XOR C - AF.B.B1^=BC.B.B0; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xaa: - // XOR D - AF.B.B1^=DE.B.B1; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xab: - // XOR E - AF.B.B1^=DE.B.B0; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xac: - // XOR H - AF.B.B1^=HL.B.B1; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xad: - // XOR L - AF.B.B1^=HL.B.B0; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xae: - // XOR (HL) - tempValue=gbReadMemory(HL.W); - AF.B.B1^=tempValue; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xaf: - // XOR A - AF.B.B1=0; - AF.B.B0=Z_FLAG; - break; - case 0xb0: - // OR B - AF.B.B1|=BC.B.B1; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xb1: - // OR C - AF.B.B1|=BC.B.B0; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xb2: - // OR D - AF.B.B1|=DE.B.B1; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xb3: - // OR E - AF.B.B1|=DE.B.B0; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xb4: - // OR H - AF.B.B1|=HL.B.B1; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xb5: - // OR L - AF.B.B1|=HL.B.B0; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xb6: - // OR (HL) - tempValue=gbReadMemory(HL.W); - AF.B.B1|=tempValue; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xb7: - // OR A - AF.B.B1|=AF.B.B1; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xb8: - // CP B: - tempRegister.W=AF.B.B1-BC.B.B1; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - break; - case 0xb9: - // CP C - tempRegister.W=AF.B.B1-BC.B.B0; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); - break; - case 0xba: - // CP D - tempRegister.W=AF.B.B1-DE.B.B1; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - break; - case 0xbb: - // CP E - tempRegister.W=AF.B.B1-DE.B.B0; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); - break; - case 0xbc: - // CP H - tempRegister.W=AF.B.B1-HL.B.B1; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); - break; - case 0xbd: - // CP L - tempRegister.W=AF.B.B1-HL.B.B0; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); - break; - case 0xbe: - // CP (HL) - tempValue=gbReadMemory(HL.W); - tempRegister.W=AF.B.B1-tempValue; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); - break; - case 0xbf: - // CP A - AF.B.B0=N_FLAG|Z_FLAG; - break; - case 0xc0: - // RET NZ - if(!(AF.B.B0&Z_FLAG)) { - PC.B.B0=gbReadMemory(SP.W++); - PC.B.B1=gbReadMemory(SP.W++); - clockTicks += 3; - } - break; - case 0xc1: - // POP BC - BC.B.B0=gbReadMemory(SP.W++); - BC.B.B1=gbReadMemory(SP.W++); - break; - case 0xc2: - // JP NZ,NNNN - if(AF.B.B0&Z_FLAG) - PC.W+=2; - else { - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W); - PC.W=tempRegister.W; - clockTicks++; - } - break; - case 0xc3: - // JP NNNN - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W); - PC.W=tempRegister.W; - break; - case 0xc4: - // CALL NZ,NNNN - if(AF.B.B0&Z_FLAG) - PC.W+=2; - else { - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W++); - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=tempRegister.W; - clockTicks += 3; - } - break; - case 0xc5: - // PUSH BC - gbWriteMemory(--SP.W,BC.B.B1); - gbWriteMemory(--SP.W,BC.B.B0); - break; - case 0xc6: - // ADD NN - tempValue=gbReadOpcode(PC.W++); - tempRegister.W=AF.B.B1+tempValue; - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10 ? H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0xc7: - // RST 00 - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=0x0000; - break; - case 0xc8: - // RET Z - if(AF.B.B0&Z_FLAG) { - PC.B.B0=gbReadMemory(SP.W++); - PC.B.B1=gbReadMemory(SP.W++); - clockTicks += 3; - } - break; - case 0xc9: - // RET - PC.B.B0=gbReadMemory(SP.W++); - PC.B.B1=gbReadMemory(SP.W++); - break; - case 0xca: - // JP Z,NNNN - if(AF.B.B0&Z_FLAG) { - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W); - PC.W=tempRegister.W; - clockTicks++; - } else - PC.W+=2; - break; - // CB done outside - case 0xcc: - // CALL Z,NNNN - if(AF.B.B0&Z_FLAG) { - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W++); - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=tempRegister.W; - clockTicks += 3; - } else - PC.W+=2; - break; - case 0xcd: - // CALL NNNN - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W++); - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=tempRegister.W; - break; - case 0xce: - // ADC NN - tempValue=gbReadOpcode(PC.W++); - tempRegister.W=AF.B.B1+tempValue+(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0xcf: - // RST 08 - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=0x0008; - break; - case 0xd0: - // RET NC - if(!(AF.B.B0&C_FLAG)) { - PC.B.B0=gbReadMemory(SP.W++); - PC.B.B1=gbReadMemory(SP.W++); - clockTicks += 3; - } - break; - case 0xd1: - // POP DE - DE.B.B0=gbReadMemory(SP.W++); - DE.B.B1=gbReadMemory(SP.W++); - break; - case 0xd2: - // JP NC,NNNN - if(AF.B.B0&C_FLAG) - PC.W+=2; - else { - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W); - PC.W=tempRegister.W; - clockTicks++; - } - break; - // D3 illegal - case 0xd3: - PC.W--; - IFF = 0; - break; - case 0xd4: - // CALL NC,NNNN - if(AF.B.B0&C_FLAG) - PC.W+=2; - else { - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W++); - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=tempRegister.W; - clockTicks += 3; - } - break; - case 0xd5: - // PUSH DE - gbWriteMemory(--SP.W,DE.B.B1); - gbWriteMemory(--SP.W,DE.B.B0); - break; - case 0xd6: - // SUB NN - tempValue=gbReadOpcode(PC.W++); - tempRegister.W=AF.B.B1-tempValue; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0xd7: - // RST 10 - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=0x0010; - break; - case 0xd8: - // RET C - if(AF.B.B0&C_FLAG) { - PC.B.B0=gbReadMemory(SP.W++); - PC.B.B1=gbReadMemory(SP.W++); - clockTicks += 3; - } - break; - case 0xd9: - // RETI - PC.B.B0=gbReadMemory(SP.W++); - PC.B.B1=gbReadMemory(SP.W++); - IFF |= 0x01; - break; - case 0xda: - // JP C,NNNN - if(AF.B.B0&C_FLAG) { - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W); - PC.W=tempRegister.W; - clockTicks++; - } else - PC.W+=2; - break; - // DB illegal - case 0xdb: - PC.W--; - IFF = 0; - break; - case 0xdc: - // CALL C,NNNN - if(AF.B.B0&C_FLAG) { - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W++); - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=tempRegister.W; - clockTicks += 3; - } else - PC.W+=2; - break; - // DD illegal - case 0xdd: - PC.W--; - IFF = 0; - break; - case 0xde: - // SBC NN - tempValue=gbReadOpcode(PC.W++); - tempRegister.W=AF.B.B1-tempValue-(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); - AF.B.B1=tempRegister.B.B0; - break; - case 0xdf: - // RST 18 - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=0x0018; - break; - case 0xe0: - // LD (FF00+NN),A - gbWriteMemory(0xff00 + gbReadOpcode(PC.W++),AF.B.B1); - break; - case 0xe1: - // POP HL - HL.B.B0=gbReadMemory(SP.W++); - HL.B.B1=gbReadMemory(SP.W++); - break; - case 0xe2: - // LD (FF00+C),A - gbWriteMemory(0xff00 + BC.B.B0,AF.B.B1); - break; - // E3 illegal - // E4 illegal - case 0xe3: - case 0xe4: - PC.W--; - IFF = 0; - break; - case 0xe5: - // PUSH HL - gbWriteMemory(--SP.W,HL.B.B1); - gbWriteMemory(--SP.W,HL.B.B0); - break; - case 0xe6: - // AND NN - tempValue=gbReadOpcode(PC.W++); - AF.B.B1&=tempValue; - AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; - break; - case 0xe7: - // RST 20 - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=0x0020; - break; - case 0xe8: - // ADD SP,NN - offset = (s8)gbReadOpcode(PC.W++); - - if(offset >= 0) { - tempRegister.W = SP.W + offset; - AF.B.B0 = (SP.W > tempRegister.W ? C_FLAG : 0) | - ((SP.W^offset^tempRegister.W)&0x1000? H_FLAG:0); - SP.W = tempRegister.W; - } else { - tempRegister.W = SP.W + offset; - AF.B.B0 = (SP.W < tempRegister.W ? C_FLAG : 0) | - ((SP.W^offset^tempRegister.W)&0x1000?H_FLAG:0); - SP.W = tempRegister.W; - } - break; - case 0xe9: - // LD PC,HL - PC.W=HL.W; - break; - case 0xea: - // LD (NNNN),A - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W++); - gbWriteMemory(tempRegister.W,AF.B.B1); - break; - // EB illegal - // EC illegal - // ED illegal - case 0xeb: - case 0xec: - case 0xed: - PC.W--; - IFF = 0; - break; - case 0xee: - // XOR NN - tempValue=gbReadOpcode(PC.W++); - AF.B.B1^=tempValue; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xef: - // RST 28 - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=0x0028; - break; - case 0xf0: - // LD A,(FF00+NN) - AF.B.B1 = gbReadMemory(0xff00+gbReadOpcode(PC.W++)); - break; - case 0xf1: - // POP AF - AF.B.B0=gbReadMemory(SP.W++); - AF.B.B1=gbReadMemory(SP.W++); - break; - case 0xf2: - // LD A,(FF00+C) - AF.B.B1 = gbReadMemory(0xff00+BC.B.B0); - break; - case 0xf3: - // DI - // IFF&=0xFE; - IFF|=0x08; - break; - // F4 illegal - case 0xf4: - PC.W--; - IFF = 0; - break; - case 0xf5: - // PUSH AF - gbWriteMemory(--SP.W,AF.B.B1); - gbWriteMemory(--SP.W,AF.B.B0); - break; - case 0xf6: - // OR NN - tempValue=gbReadOpcode(PC.W++); - AF.B.B1|=tempValue; - AF.B.B0=ZeroTable[AF.B.B1]; - break; - case 0xf7: - // RST 30 - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=0x0030; - break; - case 0xf8: - // LD HL,SP+NN - offset = (s8)gbReadOpcode(PC.W++); - if(offset >= 0) { - tempRegister.W = SP.W + offset; - AF.B.B0 = (SP.W > tempRegister.W ? C_FLAG : 0) | - ((SP.W^offset^tempRegister.W)&0x1000? H_FLAG:0); - HL.W = tempRegister.W; - } else { - tempRegister.W = SP.W + offset; - AF.B.B0 = (SP.W < tempRegister.W ? C_FLAG : 0) | - ((SP.W^offset^tempRegister.W)&0x1000?H_FLAG:0); - HL.W = tempRegister.W; - } - break; - case 0xf9: - // LD SP,HL - SP.W=HL.W; - break; - case 0xfa: - // LD A,(NNNN) - tempRegister.B.B0=gbReadOpcode(PC.W++); - tempRegister.B.B1=gbReadOpcode(PC.W++); - AF.B.B1=gbReadMemory(tempRegister.W); - break; - case 0xfb: - // EI - if (!(IFF & 0x30)) - // If an EI is executed right before HALT, - // the interrupts are triggered before the Halt state !! - // Fix Torpedo Range Intro. - // IFF |= 0x10 : 1 ticks before the EI enables the interrupts - // IFF |= 0x40 : marks that an EI is being executed. - IFF|=0x50; - break; - // FC illegal (FC = breakpoint) - case 0xfc: - breakpoint = true; - break; - // FD illegal - case 0xfd: - PC.W--; - IFF = 0; - break; - case 0xfe: - // CP NN - tempValue=gbReadOpcode(PC.W++); - tempRegister.W=AF.B.B1-tempValue; - AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| - ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); - break; - case 0xff: - // RST 38 - gbWriteMemory(--SP.W,PC.B.B1); - gbWriteMemory(--SP.W,PC.B.B0); - PC.W=0x0038; - break; - default: - if (gbSystemMessage == false) - { - systemMessage(0, N_("Unknown opcode %02x at %04x"), - gbReadOpcode(PC.W-1),PC.W-1); - gbSystemMessage =true; - } - return; +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + case 0x00: + // NOP + break; + case 0x01: + // LD BC, NNNN + BC.B.B0=gbReadOpcode(PC.W++); + BC.B.B1=gbReadOpcode(PC.W++); + break; + case 0x02: + // LD (BC),A + gbWriteMemory(BC.W,AF.B.B1); + break; + case 0x03: + // INC BC + BC.W++; + break; + case 0x04: + // INC B + BC.B.B1++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B1]| (BC.B.B1&0x0F? 0:H_FLAG); + break; + case 0x05: + // DEC B + BC.B.B1--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B1]| + ((BC.B.B1&0x0F)==0x0F? H_FLAG:0); + break; + case 0x06: + // LD B, NN + BC.B.B1=gbReadOpcode(PC.W++); + break; + case 0x07: + // RLCA + tempValue=AF.B.B1&0x80? C_FLAG:0; + AF.B.B1=(AF.B.B1<<1)|(AF.B.B1>>7); + AF.B.B0=tempValue; + break; + case 0x08: + // LD (NNNN), SP + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W++); + gbWriteMemory(tempRegister.W++,SP.B.B0); + gbWriteMemory(tempRegister.W,SP.B.B1); + break; + case 0x09: + // ADD HL,BC + tempRegister.W=(HL.W+BC.W)&0xFFFF; + AF.B.B0= (AF.B.B0 & Z_FLAG)| ((HL.W^BC.W^tempRegister.W)&0x1000? H_FLAG:0)| + (((long)HL.W+(long)BC.W)&0x10000? C_FLAG:0); + HL.W=tempRegister.W; + break; + case 0x0a: + // LD A,(BC) + AF.B.B1=gbReadMemory(BC.W); + break; + case 0x0b: + // DEC BC + BC.W--; + break; + case 0x0c: + // INC C + BC.B.B0++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B0]| (BC.B.B0&0x0F? 0:H_FLAG); + break; + case 0x0d: + // DEC C + BC.B.B0--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B0]| + ((BC.B.B0&0x0F)==0x0F? H_FLAG:0); + break; + case 0x0e: + // LD C, NN + BC.B.B0=gbReadOpcode(PC.W++); + break; + case 0x0f: + // RRCA + tempValue=AF.B.B1&0x01; + AF.B.B1=(AF.B.B1>>1)|(tempValue? 0x80:0); + AF.B.B0=(tempValue<<4); + break; + case 0x10: + // STOP + opcode = gbReadOpcode(PC.W++); + if(gbCgbMode) { + if(gbMemory[0xff4d] & 1) { + + gbSpeedSwitch(); + //clockTicks += 228*144-(gbSpeed ? 62 : 63); + + if(gbSpeed == 0) + gbMemory[0xff4d] = 0x00; + else + gbMemory[0xff4d] = 0x80; + } + } + break; + case 0x11: + // LD DE, NNNN + DE.B.B0=gbReadOpcode(PC.W++); + DE.B.B1=gbReadOpcode(PC.W++); + break; + case 0x12: + // LD (DE),A + gbWriteMemory(DE.W,AF.B.B1); + break; + case 0x13: + // INC DE + DE.W++; + break; + case 0x14: + // INC D + DE.B.B1++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B1]| (DE.B.B1&0x0F? 0:H_FLAG); + break; + case 0x15: + // DEC D + DE.B.B1--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B1]| + ((DE.B.B1&0x0F)==0x0F? H_FLAG:0); + break; + case 0x16: + // LD D,NN + DE.B.B1=gbReadOpcode(PC.W++); + break; + case 0x17: + // RLA + tempValue=AF.B.B1&0x80? C_FLAG:0; + AF.B.B1=(AF.B.B1<<1)|((AF.B.B0&C_FLAG)>>4); + AF.B.B0=tempValue; + break; + case 0x18: + // JR NN + PC.W+=(s8)gbReadOpcode(PC.W)+1; + break; + case 0x19: + // ADD HL,DE + tempRegister.W=(HL.W+DE.W)&0xFFFF; + AF.B.B0= (AF.B.B0 & Z_FLAG)| ((HL.W^DE.W^tempRegister.W)&0x1000? H_FLAG:0)| + (((long)HL.W+(long)DE.W)&0x10000? C_FLAG:0); + HL.W=tempRegister.W; + break; + case 0x1a: + // LD A,(DE) + AF.B.B1=gbReadMemory(DE.W); + break; + case 0x1b: + // DEC DE + DE.W--; + break; + case 0x1c: + // INC E + DE.B.B0++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B0]| (DE.B.B0&0x0F? 0:H_FLAG); + break; + case 0x1d: + // DEC E + DE.B.B0--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B0]| + ((DE.B.B0&0x0F)==0x0F? H_FLAG:0); + break; + case 0x1e: + // LD E,NN + DE.B.B0=gbReadOpcode(PC.W++); + break; + case 0x1f: + // RRA + tempValue=AF.B.B1&0x01; + AF.B.B1=(AF.B.B1>>1)|(AF.B.B0&C_FLAG? 0x80:0); + AF.B.B0=(tempValue<<4); + break; + case 0x20: + // JR NZ,NN + if(AF.B.B0&Z_FLAG) + PC.W++; + else { + PC.W+=(s8)gbReadOpcode(PC.W)+1; + clockTicks++; + } + break; + case 0x21: + // LD HL,NNNN + HL.B.B0=gbReadOpcode(PC.W++); + HL.B.B1=gbReadOpcode(PC.W++); + break; + case 0x22: + // LDI (HL),A + gbWriteMemory(HL.W++,AF.B.B1); + break; + case 0x23: + // INC HL + HL.W++; + break; + case 0x24: + // INC H + HL.B.B1++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B1]| (HL.B.B1&0x0F? 0:H_FLAG); + break; + case 0x25: + // DEC H + HL.B.B1--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B1]| + ((HL.B.B1&0x0F)==0x0F? H_FLAG:0); + break; + case 0x26: + // LD H,NN + HL.B.B1=gbReadOpcode(PC.W++); + break; + case 0x27: + // DAA + tempRegister.W=AF.B.B1; + if(AF.B.B0&C_FLAG) tempRegister.W|=256; + if(AF.B.B0&H_FLAG) tempRegister.W|=512; + if(AF.B.B0&N_FLAG) tempRegister.W|=1024; + AF.W=DAATable[tempRegister.W]; + break; + case 0x28: + // JR Z,NN + if(AF.B.B0&Z_FLAG) { + PC.W+=(s8)gbReadOpcode(PC.W)+1; + clockTicks++; + } else + PC.W++; + break; + case 0x29: + // ADD HL,HL + tempRegister.W=(HL.W+HL.W)&0xFFFF; AF.B.B0= (AF.B.B0 & Z_FLAG)| + ((HL.W^HL.W^tempRegister.W)&0x1000? H_FLAG:0)| + (((long)HL.W+(long)HL.W)&0x10000? C_FLAG:0); + HL.W=tempRegister.W; + break; + case 0x2a: + // LDI A,(HL) + AF.B.B1 = gbReadMemory(HL.W++); + break; + case 0x2b: + // DEC HL + HL.W--; + break; + case 0x2c: + // INC L + HL.B.B0++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B0]| (HL.B.B0&0x0F? 0:H_FLAG); + break; + case 0x2d: + // DEC L + HL.B.B0--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B0]| + ((HL.B.B0&0x0F)==0x0F? H_FLAG:0); + break; + case 0x2e: + // LD L,NN + HL.B.B0=gbReadOpcode(PC.W++); + break; + case 0x2f: + // CPL + AF.B.B1 ^= 255; + AF.B.B0|=N_FLAG|H_FLAG; + break; + case 0x30: + // JR NC,NN + if(AF.B.B0&C_FLAG) + PC.W++; + else { + PC.W+=(s8)gbReadOpcode(PC.W)+1; + clockTicks++; + } + break; + case 0x31: + // LD SP,NNNN + SP.B.B0=gbReadOpcode(PC.W++); + SP.B.B1=gbReadOpcode(PC.W++); + break; + case 0x32: + // LDD (HL),A + gbWriteMemory(HL.W--,AF.B.B1); + break; + case 0x33: + // INC SP + SP.W++; + break; + case 0x34: + // INC (HL) + tempValue=gbReadMemory(HL.W)+1; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[tempValue]| (tempValue&0x0F? 0:H_FLAG); + gbWriteMemory(HL.W,tempValue); + break; + case 0x35: + // DEC (HL) + tempValue=gbReadMemory(HL.W)-1; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[tempValue]| + ((tempValue&0x0F)==0x0F? H_FLAG:0);gbWriteMemory(HL.W,tempValue); + break; + case 0x36: + // LD (HL),NN + gbWriteMemory(HL.W,gbReadOpcode(PC.W++)); + break; + case 0x37: + // SCF + AF.B.B0 = AF.B.B0 & Z_FLAG | C_FLAG; + break; +case 0x38: + // JR C,NN + if(AF.B.B0&C_FLAG) { + PC.W+=(s8)gbReadOpcode(PC.W)+1; + clockTicks ++; + } else + PC.W++; + break; + case 0x39: + // ADD HL,SP + tempRegister.W=(HL.W+SP.W)&0xFFFF; + AF.B.B0= (AF.B.B0 & Z_FLAG)| ((HL.W^SP.W^tempRegister.W)&0x1000? H_FLAG:0)| + (((long)HL.W+(long)SP.W)&0x10000? C_FLAG:0); + HL.W=tempRegister.W; + break; + case 0x3a: + // LDD A,(HL) + AF.B.B1 = gbReadMemory(HL.W--); + break; + case 0x3b: + // DEC SP + SP.W--; + break; + case 0x3c: + // INC A + AF.B.B1++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[AF.B.B1]| (AF.B.B1&0x0F? 0:H_FLAG); + break; + case 0x3d: + // DEC A + AF.B.B1--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[AF.B.B1]| + ((AF.B.B1&0x0F)==0x0F? H_FLAG:0); + break; + case 0x3e: + // LD A,NN + AF.B.B1=gbReadOpcode(PC.W++); + break; + case 0x3f: + // CCF + AF.B.B0^=C_FLAG;AF.B.B0&=~(N_FLAG|H_FLAG); + break; + case 0x40: + // LD B,B + BC.B.B1=BC.B.B1; + break; + case 0x41: + // LD B,C + BC.B.B1=BC.B.B0; + break; + case 0x42: + // LD B,D + BC.B.B1=DE.B.B1; + break; + case 0x43: + // LD B,E + BC.B.B1=DE.B.B0; + break; + case 0x44: + // LD B,H + BC.B.B1=HL.B.B1; + break; + case 0x45: + // LD B,L + BC.B.B1=HL.B.B0; + break; + case 0x46: + // LD B,(HL) + BC.B.B1=gbReadMemory(HL.W); + break; + case 0x47: + // LD B,A + BC.B.B1=AF.B.B1; + break; + case 0x48: + // LD C,B + BC.B.B0=BC.B.B1; + break; + case 0x49: + // LD C,C + BC.B.B0=BC.B.B0; + break; + case 0x4a: + // LD C,D + BC.B.B0=DE.B.B1; + break; + case 0x4b: + // LD C,E + BC.B.B0=DE.B.B0; + break; + case 0x4c: + // LD C,H + BC.B.B0=HL.B.B1; + break; + case 0x4d: + // LD C,L + BC.B.B0=HL.B.B0; + break; + case 0x4e: + // LD C,(HL) + BC.B.B0=gbReadMemory(HL.W); + break; + case 0x4f: + // LD C,A + BC.B.B0=AF.B.B1; + break; + case 0x50: + // LD D,B + DE.B.B1=BC.B.B1; + break; + case 0x51: + // LD D,C + DE.B.B1=BC.B.B0; + break; + case 0x52: + // LD D,D + DE.B.B1=DE.B.B1; + break; + case 0x53: + // LD D,E + DE.B.B1=DE.B.B0; + break; + case 0x54: + // LD D,H + DE.B.B1=HL.B.B1; + break; + case 0x55: + // LD D,L + DE.B.B1=HL.B.B0; + break; + case 0x56: + // LD D,(HL) + DE.B.B1=gbReadMemory(HL.W); + break; + case 0x57: + // LD D,A + DE.B.B1=AF.B.B1; + break; + case 0x58: + // LD E,B + DE.B.B0=BC.B.B1; + break; + case 0x59: + // LD E,C + DE.B.B0=BC.B.B0; + break; + case 0x5a: + // LD E,D + DE.B.B0=DE.B.B1; + break; + case 0x5b: + // LD E,E + DE.B.B0=DE.B.B0; + break; + case 0x5c: + // LD E,H + DE.B.B0=HL.B.B1; + break; + case 0x5d: + // LD E,L + DE.B.B0=HL.B.B0; + break; + case 0x5e: + // LD E,(HL) + DE.B.B0=gbReadMemory(HL.W); + break; + case 0x5f: + // LD E,A + DE.B.B0=AF.B.B1; + break; + case 0x60: + // LD H,B + HL.B.B1=BC.B.B1; + break; + case 0x61: + // LD H,C + HL.B.B1=BC.B.B0; + break; + case 0x62: + // LD H,D + HL.B.B1=DE.B.B1; + break; + case 0x63: + // LD H,E + HL.B.B1=DE.B.B0; + break; + case 0x64: + // LD H,H + HL.B.B1=HL.B.B1; + break; + case 0x65: + // LD H,L + HL.B.B1=HL.B.B0; + break; + case 0x66: + // LD H,(HL) + HL.B.B1=gbReadMemory(HL.W); + break; + case 0x67: + // LD H,A + HL.B.B1=AF.B.B1; + break; + case 0x68: + // LD L,B + HL.B.B0=BC.B.B1; + break; + case 0x69: + // LD L,C + HL.B.B0=BC.B.B0; + break; + case 0x6a: + // LD L,D + HL.B.B0=DE.B.B1; + break; + case 0x6b: + // LD L,E + HL.B.B0=DE.B.B0; + break; + case 0x6c: + // LD L,H + HL.B.B0=HL.B.B1; + break; + case 0x6d: + // LD L,L + HL.B.B0=HL.B.B0; + break; + case 0x6e: + // LD L,(HL) + HL.B.B0=gbReadMemory(HL.W); + break; + case 0x6f: + // LD L,A + HL.B.B0=AF.B.B1; + break; + case 0x70: + // LD (HL),B + gbWriteMemory(HL.W,BC.B.B1); + break; + case 0x71: + // LD (HL),C + gbWriteMemory(HL.W,BC.B.B0); + break; + case 0x72: + // LD (HL),D + gbWriteMemory(HL.W,DE.B.B1); + break; + case 0x73: + // LD (HL),E + gbWriteMemory(HL.W,DE.B.B0); + break; + case 0x74: + // LD (HL),H + gbWriteMemory(HL.W,HL.B.B1); + break; + case 0x75: + // LD (HL),L + gbWriteMemory(HL.W,HL.B.B0); + break; + case 0x76: + // HALT + // If an EI is pending, the interrupts are triggered before Halt state !! + // Fix Torpedo Range's intro. + if (IFF & 0x40) + { + IFF &= ~0x70; + IFF |=1; + PC.W--; + } + else + { + // if (IE & IF) and interrupts are disabeld, + // Halt is cancelled. + if ((register_IE & register_IF & 0x1f) && !(IFF & 1)) + { + IFF|=2; + } + else + IFF |= 0x80; + } + break; + case 0x77: + // LD (HL),A + gbWriteMemory(HL.W,AF.B.B1); + break; + case 0x78: + // LD A,B + AF.B.B1=BC.B.B1; + break; + case 0x79: + // LD A,C + AF.B.B1=BC.B.B0; + break; + case 0x7a: + // LD A,D + AF.B.B1=DE.B.B1; + break; + case 0x7b: + // LD A,E + AF.B.B1=DE.B.B0; + break; + case 0x7c: + // LD A,H + AF.B.B1=HL.B.B1; + break; + case 0x7d: + // LD A,L + AF.B.B1=HL.B.B0; + break; + case 0x7e: + // LD A,(HL) + AF.B.B1=gbReadMemory(HL.W); + break; + case 0x7f: + // LD A,A + AF.B.B1=AF.B.B1; + break; + case 0x80: + // ADD B + tempRegister.W=AF.B.B1+BC.B.B1; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x81: + // ADD C + tempRegister.W=AF.B.B1+BC.B.B0; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x82: + // ADD D + tempRegister.W=AF.B.B1+DE.B.B1; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x83: + // ADD E + tempRegister.W=AF.B.B1+DE.B.B0; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x84: + // ADD H + tempRegister.W=AF.B.B1+HL.B.B1; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x85: + // ADD L + tempRegister.W=AF.B.B1+HL.B.B0; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x86: + // ADD (HL) + tempValue=gbReadMemory(HL.W); + tempRegister.W=AF.B.B1+tempValue; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x87: + // ADD A + tempRegister.W=AF.B.B1+AF.B.B1; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^AF.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x88: + // ADC B: + tempRegister.W=AF.B.B1+BC.B.B1+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x89: + // ADC C + tempRegister.W=AF.B.B1+BC.B.B0+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x8a: + // ADC D + tempRegister.W=AF.B.B1+DE.B.B1+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x8b: + // ADC E + tempRegister.W=AF.B.B1+DE.B.B0+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x8c: + // ADC H + tempRegister.W=AF.B.B1+HL.B.B1+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); AF.B.B1=tempRegister.B.B0; + break; + case 0x8d: + // ADC L + tempRegister.W=AF.B.B1+HL.B.B0+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x8e: + // ADC (HL) + tempValue=gbReadMemory(HL.W); + tempRegister.W=AF.B.B1+tempValue+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x8f: + // ADC A + tempRegister.W=AF.B.B1+AF.B.B1+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^AF.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x90: + // SUB B + tempRegister.W=AF.B.B1-BC.B.B1; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x91: + // SUB C + tempRegister.W=AF.B.B1-BC.B.B0; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x92: + // SUB D + tempRegister.W=AF.B.B1-DE.B.B1; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x93: + // SUB E + tempRegister.W=AF.B.B1-DE.B.B0; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x94: + // SUB H + tempRegister.W=AF.B.B1-HL.B.B1; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x95: + // SUB L + tempRegister.W=AF.B.B1-HL.B.B0; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x96: + // SUB (HL) + tempValue=gbReadMemory(HL.W); + tempRegister.W=AF.B.B1-tempValue; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x97: + // SUB A + AF.B.B1=0; + AF.B.B0=N_FLAG|Z_FLAG; + break; + case 0x98: + // SBC B + tempRegister.W=AF.B.B1-BC.B.B1-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x99: + // SBC C + tempRegister.W=AF.B.B1-BC.B.B0-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x9a: + // SBC D + tempRegister.W=AF.B.B1-DE.B.B1-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x9b: + // SBC E + tempRegister.W=AF.B.B1-DE.B.B0-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x9c: + // SBC H + tempRegister.W=AF.B.B1-HL.B.B1-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x9d: + // SBC L + tempRegister.W=AF.B.B1-HL.B.B0-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x9e: + // SBC (HL) + tempValue=gbReadMemory(HL.W); + tempRegister.W=AF.B.B1-tempValue-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x9f: + // SBC A + tempRegister.W=AF.B.B1-AF.B.B1-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^AF.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0xa0: + // AND B + AF.B.B1&=BC.B.B1; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa1: + // AND C + AF.B.B1&=BC.B.B0; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa2: + // AND_D + AF.B.B1&=DE.B.B1; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa3: + // AND E + AF.B.B1&=DE.B.B0; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa4: + // AND H + AF.B.B1&=HL.B.B1; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa5: + // AND L + AF.B.B1&=HL.B.B0; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa6: + // AND (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B1&=tempValue; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa7: + // AND A + AF.B.B1&=AF.B.B1; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa8: + // XOR B + AF.B.B1^=BC.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xa9: + // XOR C + AF.B.B1^=BC.B.B0; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xaa: + // XOR D + AF.B.B1^=DE.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xab: + // XOR E + AF.B.B1^=DE.B.B0; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xac: + // XOR H + AF.B.B1^=HL.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xad: + // XOR L + AF.B.B1^=HL.B.B0; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xae: + // XOR (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B1^=tempValue; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xaf: + // XOR A + AF.B.B1=0; + AF.B.B0=Z_FLAG; + break; + case 0xb0: + // OR B + AF.B.B1|=BC.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb1: + // OR C + AF.B.B1|=BC.B.B0; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb2: + // OR D + AF.B.B1|=DE.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb3: + // OR E + AF.B.B1|=DE.B.B0; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb4: + // OR H + AF.B.B1|=HL.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb5: + // OR L + AF.B.B1|=HL.B.B0; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb6: + // OR (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B1|=tempValue; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb7: + // OR A + AF.B.B1|=AF.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb8: + // CP B: + tempRegister.W=AF.B.B1-BC.B.B1; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xb9: + // CP C + tempRegister.W=AF.B.B1-BC.B.B0; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xba: + // CP D + tempRegister.W=AF.B.B1-DE.B.B1; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xbb: + // CP E + tempRegister.W=AF.B.B1-DE.B.B0; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xbc: + // CP H + tempRegister.W=AF.B.B1-HL.B.B1; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xbd: + // CP L + tempRegister.W=AF.B.B1-HL.B.B0; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xbe: + // CP (HL) + tempValue=gbReadMemory(HL.W); + tempRegister.W=AF.B.B1-tempValue; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xbf: + // CP A + AF.B.B0=N_FLAG|Z_FLAG; + break; + case 0xc0: + // RET NZ + if(!(AF.B.B0&Z_FLAG)) { + PC.B.B0=gbReadMemory(SP.W++); + PC.B.B1=gbReadMemory(SP.W++); + clockTicks += 3; + } + break; + case 0xc1: + // POP BC + BC.B.B0=gbReadMemory(SP.W++); + BC.B.B1=gbReadMemory(SP.W++); + break; + case 0xc2: + // JP NZ,NNNN + if(AF.B.B0&Z_FLAG) + PC.W+=2; + else { + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W); + PC.W=tempRegister.W; + clockTicks++; + } + break; + case 0xc3: + // JP NNNN + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W); + PC.W=tempRegister.W; + break; + case 0xc4: + // CALL NZ,NNNN + if(AF.B.B0&Z_FLAG) + PC.W+=2; + else { + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W++); + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=tempRegister.W; + clockTicks += 3; + } + break; + case 0xc5: + // PUSH BC + gbWriteMemory(--SP.W,BC.B.B1); + gbWriteMemory(--SP.W,BC.B.B0); + break; + case 0xc6: + // ADD NN + tempValue=gbReadOpcode(PC.W++); + tempRegister.W=AF.B.B1+tempValue; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0xc7: + // RST 00 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0000; + break; + case 0xc8: + // RET Z + if(AF.B.B0&Z_FLAG) { + PC.B.B0=gbReadMemory(SP.W++); + PC.B.B1=gbReadMemory(SP.W++); + clockTicks += 3; + } + break; + case 0xc9: + // RET + PC.B.B0=gbReadMemory(SP.W++); + PC.B.B1=gbReadMemory(SP.W++); + break; + case 0xca: + // JP Z,NNNN + if(AF.B.B0&Z_FLAG) { + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W); + PC.W=tempRegister.W; + clockTicks++; + } else + PC.W+=2; + break; + // CB done outside + case 0xcc: + // CALL Z,NNNN + if(AF.B.B0&Z_FLAG) { + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W++); + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=tempRegister.W; + clockTicks += 3; + } else + PC.W+=2; + break; + case 0xcd: + // CALL NNNN + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W++); + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=tempRegister.W; + break; + case 0xce: + // ADC NN + tempValue=gbReadOpcode(PC.W++); + tempRegister.W=AF.B.B1+tempValue+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0xcf: + // RST 08 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0008; + break; + case 0xd0: + // RET NC + if(!(AF.B.B0&C_FLAG)) { + PC.B.B0=gbReadMemory(SP.W++); + PC.B.B1=gbReadMemory(SP.W++); + clockTicks += 3; + } + break; + case 0xd1: + // POP DE + DE.B.B0=gbReadMemory(SP.W++); + DE.B.B1=gbReadMemory(SP.W++); + break; + case 0xd2: + // JP NC,NNNN + if(AF.B.B0&C_FLAG) + PC.W+=2; + else { + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W); + PC.W=tempRegister.W; + clockTicks++; + } + break; + // D3 illegal + case 0xd3: + PC.W--; + IFF = 0; + break; + case 0xd4: + // CALL NC,NNNN + if(AF.B.B0&C_FLAG) + PC.W+=2; + else { + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W++); + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=tempRegister.W; + clockTicks += 3; + } + break; + case 0xd5: + // PUSH DE + gbWriteMemory(--SP.W,DE.B.B1); + gbWriteMemory(--SP.W,DE.B.B0); + break; + case 0xd6: + // SUB NN + tempValue=gbReadOpcode(PC.W++); + tempRegister.W=AF.B.B1-tempValue; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0xd7: + // RST 10 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0010; + break; + case 0xd8: + // RET C + if(AF.B.B0&C_FLAG) { + PC.B.B0=gbReadMemory(SP.W++); + PC.B.B1=gbReadMemory(SP.W++); + clockTicks += 3; + } + break; + case 0xd9: + // RETI + PC.B.B0=gbReadMemory(SP.W++); + PC.B.B1=gbReadMemory(SP.W++); + IFF |= 0x01; + break; + case 0xda: + // JP C,NNNN + if(AF.B.B0&C_FLAG) { + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W); + PC.W=tempRegister.W; + clockTicks++; + } else + PC.W+=2; + break; + // DB illegal + case 0xdb: + PC.W--; + IFF = 0; + break; + case 0xdc: + // CALL C,NNNN + if(AF.B.B0&C_FLAG) { + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W++); + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=tempRegister.W; + clockTicks += 3; + } else + PC.W+=2; + break; + // DD illegal + case 0xdd: + PC.W--; + IFF = 0; + break; + case 0xde: + // SBC NN + tempValue=gbReadOpcode(PC.W++); + tempRegister.W=AF.B.B1-tempValue-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0xdf: + // RST 18 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0018; + break; + case 0xe0: + // LD (FF00+NN),A + gbWriteMemory(0xff00 + gbReadOpcode(PC.W++),AF.B.B1); + break; + case 0xe1: + // POP HL + HL.B.B0=gbReadMemory(SP.W++); + HL.B.B1=gbReadMemory(SP.W++); + break; + case 0xe2: + // LD (FF00+C),A + gbWriteMemory(0xff00 + BC.B.B0,AF.B.B1); + break; + // E3 illegal + // E4 illegal + case 0xe3: + case 0xe4: + PC.W--; + IFF = 0; + break; + case 0xe5: + // PUSH HL + gbWriteMemory(--SP.W,HL.B.B1); + gbWriteMemory(--SP.W,HL.B.B0); + break; + case 0xe6: + // AND NN + tempValue=gbReadOpcode(PC.W++); + AF.B.B1&=tempValue; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xe7: + // RST 20 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0020; + break; + case 0xe8: + // ADD SP,NN + offset = (s8)gbReadOpcode(PC.W++); + + if(offset >= 0) { + tempRegister.W = SP.W + offset; + AF.B.B0 = (SP.W > tempRegister.W ? C_FLAG : 0) | + ((SP.W^offset^tempRegister.W)&0x1000? H_FLAG:0); + SP.W = tempRegister.W; + } else { + tempRegister.W = SP.W + offset; + AF.B.B0 = (SP.W < tempRegister.W ? C_FLAG : 0) | + ((SP.W^offset^tempRegister.W)&0x1000?H_FLAG:0); + SP.W = tempRegister.W; + } + break; + case 0xe9: + // LD PC,HL + PC.W=HL.W; + break; + case 0xea: + // LD (NNNN),A + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W++); + gbWriteMemory(tempRegister.W,AF.B.B1); + break; + // EB illegal + // EC illegal + // ED illegal + case 0xeb: + case 0xec: + case 0xed: + PC.W--; + IFF = 0; + break; + case 0xee: + // XOR NN + tempValue=gbReadOpcode(PC.W++); + AF.B.B1^=tempValue; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xef: + // RST 28 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0028; + break; + case 0xf0: + // LD A,(FF00+NN) + AF.B.B1 = gbReadMemory(0xff00+gbReadOpcode(PC.W++)); + break; + case 0xf1: + // POP AF + AF.B.B0=gbReadMemory(SP.W++); + AF.B.B1=gbReadMemory(SP.W++); + break; + case 0xf2: + // LD A,(FF00+C) + AF.B.B1 = gbReadMemory(0xff00+BC.B.B0); + break; + case 0xf3: + // DI + // IFF&=0xFE; + IFF|=0x08; + break; + // F4 illegal + case 0xf4: + PC.W--; + IFF = 0; + break; + case 0xf5: + // PUSH AF + gbWriteMemory(--SP.W,AF.B.B1); + gbWriteMemory(--SP.W,AF.B.B0); + break; + case 0xf6: + // OR NN + tempValue=gbReadOpcode(PC.W++); + AF.B.B1|=tempValue; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xf7: + // RST 30 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0030; + break; + case 0xf8: + // LD HL,SP+NN + offset = (s8)gbReadOpcode(PC.W++); + if(offset >= 0) { + tempRegister.W = SP.W + offset; + AF.B.B0 = (SP.W > tempRegister.W ? C_FLAG : 0) | + ((SP.W^offset^tempRegister.W)&0x1000? H_FLAG:0); + HL.W = tempRegister.W; + } else { + tempRegister.W = SP.W + offset; + AF.B.B0 = (SP.W < tempRegister.W ? C_FLAG : 0) | + ((SP.W^offset^tempRegister.W)&0x1000?H_FLAG:0); + HL.W = tempRegister.W; + } + break; + case 0xf9: + // LD SP,HL + SP.W=HL.W; + break; + case 0xfa: + // LD A,(NNNN) + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W++); + AF.B.B1=gbReadMemory(tempRegister.W); + break; + case 0xfb: + // EI + if (!(IFF & 0x30)) + // If an EI is executed right before HALT, + // the interrupts are triggered before the Halt state !! + // Fix Torpedo Range Intro. + // IFF |= 0x10 : 1 ticks before the EI enables the interrupts + // IFF |= 0x40 : marks that an EI is being executed. + IFF|=0x50; + break; + // FC illegal (FC = breakpoint) + case 0xfc: + breakpoint = true; + break; + // FD illegal + case 0xfd: + PC.W--; + IFF = 0; + break; + case 0xfe: + // CP NN + tempValue=gbReadOpcode(PC.W++); + tempRegister.W=AF.B.B1-tempValue; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xff: + // RST 38 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0038; + break; + default: + if (gbSystemMessage == false) + { + systemMessage(0, N_("Unknown opcode %02x at %04x"), + gbReadOpcode(PC.W-1),PC.W-1); + gbSystemMessage =true; + } + return; diff --git a/src/dmg/gbCodesCB.h b/src/dmg/gbCodesCB.h index 64fefef2..5a09d8d5 100644 --- a/src/dmg/gbCodesCB.h +++ b/src/dmg/gbCodesCB.h @@ -1,1291 +1,1291 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - case 0x00: - // RLC B - AF.B.B0 = (BC.B.B1 & 0x80)?C_FLAG:0; - BC.B.B1 = (BC.B.B1<<1) | (BC.B.B1>>7); - AF.B.B0 |= ZeroTable[BC.B.B1]; - break; - case 0x01: - // RLC C - AF.B.B0 = (BC.B.B0 & 0x80)?C_FLAG:0; - BC.B.B0 = (BC.B.B0<<1) | (BC.B.B0>>7); - AF.B.B0 |= ZeroTable[BC.B.B0]; - break; - case 0x02: - // RLC D - AF.B.B0 = (DE.B.B1 & 0x80)?C_FLAG:0; - DE.B.B1 = (DE.B.B1<<1) | (DE.B.B1>>7); - AF.B.B0 |= ZeroTable[DE.B.B1]; - break; - case 0x03: - // RLC E - AF.B.B0 = (DE.B.B0 & 0x80)?C_FLAG:0; - DE.B.B0 = (DE.B.B0<<1) | (DE.B.B0>>7); - AF.B.B0 |= ZeroTable[DE.B.B0]; - break; - case 0x04: - // RLC H - AF.B.B0 = (HL.B.B1 & 0x80)?C_FLAG:0; - HL.B.B1 = (HL.B.B1<<1) | (HL.B.B1>>7); - AF.B.B0 |= ZeroTable[HL.B.B1]; - break; - case 0x05: - // RLC L - AF.B.B0 = (HL.B.B0 & 0x80)?C_FLAG:0; - HL.B.B0 = (HL.B.B0<<1) | (HL.B.B0>>7); - AF.B.B0 |= ZeroTable[HL.B.B0]; - break; - case 0x06: - // RLC (HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0 = (tempValue & 0x80)?C_FLAG:0; - tempValue = (tempValue<<1) | (tempValue>>7); - AF.B.B0 |= ZeroTable[tempValue]; - gbWriteMemory(HL.W,tempValue); - break; - case 0x07: - // RLC A - AF.B.B0 = (AF.B.B1 & 0x80)?C_FLAG:0; - AF.B.B1 = (AF.B.B1<<1) | (AF.B.B1>>7); - AF.B.B0 |= ZeroTable[AF.B.B1]; - break; - case 0x08: - // RRC B - AF.B.B0=(BC.B.B1&0x01 ? C_FLAG : 0); - BC.B.B1=(BC.B.B1>>1)|(BC.B.B1<<7); - AF.B.B0|=ZeroTable[BC.B.B1]; - break; - case 0x09: - // RRC C - AF.B.B0=(BC.B.B0&0x01 ? C_FLAG : 0); - BC.B.B0=(BC.B.B0>>1)|(BC.B.B0<<7); - AF.B.B0|=ZeroTable[BC.B.B0]; - break; - case 0x0a: - // RRC D - AF.B.B0=(DE.B.B1&0x01 ? C_FLAG : 0); - DE.B.B1=(DE.B.B1>>1)|(DE.B.B1<<7); - AF.B.B0|=ZeroTable[DE.B.B1]; - break; - case 0x0b: - // RRC E - AF.B.B0=(DE.B.B0&0x01 ? C_FLAG : 0); - DE.B.B0=(DE.B.B0>>1)|(DE.B.B0<<7); - AF.B.B0|=ZeroTable[DE.B.B0]; - break; - case 0x0c: - // RRC H - AF.B.B0=(HL.B.B1&0x01 ? C_FLAG : 0); - HL.B.B1=(HL.B.B1>>1)|(HL.B.B1<<7); - AF.B.B0|=ZeroTable[HL.B.B1]; - break; - case 0x0d: - // RRC L - AF.B.B0=(HL.B.B0&0x01 ? C_FLAG : 0); - HL.B.B0=(HL.B.B0>>1)|(HL.B.B0<<7); - AF.B.B0|=ZeroTable[HL.B.B0]; - break; - case 0x0e: - // RRC (HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0=(tempValue&0x01 ? C_FLAG : 0); - tempValue=(tempValue>>1)|(tempValue<<7); - AF.B.B0|=ZeroTable[tempValue]; - gbWriteMemory(HL.W,tempValue); - break; - case 0x0f: - // RRC A - AF.B.B0=(AF.B.B1&0x01 ? C_FLAG : 0); - AF.B.B1=(AF.B.B1>>1)|(AF.B.B1<<7); - AF.B.B0|=ZeroTable[AF.B.B1]; - break; - case 0x10: - // RL B - if(BC.B.B1&0x80) { - BC.B.B1=(BC.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[BC.B.B1]|C_FLAG; - } else { - BC.B.B1=(BC.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[BC.B.B1]; - } - break; - case 0x11: - // RL C - if(BC.B.B0&0x80) { - BC.B.B0=(BC.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[BC.B.B0]|C_FLAG; - } else { - BC.B.B0=(BC.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[BC.B.B0]; - } - break; - case 0x12: - // RL D - if(DE.B.B1&0x80) { - DE.B.B1=(DE.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[DE.B.B1]|C_FLAG; - } else { - DE.B.B1=(DE.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[DE.B.B1]; - } - break; - case 0x13: - // RL E - if(DE.B.B0&0x80) { - DE.B.B0=(DE.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[DE.B.B0]|C_FLAG; - } else { - DE.B.B0=(DE.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[DE.B.B0]; - } - break; - case 0x14: - // RL H - if(HL.B.B1&0x80) { - HL.B.B1=(HL.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[HL.B.B1]|C_FLAG; - } else { - HL.B.B1=(HL.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[HL.B.B1]; - } - break; - case 0x15: - // RL L - if(HL.B.B0&0x80) { - HL.B.B0=(HL.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[HL.B.B0]|C_FLAG; - } else { - HL.B.B0=(HL.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[HL.B.B0]; - } - break; - case 0x16: - // RL (HL) - tempValue=gbReadMemory(HL.W); - if(tempValue&0x80) { - tempValue=(tempValue<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[tempValue]|C_FLAG; - } else { - tempValue=(tempValue<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[tempValue]; - } - gbWriteMemory(HL.W,tempValue); - break; - case 0x17: - // RL A - if(AF.B.B1&0x80) { - AF.B.B1=(AF.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[AF.B.B1]|C_FLAG; - } else { - AF.B.B1=(AF.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); - AF.B.B0=ZeroTable[AF.B.B1]; - } - break; - case 0x18: - // RR B - if(BC.B.B1&0x01) { - BC.B.B1=(BC.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[BC.B.B1]|C_FLAG; - } else { - BC.B.B1=(BC.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[BC.B.B1]; - } - break; - case 0x19: - // RR C - if(BC.B.B0&0x01) { - BC.B.B0=(BC.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[BC.B.B0]|C_FLAG; - } else { - BC.B.B0=(BC.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[BC.B.B0]; - } - break; - case 0x1a: - // RR D - if(DE.B.B1&0x01) { - DE.B.B1=(DE.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[DE.B.B1]|C_FLAG; - } else { - DE.B.B1=(DE.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[DE.B.B1]; - } - break; - case 0x1b: - // RR E - if(DE.B.B0&0x01) { - DE.B.B0=(DE.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[DE.B.B0]|C_FLAG; - } else { - DE.B.B0=(DE.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[DE.B.B0]; - } - break; - case 0x1c: - // RR H - if(HL.B.B1&0x01) { - HL.B.B1=(HL.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[HL.B.B1]|C_FLAG; - } else { - HL.B.B1=(HL.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[HL.B.B1]; - } - break; - case 0x1d: - // RR L - if(HL.B.B0&0x01) { - HL.B.B0=(HL.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[HL.B.B0]|C_FLAG; - } else { - HL.B.B0=(HL.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[HL.B.B0]; - } - break; - case 0x1e: - // RR (HL) - tempValue=gbReadMemory(HL.W); - if(tempValue&0x01) { - tempValue=(tempValue>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[tempValue]|C_FLAG; - } else { - tempValue=(tempValue>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[tempValue]; - } - gbWriteMemory(HL.W,tempValue); - break; - case 0x1f: - // RR A - if(AF.B.B1&0x01) { - AF.B.B1=(AF.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[AF.B.B1]|C_FLAG; - } else { - AF.B.B1=(AF.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); - AF.B.B0=ZeroTable[AF.B.B1]; - } - break; - case 0x20: - // SLA B - AF.B.B0=(BC.B.B1&0x80?C_FLAG : 0); - BC.B.B1<<=1; - AF.B.B0|=ZeroTable[BC.B.B1]; - break; - case 0x21: - // SLA C - AF.B.B0=(BC.B.B0&0x80?C_FLAG : 0); - BC.B.B0<<=1; - AF.B.B0|=ZeroTable[BC.B.B0]; - break; - case 0x22: - // SLA D - AF.B.B0=(DE.B.B1&0x80?C_FLAG : 0); - DE.B.B1<<=1; - AF.B.B0|=ZeroTable[DE.B.B1]; - break; - case 0x23: - // SLA E - AF.B.B0=(DE.B.B0&0x80?C_FLAG : 0); - DE.B.B0<<=1; - AF.B.B0|=ZeroTable[DE.B.B0]; - break; - case 0x24: - // SLA H - AF.B.B0=(HL.B.B1&0x80?C_FLAG : 0); - HL.B.B1<<=1; - AF.B.B0|=ZeroTable[HL.B.B1]; - break; - case 0x25: - // SLA L - AF.B.B0=(HL.B.B0&0x80?C_FLAG : 0); - HL.B.B0<<=1; - AF.B.B0|=ZeroTable[HL.B.B0]; - break; - case 0x26: - // SLA (HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0=(tempValue&0x80?C_FLAG : 0); - tempValue<<=1; - AF.B.B0|=ZeroTable[tempValue]; - gbWriteMemory(HL.W,tempValue); - break; - case 0x27: - // SLA A - AF.B.B0=(AF.B.B1&0x80?C_FLAG : 0); - AF.B.B1<<=1; - AF.B.B0|=ZeroTable[AF.B.B1]; - break; - case 0x28: - // SRA B - AF.B.B0=(BC.B.B1&0x01 ? C_FLAG: 0); - BC.B.B1=(BC.B.B1>>1)|(BC.B.B1&0x80); - AF.B.B0|=ZeroTable[BC.B.B1]; - break; - case 0x29: - // SRA C - AF.B.B0=(BC.B.B0&0x01 ? C_FLAG: 0); - BC.B.B0=(BC.B.B0>>1)|(BC.B.B0&0x80); - AF.B.B0|=ZeroTable[BC.B.B0]; - break; - case 0x2a: - // SRA D - AF.B.B0=(DE.B.B1&0x01 ? C_FLAG: 0); - DE.B.B1=(DE.B.B1>>1)|(DE.B.B1&0x80); - AF.B.B0|=ZeroTable[DE.B.B1]; - break; - case 0x2b: - // SRA E - AF.B.B0=(DE.B.B0&0x01 ? C_FLAG: 0); - DE.B.B0=(DE.B.B0>>1)|(DE.B.B0&0x80); - AF.B.B0|=ZeroTable[DE.B.B0]; - break; - case 0x2c: - // SRA H - AF.B.B0=(HL.B.B1&0x01 ? C_FLAG: 0); - HL.B.B1=(HL.B.B1>>1)|(HL.B.B1&0x80); - AF.B.B0|=ZeroTable[HL.B.B1]; - break; - case 0x2d: - // SRA L - AF.B.B0=(HL.B.B0&0x01 ? C_FLAG: 0); - HL.B.B0=(HL.B.B0>>1)|(HL.B.B0&0x80); - AF.B.B0|=ZeroTable[HL.B.B0]; - break; - case 0x2e: - // SRA (HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0=(tempValue&0x01 ? C_FLAG: 0); - tempValue=(tempValue>>1)|(tempValue&0x80); - AF.B.B0|=ZeroTable[tempValue]; - gbWriteMemory(HL.W,tempValue); - break; - case 0x2f: - // SRA A - AF.B.B0=(AF.B.B1&0x01 ? C_FLAG: 0); - AF.B.B1=(AF.B.B1>>1)|(AF.B.B1&0x80); - AF.B.B0|=ZeroTable[AF.B.B1]; - break; - case 0x30: - // SWAP B - BC.B.B1 = (BC.B.B1&0xf0)>>4 | (BC.B.B1&0x0f)<<4; - AF.B.B0 = ZeroTable[BC.B.B1]; - break; - case 0x31: - // SWAP C - BC.B.B0 = (BC.B.B0&0xf0)>>4 | (BC.B.B0&0x0f)<<4; - AF.B.B0 = ZeroTable[BC.B.B0]; - break; - case 0x32: - // SWAP D - DE.B.B1 = (DE.B.B1&0xf0)>>4 | (DE.B.B1&0x0f)<<4; - AF.B.B0 = ZeroTable[DE.B.B1]; - break; - case 0x33: - // SWAP E - DE.B.B0 = (DE.B.B0&0xf0)>>4 | (DE.B.B0&0x0f)<<4; - AF.B.B0 = ZeroTable[DE.B.B0]; - break; - case 0x34: - // SWAP H - HL.B.B1 = (HL.B.B1&0xf0)>>4 | (HL.B.B1&0x0f)<<4; - AF.B.B0 = ZeroTable[HL.B.B1]; - break; - case 0x35: - // SWAP L - HL.B.B0 = (HL.B.B0&0xf0)>>4 | (HL.B.B0&0x0f)<<4; - AF.B.B0 = ZeroTable[HL.B.B0]; - break; - case 0x36: - // SWAP (HL) - tempValue=gbReadMemory(HL.W); - tempValue = (tempValue&0xf0)>>4 | (tempValue&0x0f)<<4; - AF.B.B0 = ZeroTable[tempValue]; - gbWriteMemory(HL.W,tempValue); - break; - case 0x37: - // SWAP A - AF.B.B1 = (AF.B.B1&0xf0)>>4 | (AF.B.B1&0x0f)<<4; - AF.B.B0 = ZeroTable[AF.B.B1]; - break; - case 0x38: - // SRL B - AF.B.B0=(BC.B.B1&0x01)?C_FLAG:0; - BC.B.B1>>=1; - AF.B.B0|=ZeroTable[BC.B.B1]; - break; - case 0x39: - // SRL C - AF.B.B0=(BC.B.B0&0x01)?C_FLAG:0; - BC.B.B0>>=1; - AF.B.B0|=ZeroTable[BC.B.B0]; - break; - case 0x3a: - // SRL D - AF.B.B0=(DE.B.B1&0x01)?C_FLAG:0; - DE.B.B1>>=1; - AF.B.B0|=ZeroTable[DE.B.B1]; - break; - case 0x3b: - // SRL E - AF.B.B0=(DE.B.B0&0x01)?C_FLAG:0; - DE.B.B0>>=1; - AF.B.B0|=ZeroTable[DE.B.B0]; - break; - case 0x3c: - // SRL H - AF.B.B0=(HL.B.B1&0x01)?C_FLAG:0; - HL.B.B1>>=1; - AF.B.B0|=ZeroTable[HL.B.B1]; - break; - case 0x3d: - // SRL L - AF.B.B0=(HL.B.B0&0x01)?C_FLAG:0; - HL.B.B0>>=1; - AF.B.B0|=ZeroTable[HL.B.B0]; - break; - case 0x3e: - // SRL (HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0=(tempValue&0x01)?C_FLAG:0; - tempValue>>=1; - AF.B.B0|=ZeroTable[tempValue]; - gbWriteMemory(HL.W,tempValue); - break; - case 0x3f: - // SRL A - AF.B.B0=(AF.B.B1&0x01)?C_FLAG:0; - AF.B.B1>>=1; - AF.B.B0|=ZeroTable[AF.B.B1]; - break; - case 0x40: - // BIT 0,B - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<0)? 0:Z_FLAG); - break; - case 0x41: - // BIT 0,C - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<0)? 0:Z_FLAG); - break; - case 0x42: - // BIT 0,D - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<0)? 0:Z_FLAG); - break; - case 0x43: - // BIT 0,E - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<0)? 0:Z_FLAG); - break; - case 0x44: - // BIT 0,H - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<0)? 0:Z_FLAG); - break; - case 0x45: - // BIT 0,L - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<0)? 0:Z_FLAG); - break; - case 0x46: - // BIT 0,(HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<0)? 0:Z_FLAG); - break; - case 0x47: - // BIT 0,A - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<0)? 0:Z_FLAG); - break; - case 0x48: - // BIT 1,B - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<1)? 0:Z_FLAG); - break; - case 0x49: - // BIT 1,C - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<1)? 0:Z_FLAG); - break; - case 0x4a: - // BIT 1,D - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<1)? 0:Z_FLAG); - break; - case 0x4b: - // BIT 1,E - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<1)? 0:Z_FLAG); - break; - case 0x4c: - // BIT 1,H - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<1)? 0:Z_FLAG); - break; - case 0x4d: - // BIT 1,L - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<1)? 0:Z_FLAG); - break; - case 0x4e: - // BIT 1,(HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<1)? 0:Z_FLAG); - break; - case 0x4f: - // BIT 1,A - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<1)? 0:Z_FLAG); - break; - case 0x50: - // BIT 2,B - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<2)? 0:Z_FLAG); - break; - case 0x51: - // BIT 2,C - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<2)? 0:Z_FLAG); - break; - case 0x52: - // BIT 2,D - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<2)? 0:Z_FLAG); - break; - case 0x53: - // BIT 2,E - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<2)? 0:Z_FLAG); - break; - case 0x54: - // BIT 2,H - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<2)? 0:Z_FLAG); - break; - case 0x55: - // BIT 2,L - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<2)? 0:Z_FLAG); - break; - case 0x56: - // BIT 2,(HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<2)? 0:Z_FLAG); - break; - case 0x57: - // BIT 2,A - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<2)? 0:Z_FLAG); - break; - case 0x58: - // BIT 3,B - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<3)? 0:Z_FLAG); - break; - case 0x59: - // BIT 3,C - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<3)? 0:Z_FLAG); - break; - case 0x5a: - // BIT 3,D - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<3)? 0:Z_FLAG); - break; - case 0x5b: - // BIT 3,E - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<3)? 0:Z_FLAG); - break; - case 0x5c: - // BIT 3,H - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<3)? 0:Z_FLAG); - break; - case 0x5d: - // BIT 3,L - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<3)? 0:Z_FLAG); - break; - case 0x5e: - // BIT 3,(HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<3)? 0:Z_FLAG); - break; - case 0x5f: - // BIT 3,A - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<3)? 0:Z_FLAG); - break; - case 0x60: - // BIT 4,B - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<4)? 0:Z_FLAG); - break; - case 0x61: - // BIT 4,C - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<4)? 0:Z_FLAG); - break; - case 0x62: - // BIT 4,D - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<4)? 0:Z_FLAG); - break; - case 0x63: - // BIT 4,E - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<4)? 0:Z_FLAG); - break; - case 0x64: - // BIT 4,H - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<4)? 0:Z_FLAG); - break; - case 0x65: - // BIT 4,L - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<4)? 0:Z_FLAG); - break; - case 0x66: - // BIT 4,(HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<4)? 0:Z_FLAG); - break; - case 0x67: - // BIT 4,A - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<4)? 0:Z_FLAG); - break; - case 0x68: - // BIT 5,B - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<5)? 0:Z_FLAG); - break; - case 0x69: - // BIT 5,C - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<5)? 0:Z_FLAG); - break; - case 0x6a: - // BIT 5,D - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<5)? 0:Z_FLAG); - break; - case 0x6b: - // BIT 5,E - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<5)? 0:Z_FLAG); - break; - case 0x6c: - // BIT 5,H - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<5)? 0:Z_FLAG); - break; - case 0x6d: - // BIT 5,L - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<5)? 0:Z_FLAG); - break; - case 0x6e: - // BIT 5,(HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<5)? 0:Z_FLAG); - break; - case 0x6f: - // BIT 5,A - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<5)? 0:Z_FLAG); - break; - case 0x70: - // BIT 6,B - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<6)? 0:Z_FLAG); - break; - case 0x71: - // BIT 6,C - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<6)? 0:Z_FLAG); - break; - case 0x72: - // BIT 6,D - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<6)? 0:Z_FLAG); - break; - case 0x73: - // BIT 6,E - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<6)? 0:Z_FLAG); - break; - case 0x74: - // BIT 6,H - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<6)? 0:Z_FLAG); - break; - case 0x75: - // BIT 6,L - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<6)? 0:Z_FLAG); - break; - case 0x76: - // BIT 6,(HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<6)? 0:Z_FLAG); - break; - case 0x77: - // BIT 6,A - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<6)? 0:Z_FLAG); - break; - case 0x78: - // BIT 7,B - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<7)? 0:Z_FLAG); - break; - case 0x79: - // BIT 7,C - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<7)? 0:Z_FLAG); - break; - case 0x7a: - // BIT 7,D - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<7)? 0:Z_FLAG); - break; - case 0x7b: - // BIT 7,E - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<7)? 0:Z_FLAG); - break; - case 0x7c: - // BIT 7,H - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<7)? 0:Z_FLAG); - break; - case 0x7d: - // BIT 7,L - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<7)? 0:Z_FLAG); - break; - case 0x7e: - // BIT 7,(HL) - tempValue=gbReadMemory(HL.W); - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<7)? 0:Z_FLAG); - break; - case 0x7f: - // BIT 7,A - AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<7)? 0:Z_FLAG); - break; - case 0x80: - // RES 0,B - BC.B.B1&=~(1<<0); - break; - case 0x81: - // RES 0,C - BC.B.B0&=~(1<<0); - break; - case 0x82: - // RES 0,D - DE.B.B1&=~(1<<0); - break; - case 0x83: - // RES 0,E - DE.B.B0&=~(1<<0); - break; - case 0x84: - // RES 0,H - HL.B.B1&=~(1<<0); - break; - case 0x85: - // RES 0,L - HL.B.B0&=~(1<<0); - break; - case 0x86: - // RES 0,(HL) - tempValue=gbReadMemory(HL.W); - tempValue&=~(1<<0); - gbWriteMemory(HL.W,tempValue); - break; - case 0x87: - // RES 0,A - AF.B.B1&=~(1<<0); - break; - case 0x88: - // RES 1,B - BC.B.B1&=~(1<<1); - break; - case 0x89: - // RES 1,C - BC.B.B0&=~(1<<1); - break; - case 0x8a: - // RES 1,D - DE.B.B1&=~(1<<1); - break; - case 0x8b: - // RES 1,E - DE.B.B0&=~(1<<1); - break; - case 0x8c: - // RES 1,H - HL.B.B1&=~(1<<1); - break; - case 0x8d: - // RES 1,L - HL.B.B0&=~(1<<1); - break; - case 0x8e: - // RES 1,(HL) - tempValue=gbReadMemory(HL.W); - tempValue&=~(1<<1); - gbWriteMemory(HL.W,tempValue); - break; - case 0x8f: - // RES 1,A - AF.B.B1&=~(1<<1); - break; - case 0x90: - // RES 2,B - BC.B.B1&=~(1<<2); - break; - case 0x91: - // RES 2,C - BC.B.B0&=~(1<<2); - break; - case 0x92: - // RES 2,D - DE.B.B1&=~(1<<2); - break; - case 0x93: - // RES 2,E - DE.B.B0&=~(1<<2); - break; - case 0x94: - // RES 2,H - HL.B.B1&=~(1<<2); - break; - case 0x95: - // RES 2,L - HL.B.B0&=~(1<<2); - break; - case 0x96: - // RES 2,(HL) - tempValue=gbReadMemory(HL.W); - tempValue&=~(1<<2); - gbWriteMemory(HL.W,tempValue); - break; - case 0x97: - // RES 2,A - AF.B.B1&=~(1<<2); - break; - case 0x98: - // RES 3,B - BC.B.B1&=~(1<<3); - break; - case 0x99: - // RES 3,C - BC.B.B0&=~(1<<3); - break; - case 0x9a: - // RES 3,D - DE.B.B1&=~(1<<3); - break; - case 0x9b: - // RES 3,E - DE.B.B0&=~(1<<3); - break; - case 0x9c: - // RES 3,H - HL.B.B1&=~(1<<3); - break; - case 0x9d: - // RES 3,L - HL.B.B0&=~(1<<3); - break; - case 0x9e: - // RES 3,(HL) - tempValue=gbReadMemory(HL.W); - tempValue&=~(1<<3); - gbWriteMemory(HL.W,tempValue); - break; - case 0x9f: - // RES 3,A - AF.B.B1&=~(1<<3); - break; - case 0xa0: - // RES 4,B - BC.B.B1&=~(1<<4); - break; - case 0xa1: - // RES 4,C - BC.B.B0&=~(1<<4); - break; - case 0xa2: - // RES 4,D - DE.B.B1&=~(1<<4); - break; - case 0xa3: - // RES 4,E - DE.B.B0&=~(1<<4); - break; - case 0xa4: - // RES 4,H - HL.B.B1&=~(1<<4); - break; - case 0xa5: - // RES 4,L - HL.B.B0&=~(1<<4); - break; - case 0xa6: - // RES 4,(HL) - tempValue=gbReadMemory(HL.W); - tempValue&=~(1<<4); - gbWriteMemory(HL.W,tempValue); - break; - case 0xa7: - // RES 4,A - AF.B.B1&=~(1<<4); - break; - case 0xa8: - // RES 5,B - BC.B.B1&=~(1<<5); - break; - case 0xa9: - // RES 5,C - BC.B.B0&=~(1<<5); - break; - case 0xaa: - // RES 5,D - DE.B.B1&=~(1<<5); - break; - case 0xab: - // RES 5,E - DE.B.B0&=~(1<<5); - break; - case 0xac: - // RES 5,H - HL.B.B1&=~(1<<5); - break; - case 0xad: - // RES 5,L - HL.B.B0&=~(1<<5); - break; - case 0xae: - // RES 5,(HL) - tempValue=gbReadMemory(HL.W); - tempValue&=~(1<<5); - gbWriteMemory(HL.W,tempValue); - break; - case 0xaf: - // RES 5,A - AF.B.B1&=~(1<<5); - break; - case 0xb0: - // RES 6,B - BC.B.B1&=~(1<<6); - break; - case 0xb1: - // RES 6,C - BC.B.B0&=~(1<<6); - break; - case 0xb2: - // RES 6,D - DE.B.B1&=~(1<<6); - break; - case 0xb3: - // RES 6,E - DE.B.B0&=~(1<<6); - break; - case 0xb4: - // RES 6,H - HL.B.B1&=~(1<<6); - break; - case 0xb5: - // RES 6,L - HL.B.B0&=~(1<<6); - break; - case 0xb6: - // RES 6,(HL) - tempValue=gbReadMemory(HL.W); - tempValue&=~(1<<6); - gbWriteMemory(HL.W,tempValue); - break; - case 0xb7: - // RES 6,A - AF.B.B1&=~(1<<6); - break; - case 0xb8: - // RES 7,B - BC.B.B1&=~(1<<7); - break; - case 0xb9: - // RES 7,C - BC.B.B0&=~(1<<7); - break; - case 0xba: - // RES 7,D - DE.B.B1&=~(1<<7); - break; - case 0xbb: - // RES 7,E - DE.B.B0&=~(1<<7); - break; - case 0xbc: - // RES 7,H - HL.B.B1&=~(1<<7); - break; - case 0xbd: - // RES 7,L - HL.B.B0&=~(1<<7); - break; - case 0xbe: - // RES 7,(HL) - tempValue=gbReadMemory(HL.W); - tempValue&=~(1<<7); - gbWriteMemory(HL.W,tempValue); - break; - case 0xbf: - // RES 7,A - AF.B.B1&=~(1<<7); - break; - case 0xc0: - // SET 0,B - BC.B.B1|=1<<0; - break; - case 0xc1: - // SET 0,C - BC.B.B0|=1<<0; - break; - case 0xc2: - // SET 0,D - DE.B.B1|=1<<0; - break; - case 0xc3: - // SET 0,E - DE.B.B0|=1<<0; - break; - case 0xc4: - // SET 0,H - HL.B.B1|=1<<0; - break; - case 0xc5: - // SET 0,L - HL.B.B0|=1<<0; - break; - case 0xc6: - // SET 0,(HL) - tempValue=gbReadMemory(HL.W); - tempValue|=1<<0; - gbWriteMemory(HL.W,tempValue); - break; - case 0xc7: - // SET 0,A - AF.B.B1|=1<<0; - break; - case 0xc8: - // SET 1,B - BC.B.B1|=1<<1; - break; - case 0xc9: - // SET 1,C - BC.B.B0|=1<<1; - break; - case 0xca: - // SET 1,D - DE.B.B1|=1<<1; - break; - case 0xcb: - // SET 1,E - DE.B.B0|=1<<1; - break; - case 0xcc: - // SET 1,H - HL.B.B1|=1<<1; - break; - case 0xcd: - // SET 1,L - HL.B.B0|=1<<1; - break; - case 0xce: - // SET 1,(HL) - tempValue=gbReadMemory(HL.W); - tempValue|=1<<1; - gbWriteMemory(HL.W,tempValue); - break; - case 0xcf: - // SET 1,A - AF.B.B1|=1<<1; - break; - case 0xd0: - // SET 2,B - BC.B.B1|=1<<2; - break; - case 0xd1: - // SET 2,C - BC.B.B0|=1<<2; - break; - case 0xd2: - // SET 2,D - DE.B.B1|=1<<2; - break; - case 0xd3: - // SET 2,E - DE.B.B0|=1<<2; - break; - case 0xd4: - // SET 2,H - HL.B.B1|=1<<2; - break; - case 0xd5: - // SET 2,L - HL.B.B0|=1<<2; - break; - case 0xd6: - // SET 2,(HL) - tempValue=gbReadMemory(HL.W); - tempValue|=1<<2; - gbWriteMemory(HL.W,tempValue); - break; - case 0xd7: - // SET 2,A - AF.B.B1|=1<<2; - break; - case 0xd8: - // SET 3,B - BC.B.B1|=1<<3; - break; - case 0xd9: - // SET 3,C - BC.B.B0|=1<<3; - break; - case 0xda: - // SET 3,D - DE.B.B1|=1<<3; - break; - case 0xdb: - // SET 3,E - DE.B.B0|=1<<3; - break; - case 0xdc: - // SET 3,H - HL.B.B1|=1<<3; - break; - case 0xdd: - // SET 3,L - HL.B.B0|=1<<3; - break; - case 0xde: - // SET 3,(HL) - tempValue=gbReadMemory(HL.W); - tempValue|=1<<3; - gbWriteMemory(HL.W,tempValue); - break; - case 0xdf: - // SET 3,A - AF.B.B1|=1<<3; - break; - case 0xe0: - // SET 4,B - BC.B.B1|=1<<4; - break; - case 0xe1: - // SET 4,C - BC.B.B0|=1<<4; - break; - case 0xe2: - // SET 4,D - DE.B.B1|=1<<4; - break; - case 0xe3: - // SET 4,E - DE.B.B0|=1<<4; - break; - case 0xe4: - // SET 4,H - HL.B.B1|=1<<4; - break; - case 0xe5: - // SET 4,L - HL.B.B0|=1<<4; - break; - case 0xe6: - // SET 4,(HL) - tempValue=gbReadMemory(HL.W); - tempValue|=1<<4; - gbWriteMemory(HL.W,tempValue); - break; - case 0xe7: - // SET 4,A - AF.B.B1|=1<<4; - break; - case 0xe8: - // SET 5,B - BC.B.B1|=1<<5; - break; - case 0xe9: - // SET 5,C - BC.B.B0|=1<<5; - break; - case 0xea: - // SET 5,D - DE.B.B1|=1<<5; - break; - case 0xeb: - // SET 5,E - DE.B.B0|=1<<5; - break; - case 0xec: - // SET 5,H - HL.B.B1|=1<<5; - break; - case 0xed: - // SET 5,L - HL.B.B0|=1<<5; - break; - case 0xee: - // SET 5,(HL) - tempValue=gbReadMemory(HL.W); - tempValue|=1<<5; - gbWriteMemory(HL.W,tempValue); - break; - case 0xef: - // SET 5,A - AF.B.B1|=1<<5; - break; - case 0xf0: - // SET 6,B - BC.B.B1|=1<<6; - break; - case 0xf1: - // SET 6,C - BC.B.B0|=1<<6; - break; - case 0xf2: - // SET 6,D - DE.B.B1|=1<<6; - break; - case 0xf3: - // SET 6,E - DE.B.B0|=1<<6; - break; - case 0xf4: - // SET 6,H - HL.B.B1|=1<<6; - break; - case 0xf5: - // SET 6,L - HL.B.B0|=1<<6; - break; - case 0xf6: - // SET 6,(HL) - tempValue=gbReadMemory(HL.W); - tempValue|=1<<6; - gbWriteMemory(HL.W,tempValue); - break; - case 0xf7: - // SET 6,A - AF.B.B1|=1<<6; - break; - case 0xf8: - // SET 7,B - BC.B.B1|=1<<7; - break; - case 0xf9: - // SET 7,C - BC.B.B0|=1<<7; - break; - case 0xfa: - // SET 7,D - DE.B.B1|=1<<7; - break; - case 0xfb: - // SET 7,E - DE.B.B0|=1<<7; - break; - case 0xfc: - // SET 7,H - HL.B.B1|=1<<7; - break; - case 0xfd: - // SET 7,L - HL.B.B0|=1<<7; - break; - case 0xfe: - // SET 7,(HL) - tempValue=gbReadMemory(HL.W); - tempValue|=1<<7; - gbWriteMemory(HL.W,tempValue); - break; - case 0xff: - // SET 7,A - AF.B.B1|=1<<7; - break; - default: - if (gbSystemMessage == false) - { - systemMessage(0, N_("Unknown opcode %02x at %04x"), - gbReadOpcode(PC.W-1),PC.W-1); - gbSystemMessage =true; - } - return; +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + case 0x00: + // RLC B + AF.B.B0 = (BC.B.B1 & 0x80)?C_FLAG:0; + BC.B.B1 = (BC.B.B1<<1) | (BC.B.B1>>7); + AF.B.B0 |= ZeroTable[BC.B.B1]; + break; + case 0x01: + // RLC C + AF.B.B0 = (BC.B.B0 & 0x80)?C_FLAG:0; + BC.B.B0 = (BC.B.B0<<1) | (BC.B.B0>>7); + AF.B.B0 |= ZeroTable[BC.B.B0]; + break; + case 0x02: + // RLC D + AF.B.B0 = (DE.B.B1 & 0x80)?C_FLAG:0; + DE.B.B1 = (DE.B.B1<<1) | (DE.B.B1>>7); + AF.B.B0 |= ZeroTable[DE.B.B1]; + break; + case 0x03: + // RLC E + AF.B.B0 = (DE.B.B0 & 0x80)?C_FLAG:0; + DE.B.B0 = (DE.B.B0<<1) | (DE.B.B0>>7); + AF.B.B0 |= ZeroTable[DE.B.B0]; + break; + case 0x04: + // RLC H + AF.B.B0 = (HL.B.B1 & 0x80)?C_FLAG:0; + HL.B.B1 = (HL.B.B1<<1) | (HL.B.B1>>7); + AF.B.B0 |= ZeroTable[HL.B.B1]; + break; + case 0x05: + // RLC L + AF.B.B0 = (HL.B.B0 & 0x80)?C_FLAG:0; + HL.B.B0 = (HL.B.B0<<1) | (HL.B.B0>>7); + AF.B.B0 |= ZeroTable[HL.B.B0]; + break; + case 0x06: + // RLC (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0 = (tempValue & 0x80)?C_FLAG:0; + tempValue = (tempValue<<1) | (tempValue>>7); + AF.B.B0 |= ZeroTable[tempValue]; + gbWriteMemory(HL.W,tempValue); + break; + case 0x07: + // RLC A + AF.B.B0 = (AF.B.B1 & 0x80)?C_FLAG:0; + AF.B.B1 = (AF.B.B1<<1) | (AF.B.B1>>7); + AF.B.B0 |= ZeroTable[AF.B.B1]; + break; + case 0x08: + // RRC B + AF.B.B0=(BC.B.B1&0x01 ? C_FLAG : 0); + BC.B.B1=(BC.B.B1>>1)|(BC.B.B1<<7); + AF.B.B0|=ZeroTable[BC.B.B1]; + break; + case 0x09: + // RRC C + AF.B.B0=(BC.B.B0&0x01 ? C_FLAG : 0); + BC.B.B0=(BC.B.B0>>1)|(BC.B.B0<<7); + AF.B.B0|=ZeroTable[BC.B.B0]; + break; + case 0x0a: + // RRC D + AF.B.B0=(DE.B.B1&0x01 ? C_FLAG : 0); + DE.B.B1=(DE.B.B1>>1)|(DE.B.B1<<7); + AF.B.B0|=ZeroTable[DE.B.B1]; + break; + case 0x0b: + // RRC E + AF.B.B0=(DE.B.B0&0x01 ? C_FLAG : 0); + DE.B.B0=(DE.B.B0>>1)|(DE.B.B0<<7); + AF.B.B0|=ZeroTable[DE.B.B0]; + break; + case 0x0c: + // RRC H + AF.B.B0=(HL.B.B1&0x01 ? C_FLAG : 0); + HL.B.B1=(HL.B.B1>>1)|(HL.B.B1<<7); + AF.B.B0|=ZeroTable[HL.B.B1]; + break; + case 0x0d: + // RRC L + AF.B.B0=(HL.B.B0&0x01 ? C_FLAG : 0); + HL.B.B0=(HL.B.B0>>1)|(HL.B.B0<<7); + AF.B.B0|=ZeroTable[HL.B.B0]; + break; + case 0x0e: + // RRC (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(tempValue&0x01 ? C_FLAG : 0); + tempValue=(tempValue>>1)|(tempValue<<7); + AF.B.B0|=ZeroTable[tempValue]; + gbWriteMemory(HL.W,tempValue); + break; + case 0x0f: + // RRC A + AF.B.B0=(AF.B.B1&0x01 ? C_FLAG : 0); + AF.B.B1=(AF.B.B1>>1)|(AF.B.B1<<7); + AF.B.B0|=ZeroTable[AF.B.B1]; + break; + case 0x10: + // RL B + if(BC.B.B1&0x80) { + BC.B.B1=(BC.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[BC.B.B1]|C_FLAG; + } else { + BC.B.B1=(BC.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[BC.B.B1]; + } + break; + case 0x11: + // RL C + if(BC.B.B0&0x80) { + BC.B.B0=(BC.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[BC.B.B0]|C_FLAG; + } else { + BC.B.B0=(BC.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[BC.B.B0]; + } + break; + case 0x12: + // RL D + if(DE.B.B1&0x80) { + DE.B.B1=(DE.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[DE.B.B1]|C_FLAG; + } else { + DE.B.B1=(DE.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[DE.B.B1]; + } + break; + case 0x13: + // RL E + if(DE.B.B0&0x80) { + DE.B.B0=(DE.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[DE.B.B0]|C_FLAG; + } else { + DE.B.B0=(DE.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[DE.B.B0]; + } + break; + case 0x14: + // RL H + if(HL.B.B1&0x80) { + HL.B.B1=(HL.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[HL.B.B1]|C_FLAG; + } else { + HL.B.B1=(HL.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[HL.B.B1]; + } + break; + case 0x15: + // RL L + if(HL.B.B0&0x80) { + HL.B.B0=(HL.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[HL.B.B0]|C_FLAG; + } else { + HL.B.B0=(HL.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[HL.B.B0]; + } + break; + case 0x16: + // RL (HL) + tempValue=gbReadMemory(HL.W); + if(tempValue&0x80) { + tempValue=(tempValue<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[tempValue]|C_FLAG; + } else { + tempValue=(tempValue<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[tempValue]; + } + gbWriteMemory(HL.W,tempValue); + break; + case 0x17: + // RL A + if(AF.B.B1&0x80) { + AF.B.B1=(AF.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[AF.B.B1]|C_FLAG; + } else { + AF.B.B1=(AF.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0=ZeroTable[AF.B.B1]; + } + break; + case 0x18: + // RR B + if(BC.B.B1&0x01) { + BC.B.B1=(BC.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[BC.B.B1]|C_FLAG; + } else { + BC.B.B1=(BC.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[BC.B.B1]; + } + break; + case 0x19: + // RR C + if(BC.B.B0&0x01) { + BC.B.B0=(BC.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[BC.B.B0]|C_FLAG; + } else { + BC.B.B0=(BC.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[BC.B.B0]; + } + break; + case 0x1a: + // RR D + if(DE.B.B1&0x01) { + DE.B.B1=(DE.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[DE.B.B1]|C_FLAG; + } else { + DE.B.B1=(DE.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[DE.B.B1]; + } + break; + case 0x1b: + // RR E + if(DE.B.B0&0x01) { + DE.B.B0=(DE.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[DE.B.B0]|C_FLAG; + } else { + DE.B.B0=(DE.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[DE.B.B0]; + } + break; + case 0x1c: + // RR H + if(HL.B.B1&0x01) { + HL.B.B1=(HL.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[HL.B.B1]|C_FLAG; + } else { + HL.B.B1=(HL.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[HL.B.B1]; + } + break; + case 0x1d: + // RR L + if(HL.B.B0&0x01) { + HL.B.B0=(HL.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[HL.B.B0]|C_FLAG; + } else { + HL.B.B0=(HL.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[HL.B.B0]; + } + break; + case 0x1e: + // RR (HL) + tempValue=gbReadMemory(HL.W); + if(tempValue&0x01) { + tempValue=(tempValue>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[tempValue]|C_FLAG; + } else { + tempValue=(tempValue>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[tempValue]; + } + gbWriteMemory(HL.W,tempValue); + break; + case 0x1f: + // RR A + if(AF.B.B1&0x01) { + AF.B.B1=(AF.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[AF.B.B1]|C_FLAG; + } else { + AF.B.B1=(AF.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[AF.B.B1]; + } + break; + case 0x20: + // SLA B + AF.B.B0=(BC.B.B1&0x80?C_FLAG : 0); + BC.B.B1<<=1; + AF.B.B0|=ZeroTable[BC.B.B1]; + break; + case 0x21: + // SLA C + AF.B.B0=(BC.B.B0&0x80?C_FLAG : 0); + BC.B.B0<<=1; + AF.B.B0|=ZeroTable[BC.B.B0]; + break; + case 0x22: + // SLA D + AF.B.B0=(DE.B.B1&0x80?C_FLAG : 0); + DE.B.B1<<=1; + AF.B.B0|=ZeroTable[DE.B.B1]; + break; + case 0x23: + // SLA E + AF.B.B0=(DE.B.B0&0x80?C_FLAG : 0); + DE.B.B0<<=1; + AF.B.B0|=ZeroTable[DE.B.B0]; + break; + case 0x24: + // SLA H + AF.B.B0=(HL.B.B1&0x80?C_FLAG : 0); + HL.B.B1<<=1; + AF.B.B0|=ZeroTable[HL.B.B1]; + break; + case 0x25: + // SLA L + AF.B.B0=(HL.B.B0&0x80?C_FLAG : 0); + HL.B.B0<<=1; + AF.B.B0|=ZeroTable[HL.B.B0]; + break; + case 0x26: + // SLA (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(tempValue&0x80?C_FLAG : 0); + tempValue<<=1; + AF.B.B0|=ZeroTable[tempValue]; + gbWriteMemory(HL.W,tempValue); + break; + case 0x27: + // SLA A + AF.B.B0=(AF.B.B1&0x80?C_FLAG : 0); + AF.B.B1<<=1; + AF.B.B0|=ZeroTable[AF.B.B1]; + break; + case 0x28: + // SRA B + AF.B.B0=(BC.B.B1&0x01 ? C_FLAG: 0); + BC.B.B1=(BC.B.B1>>1)|(BC.B.B1&0x80); + AF.B.B0|=ZeroTable[BC.B.B1]; + break; + case 0x29: + // SRA C + AF.B.B0=(BC.B.B0&0x01 ? C_FLAG: 0); + BC.B.B0=(BC.B.B0>>1)|(BC.B.B0&0x80); + AF.B.B0|=ZeroTable[BC.B.B0]; + break; + case 0x2a: + // SRA D + AF.B.B0=(DE.B.B1&0x01 ? C_FLAG: 0); + DE.B.B1=(DE.B.B1>>1)|(DE.B.B1&0x80); + AF.B.B0|=ZeroTable[DE.B.B1]; + break; + case 0x2b: + // SRA E + AF.B.B0=(DE.B.B0&0x01 ? C_FLAG: 0); + DE.B.B0=(DE.B.B0>>1)|(DE.B.B0&0x80); + AF.B.B0|=ZeroTable[DE.B.B0]; + break; + case 0x2c: + // SRA H + AF.B.B0=(HL.B.B1&0x01 ? C_FLAG: 0); + HL.B.B1=(HL.B.B1>>1)|(HL.B.B1&0x80); + AF.B.B0|=ZeroTable[HL.B.B1]; + break; + case 0x2d: + // SRA L + AF.B.B0=(HL.B.B0&0x01 ? C_FLAG: 0); + HL.B.B0=(HL.B.B0>>1)|(HL.B.B0&0x80); + AF.B.B0|=ZeroTable[HL.B.B0]; + break; + case 0x2e: + // SRA (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(tempValue&0x01 ? C_FLAG: 0); + tempValue=(tempValue>>1)|(tempValue&0x80); + AF.B.B0|=ZeroTable[tempValue]; + gbWriteMemory(HL.W,tempValue); + break; + case 0x2f: + // SRA A + AF.B.B0=(AF.B.B1&0x01 ? C_FLAG: 0); + AF.B.B1=(AF.B.B1>>1)|(AF.B.B1&0x80); + AF.B.B0|=ZeroTable[AF.B.B1]; + break; + case 0x30: + // SWAP B + BC.B.B1 = (BC.B.B1&0xf0)>>4 | (BC.B.B1&0x0f)<<4; + AF.B.B0 = ZeroTable[BC.B.B1]; + break; + case 0x31: + // SWAP C + BC.B.B0 = (BC.B.B0&0xf0)>>4 | (BC.B.B0&0x0f)<<4; + AF.B.B0 = ZeroTable[BC.B.B0]; + break; + case 0x32: + // SWAP D + DE.B.B1 = (DE.B.B1&0xf0)>>4 | (DE.B.B1&0x0f)<<4; + AF.B.B0 = ZeroTable[DE.B.B1]; + break; + case 0x33: + // SWAP E + DE.B.B0 = (DE.B.B0&0xf0)>>4 | (DE.B.B0&0x0f)<<4; + AF.B.B0 = ZeroTable[DE.B.B0]; + break; + case 0x34: + // SWAP H + HL.B.B1 = (HL.B.B1&0xf0)>>4 | (HL.B.B1&0x0f)<<4; + AF.B.B0 = ZeroTable[HL.B.B1]; + break; + case 0x35: + // SWAP L + HL.B.B0 = (HL.B.B0&0xf0)>>4 | (HL.B.B0&0x0f)<<4; + AF.B.B0 = ZeroTable[HL.B.B0]; + break; + case 0x36: + // SWAP (HL) + tempValue=gbReadMemory(HL.W); + tempValue = (tempValue&0xf0)>>4 | (tempValue&0x0f)<<4; + AF.B.B0 = ZeroTable[tempValue]; + gbWriteMemory(HL.W,tempValue); + break; + case 0x37: + // SWAP A + AF.B.B1 = (AF.B.B1&0xf0)>>4 | (AF.B.B1&0x0f)<<4; + AF.B.B0 = ZeroTable[AF.B.B1]; + break; + case 0x38: + // SRL B + AF.B.B0=(BC.B.B1&0x01)?C_FLAG:0; + BC.B.B1>>=1; + AF.B.B0|=ZeroTable[BC.B.B1]; + break; + case 0x39: + // SRL C + AF.B.B0=(BC.B.B0&0x01)?C_FLAG:0; + BC.B.B0>>=1; + AF.B.B0|=ZeroTable[BC.B.B0]; + break; + case 0x3a: + // SRL D + AF.B.B0=(DE.B.B1&0x01)?C_FLAG:0; + DE.B.B1>>=1; + AF.B.B0|=ZeroTable[DE.B.B1]; + break; + case 0x3b: + // SRL E + AF.B.B0=(DE.B.B0&0x01)?C_FLAG:0; + DE.B.B0>>=1; + AF.B.B0|=ZeroTable[DE.B.B0]; + break; + case 0x3c: + // SRL H + AF.B.B0=(HL.B.B1&0x01)?C_FLAG:0; + HL.B.B1>>=1; + AF.B.B0|=ZeroTable[HL.B.B1]; + break; + case 0x3d: + // SRL L + AF.B.B0=(HL.B.B0&0x01)?C_FLAG:0; + HL.B.B0>>=1; + AF.B.B0|=ZeroTable[HL.B.B0]; + break; + case 0x3e: + // SRL (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(tempValue&0x01)?C_FLAG:0; + tempValue>>=1; + AF.B.B0|=ZeroTable[tempValue]; + gbWriteMemory(HL.W,tempValue); + break; + case 0x3f: + // SRL A + AF.B.B0=(AF.B.B1&0x01)?C_FLAG:0; + AF.B.B1>>=1; + AF.B.B0|=ZeroTable[AF.B.B1]; + break; + case 0x40: + // BIT 0,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<0)? 0:Z_FLAG); + break; + case 0x41: + // BIT 0,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<0)? 0:Z_FLAG); + break; + case 0x42: + // BIT 0,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<0)? 0:Z_FLAG); + break; + case 0x43: + // BIT 0,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<0)? 0:Z_FLAG); + break; + case 0x44: + // BIT 0,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<0)? 0:Z_FLAG); + break; + case 0x45: + // BIT 0,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<0)? 0:Z_FLAG); + break; + case 0x46: + // BIT 0,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<0)? 0:Z_FLAG); + break; + case 0x47: + // BIT 0,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<0)? 0:Z_FLAG); + break; + case 0x48: + // BIT 1,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<1)? 0:Z_FLAG); + break; + case 0x49: + // BIT 1,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<1)? 0:Z_FLAG); + break; + case 0x4a: + // BIT 1,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<1)? 0:Z_FLAG); + break; + case 0x4b: + // BIT 1,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<1)? 0:Z_FLAG); + break; + case 0x4c: + // BIT 1,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<1)? 0:Z_FLAG); + break; + case 0x4d: + // BIT 1,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<1)? 0:Z_FLAG); + break; + case 0x4e: + // BIT 1,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<1)? 0:Z_FLAG); + break; + case 0x4f: + // BIT 1,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<1)? 0:Z_FLAG); + break; + case 0x50: + // BIT 2,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<2)? 0:Z_FLAG); + break; + case 0x51: + // BIT 2,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<2)? 0:Z_FLAG); + break; + case 0x52: + // BIT 2,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<2)? 0:Z_FLAG); + break; + case 0x53: + // BIT 2,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<2)? 0:Z_FLAG); + break; + case 0x54: + // BIT 2,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<2)? 0:Z_FLAG); + break; + case 0x55: + // BIT 2,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<2)? 0:Z_FLAG); + break; + case 0x56: + // BIT 2,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<2)? 0:Z_FLAG); + break; + case 0x57: + // BIT 2,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<2)? 0:Z_FLAG); + break; + case 0x58: + // BIT 3,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<3)? 0:Z_FLAG); + break; + case 0x59: + // BIT 3,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<3)? 0:Z_FLAG); + break; + case 0x5a: + // BIT 3,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<3)? 0:Z_FLAG); + break; + case 0x5b: + // BIT 3,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<3)? 0:Z_FLAG); + break; + case 0x5c: + // BIT 3,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<3)? 0:Z_FLAG); + break; + case 0x5d: + // BIT 3,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<3)? 0:Z_FLAG); + break; + case 0x5e: + // BIT 3,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<3)? 0:Z_FLAG); + break; + case 0x5f: + // BIT 3,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<3)? 0:Z_FLAG); + break; + case 0x60: + // BIT 4,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<4)? 0:Z_FLAG); + break; + case 0x61: + // BIT 4,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<4)? 0:Z_FLAG); + break; + case 0x62: + // BIT 4,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<4)? 0:Z_FLAG); + break; + case 0x63: + // BIT 4,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<4)? 0:Z_FLAG); + break; + case 0x64: + // BIT 4,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<4)? 0:Z_FLAG); + break; + case 0x65: + // BIT 4,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<4)? 0:Z_FLAG); + break; + case 0x66: + // BIT 4,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<4)? 0:Z_FLAG); + break; + case 0x67: + // BIT 4,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<4)? 0:Z_FLAG); + break; + case 0x68: + // BIT 5,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<5)? 0:Z_FLAG); + break; + case 0x69: + // BIT 5,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<5)? 0:Z_FLAG); + break; + case 0x6a: + // BIT 5,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<5)? 0:Z_FLAG); + break; + case 0x6b: + // BIT 5,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<5)? 0:Z_FLAG); + break; + case 0x6c: + // BIT 5,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<5)? 0:Z_FLAG); + break; + case 0x6d: + // BIT 5,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<5)? 0:Z_FLAG); + break; + case 0x6e: + // BIT 5,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<5)? 0:Z_FLAG); + break; + case 0x6f: + // BIT 5,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<5)? 0:Z_FLAG); + break; + case 0x70: + // BIT 6,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<6)? 0:Z_FLAG); + break; + case 0x71: + // BIT 6,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<6)? 0:Z_FLAG); + break; + case 0x72: + // BIT 6,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<6)? 0:Z_FLAG); + break; + case 0x73: + // BIT 6,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<6)? 0:Z_FLAG); + break; + case 0x74: + // BIT 6,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<6)? 0:Z_FLAG); + break; + case 0x75: + // BIT 6,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<6)? 0:Z_FLAG); + break; + case 0x76: + // BIT 6,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<6)? 0:Z_FLAG); + break; + case 0x77: + // BIT 6,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<6)? 0:Z_FLAG); + break; + case 0x78: + // BIT 7,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<7)? 0:Z_FLAG); + break; + case 0x79: + // BIT 7,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<7)? 0:Z_FLAG); + break; + case 0x7a: + // BIT 7,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<7)? 0:Z_FLAG); + break; + case 0x7b: + // BIT 7,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<7)? 0:Z_FLAG); + break; + case 0x7c: + // BIT 7,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<7)? 0:Z_FLAG); + break; + case 0x7d: + // BIT 7,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<7)? 0:Z_FLAG); + break; + case 0x7e: + // BIT 7,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<7)? 0:Z_FLAG); + break; + case 0x7f: + // BIT 7,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<7)? 0:Z_FLAG); + break; + case 0x80: + // RES 0,B + BC.B.B1&=~(1<<0); + break; + case 0x81: + // RES 0,C + BC.B.B0&=~(1<<0); + break; + case 0x82: + // RES 0,D + DE.B.B1&=~(1<<0); + break; + case 0x83: + // RES 0,E + DE.B.B0&=~(1<<0); + break; + case 0x84: + // RES 0,H + HL.B.B1&=~(1<<0); + break; + case 0x85: + // RES 0,L + HL.B.B0&=~(1<<0); + break; + case 0x86: + // RES 0,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<0); + gbWriteMemory(HL.W,tempValue); + break; + case 0x87: + // RES 0,A + AF.B.B1&=~(1<<0); + break; + case 0x88: + // RES 1,B + BC.B.B1&=~(1<<1); + break; + case 0x89: + // RES 1,C + BC.B.B0&=~(1<<1); + break; + case 0x8a: + // RES 1,D + DE.B.B1&=~(1<<1); + break; + case 0x8b: + // RES 1,E + DE.B.B0&=~(1<<1); + break; + case 0x8c: + // RES 1,H + HL.B.B1&=~(1<<1); + break; + case 0x8d: + // RES 1,L + HL.B.B0&=~(1<<1); + break; + case 0x8e: + // RES 1,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<1); + gbWriteMemory(HL.W,tempValue); + break; + case 0x8f: + // RES 1,A + AF.B.B1&=~(1<<1); + break; + case 0x90: + // RES 2,B + BC.B.B1&=~(1<<2); + break; + case 0x91: + // RES 2,C + BC.B.B0&=~(1<<2); + break; + case 0x92: + // RES 2,D + DE.B.B1&=~(1<<2); + break; + case 0x93: + // RES 2,E + DE.B.B0&=~(1<<2); + break; + case 0x94: + // RES 2,H + HL.B.B1&=~(1<<2); + break; + case 0x95: + // RES 2,L + HL.B.B0&=~(1<<2); + break; + case 0x96: + // RES 2,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<2); + gbWriteMemory(HL.W,tempValue); + break; + case 0x97: + // RES 2,A + AF.B.B1&=~(1<<2); + break; + case 0x98: + // RES 3,B + BC.B.B1&=~(1<<3); + break; + case 0x99: + // RES 3,C + BC.B.B0&=~(1<<3); + break; + case 0x9a: + // RES 3,D + DE.B.B1&=~(1<<3); + break; + case 0x9b: + // RES 3,E + DE.B.B0&=~(1<<3); + break; + case 0x9c: + // RES 3,H + HL.B.B1&=~(1<<3); + break; + case 0x9d: + // RES 3,L + HL.B.B0&=~(1<<3); + break; + case 0x9e: + // RES 3,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<3); + gbWriteMemory(HL.W,tempValue); + break; + case 0x9f: + // RES 3,A + AF.B.B1&=~(1<<3); + break; + case 0xa0: + // RES 4,B + BC.B.B1&=~(1<<4); + break; + case 0xa1: + // RES 4,C + BC.B.B0&=~(1<<4); + break; + case 0xa2: + // RES 4,D + DE.B.B1&=~(1<<4); + break; + case 0xa3: + // RES 4,E + DE.B.B0&=~(1<<4); + break; + case 0xa4: + // RES 4,H + HL.B.B1&=~(1<<4); + break; + case 0xa5: + // RES 4,L + HL.B.B0&=~(1<<4); + break; + case 0xa6: + // RES 4,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<4); + gbWriteMemory(HL.W,tempValue); + break; + case 0xa7: + // RES 4,A + AF.B.B1&=~(1<<4); + break; + case 0xa8: + // RES 5,B + BC.B.B1&=~(1<<5); + break; + case 0xa9: + // RES 5,C + BC.B.B0&=~(1<<5); + break; + case 0xaa: + // RES 5,D + DE.B.B1&=~(1<<5); + break; + case 0xab: + // RES 5,E + DE.B.B0&=~(1<<5); + break; + case 0xac: + // RES 5,H + HL.B.B1&=~(1<<5); + break; + case 0xad: + // RES 5,L + HL.B.B0&=~(1<<5); + break; + case 0xae: + // RES 5,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<5); + gbWriteMemory(HL.W,tempValue); + break; + case 0xaf: + // RES 5,A + AF.B.B1&=~(1<<5); + break; + case 0xb0: + // RES 6,B + BC.B.B1&=~(1<<6); + break; + case 0xb1: + // RES 6,C + BC.B.B0&=~(1<<6); + break; + case 0xb2: + // RES 6,D + DE.B.B1&=~(1<<6); + break; + case 0xb3: + // RES 6,E + DE.B.B0&=~(1<<6); + break; + case 0xb4: + // RES 6,H + HL.B.B1&=~(1<<6); + break; + case 0xb5: + // RES 6,L + HL.B.B0&=~(1<<6); + break; + case 0xb6: + // RES 6,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<6); + gbWriteMemory(HL.W,tempValue); + break; + case 0xb7: + // RES 6,A + AF.B.B1&=~(1<<6); + break; + case 0xb8: + // RES 7,B + BC.B.B1&=~(1<<7); + break; + case 0xb9: + // RES 7,C + BC.B.B0&=~(1<<7); + break; + case 0xba: + // RES 7,D + DE.B.B1&=~(1<<7); + break; + case 0xbb: + // RES 7,E + DE.B.B0&=~(1<<7); + break; + case 0xbc: + // RES 7,H + HL.B.B1&=~(1<<7); + break; + case 0xbd: + // RES 7,L + HL.B.B0&=~(1<<7); + break; + case 0xbe: + // RES 7,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<7); + gbWriteMemory(HL.W,tempValue); + break; + case 0xbf: + // RES 7,A + AF.B.B1&=~(1<<7); + break; + case 0xc0: + // SET 0,B + BC.B.B1|=1<<0; + break; + case 0xc1: + // SET 0,C + BC.B.B0|=1<<0; + break; + case 0xc2: + // SET 0,D + DE.B.B1|=1<<0; + break; + case 0xc3: + // SET 0,E + DE.B.B0|=1<<0; + break; + case 0xc4: + // SET 0,H + HL.B.B1|=1<<0; + break; + case 0xc5: + // SET 0,L + HL.B.B0|=1<<0; + break; + case 0xc6: + // SET 0,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<0; + gbWriteMemory(HL.W,tempValue); + break; + case 0xc7: + // SET 0,A + AF.B.B1|=1<<0; + break; + case 0xc8: + // SET 1,B + BC.B.B1|=1<<1; + break; + case 0xc9: + // SET 1,C + BC.B.B0|=1<<1; + break; + case 0xca: + // SET 1,D + DE.B.B1|=1<<1; + break; + case 0xcb: + // SET 1,E + DE.B.B0|=1<<1; + break; + case 0xcc: + // SET 1,H + HL.B.B1|=1<<1; + break; + case 0xcd: + // SET 1,L + HL.B.B0|=1<<1; + break; + case 0xce: + // SET 1,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<1; + gbWriteMemory(HL.W,tempValue); + break; + case 0xcf: + // SET 1,A + AF.B.B1|=1<<1; + break; + case 0xd0: + // SET 2,B + BC.B.B1|=1<<2; + break; + case 0xd1: + // SET 2,C + BC.B.B0|=1<<2; + break; + case 0xd2: + // SET 2,D + DE.B.B1|=1<<2; + break; + case 0xd3: + // SET 2,E + DE.B.B0|=1<<2; + break; + case 0xd4: + // SET 2,H + HL.B.B1|=1<<2; + break; + case 0xd5: + // SET 2,L + HL.B.B0|=1<<2; + break; + case 0xd6: + // SET 2,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<2; + gbWriteMemory(HL.W,tempValue); + break; + case 0xd7: + // SET 2,A + AF.B.B1|=1<<2; + break; + case 0xd8: + // SET 3,B + BC.B.B1|=1<<3; + break; + case 0xd9: + // SET 3,C + BC.B.B0|=1<<3; + break; + case 0xda: + // SET 3,D + DE.B.B1|=1<<3; + break; + case 0xdb: + // SET 3,E + DE.B.B0|=1<<3; + break; + case 0xdc: + // SET 3,H + HL.B.B1|=1<<3; + break; + case 0xdd: + // SET 3,L + HL.B.B0|=1<<3; + break; + case 0xde: + // SET 3,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<3; + gbWriteMemory(HL.W,tempValue); + break; + case 0xdf: + // SET 3,A + AF.B.B1|=1<<3; + break; + case 0xe0: + // SET 4,B + BC.B.B1|=1<<4; + break; + case 0xe1: + // SET 4,C + BC.B.B0|=1<<4; + break; + case 0xe2: + // SET 4,D + DE.B.B1|=1<<4; + break; + case 0xe3: + // SET 4,E + DE.B.B0|=1<<4; + break; + case 0xe4: + // SET 4,H + HL.B.B1|=1<<4; + break; + case 0xe5: + // SET 4,L + HL.B.B0|=1<<4; + break; + case 0xe6: + // SET 4,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<4; + gbWriteMemory(HL.W,tempValue); + break; + case 0xe7: + // SET 4,A + AF.B.B1|=1<<4; + break; + case 0xe8: + // SET 5,B + BC.B.B1|=1<<5; + break; + case 0xe9: + // SET 5,C + BC.B.B0|=1<<5; + break; + case 0xea: + // SET 5,D + DE.B.B1|=1<<5; + break; + case 0xeb: + // SET 5,E + DE.B.B0|=1<<5; + break; + case 0xec: + // SET 5,H + HL.B.B1|=1<<5; + break; + case 0xed: + // SET 5,L + HL.B.B0|=1<<5; + break; + case 0xee: + // SET 5,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<5; + gbWriteMemory(HL.W,tempValue); + break; + case 0xef: + // SET 5,A + AF.B.B1|=1<<5; + break; + case 0xf0: + // SET 6,B + BC.B.B1|=1<<6; + break; + case 0xf1: + // SET 6,C + BC.B.B0|=1<<6; + break; + case 0xf2: + // SET 6,D + DE.B.B1|=1<<6; + break; + case 0xf3: + // SET 6,E + DE.B.B0|=1<<6; + break; + case 0xf4: + // SET 6,H + HL.B.B1|=1<<6; + break; + case 0xf5: + // SET 6,L + HL.B.B0|=1<<6; + break; + case 0xf6: + // SET 6,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<6; + gbWriteMemory(HL.W,tempValue); + break; + case 0xf7: + // SET 6,A + AF.B.B1|=1<<6; + break; + case 0xf8: + // SET 7,B + BC.B.B1|=1<<7; + break; + case 0xf9: + // SET 7,C + BC.B.B0|=1<<7; + break; + case 0xfa: + // SET 7,D + DE.B.B1|=1<<7; + break; + case 0xfb: + // SET 7,E + DE.B.B0|=1<<7; + break; + case 0xfc: + // SET 7,H + HL.B.B1|=1<<7; + break; + case 0xfd: + // SET 7,L + HL.B.B0|=1<<7; + break; + case 0xfe: + // SET 7,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<7; + gbWriteMemory(HL.W,tempValue); + break; + case 0xff: + // SET 7,A + AF.B.B1|=1<<7; + break; + default: + if (gbSystemMessage == false) + { + systemMessage(0, N_("Unknown opcode %02x at %04x"), + gbReadOpcode(PC.W-1),PC.W-1); + gbSystemMessage =true; + } + return; diff --git a/src/dmg/gbDis.cpp b/src/dmg/gbDis.cpp index 055a5a27..4a589ae5 100644 --- a/src/dmg/gbDis.cpp +++ b/src/dmg/gbDis.cpp @@ -1,249 +1,249 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include -#include - -#include "../System.h" -#include "gbGlobals.h" - -typedef struct { - u8 mask; - u8 value; - const char *mnen; -} GBOPCODE; - -#define GB_READ(x) gbMemoryMap[(x)>>12][(x)&0xfff] - -static const char *registers[] = - { "B", "C", "D", "E", "H", "L", "(HL)", "A" }; - -static const char *registers16[] = - { "BC", "DE", "HL", "SP", // for some operations - "BC", "DE", "HL", "AF" }; // for push/pop - -static const char *cond[] = - { "NZ", "Z", "NC", "C" }; - -static char hexDigits[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' -}; - -static GBOPCODE opcodes[] = { - { 0xff, 0x00, "NOP" }, - { 0xcf, 0x01, "LD %R4,%W" }, - { 0xff, 0x02, "LD (BC),A" }, - { 0xcf, 0x03, "INC %R4" }, - { 0xc7, 0x04, "INC %r3" }, - { 0xc7, 0x05, "DEC %r3" }, - { 0xc7, 0x06, "LD %r3,%B" }, - { 0xff, 0x07, "RLCA" }, - { 0xff, 0x08, "LD (%W),SP" }, - { 0xcf, 0x09, "ADD HL,%R4" }, - { 0xff, 0x0a, "LD A,(BC)" }, - { 0xcf, 0x0b, "DEC %R4" }, - { 0xff, 0x0f, "RRCA" }, - { 0xff, 0x10, "STOP" }, - { 0xff, 0x12, "LD (DE),A" }, - { 0xff, 0x17, "RLA" }, - { 0xff, 0x18, "JR %d" }, - { 0xff, 0x1a, "LD A,(DE)" }, - { 0xff, 0x1f, "RRA" }, - { 0xe7, 0x20, "JR %c3,%d" }, - { 0xff, 0x22, "LDI (HL),A" }, - { 0xff, 0x27, "DAA" }, - { 0xff, 0x2a, "LDI A,(HL)" }, - { 0xff, 0x2f, "CPL" }, - { 0xff, 0x32, "LDD (HL),A" }, - { 0xff, 0x37, "SCF" }, - { 0xff, 0x3a, "LDD A,(HL)" }, - { 0xff, 0x3f, "CCF" }, - { 0xff, 0x76, "HALT" }, - { 0xc0, 0x40, "LD %r3,%r0" }, - { 0xf8, 0x80, "ADD A,%r0" }, - { 0xf8, 0x88, "ADC A,%r0" }, - { 0xf8, 0x90, "SUB %r0" }, - { 0xf8, 0x98, "SBC A,%r0" }, - { 0xf8, 0xa0, "AND %r0" }, - { 0xf8, 0xa8, "XOR %r0" }, - { 0xf8, 0xb0, "OR %r0" }, - { 0xf8, 0xb8, "CP %r0" }, - { 0xe7, 0xc0, "RET %c3" }, - { 0xcf, 0xc1, "POP %t4" }, - { 0xe7, 0xc2, "JP %c3,%W" }, - { 0xff, 0xc3, "JP %W" }, - { 0xe7, 0xc4, "CALL %c3,%W" }, - { 0xcf, 0xc5, "PUSH %t4" }, - { 0xff, 0xc6, "ADD A,%B" }, - { 0xc7, 0xc7, "RST %P" }, - { 0xff, 0xc9, "RET" }, - { 0xff, 0xcd, "CALL %W" }, - { 0xff, 0xce, "ADC %B" }, - { 0xff, 0xd6, "SUB %B" }, - { 0xff, 0xd9, "RETI" }, - { 0xff, 0xde, "SBC %B" }, - { 0xff, 0xe0, "LD (FF%B),A" }, - { 0xff, 0xe2, "LD (FF00h+C),A" }, - { 0xff, 0xe6, "AND %B" }, - { 0xff, 0xe8, "ADD SP,%D" }, - { 0xff, 0xe9, "LD PC,HL" }, - { 0xff, 0xea, "LD (%W),A" }, - { 0xff, 0xee, "XOR %B" }, - { 0xff, 0xf0, "LD A,(FF%B)" }, - { 0xff, 0xf2, "LD A,(FF00h+C)" }, - { 0xff, 0xf3, "DI" }, - { 0xff, 0xf6, "OR %B" }, - { 0xff, 0xf8, "LD HL,SP%D" }, - { 0xff, 0xf9, "LD SP,HL" }, - { 0xff, 0xfa, "LD A,(%W)" }, - { 0xff, 0xfb, "EI" }, - { 0xff, 0xfe, "CP %B" }, - { 0x00, 0x00, "DB %B" } -}; - -static GBOPCODE cbOpcodes[] = { - { 0xf8, 0x00, "RLC %r0" }, - { 0xf8, 0x08, "RRC %r0" }, - { 0xf8, 0x10, "RL %r0" }, - { 0xf8, 0x18, "RR %r0" }, - { 0xf8, 0x20, "SLA %r0" }, - { 0xf8, 0x28, "SRA %r0" }, - { 0xf8, 0x30, "SWAP %r0" }, - { 0xf8, 0x38, "SRL %r0" }, - { 0xc0, 0x40, "BIT %b,%r0" }, - { 0xc0, 0x80, "RES %b,%r0" }, - { 0xc0, 0xc0, "SET %b,%r0" }, - { 0x00, 0x00, "DB CBh,%B" } -}; - -static char *addHex(char *p, u8 value) -{ - *p++ = hexDigits[value >> 4]; - *p++ = hexDigits[value & 15]; - return p; -} - -static char *addHex16(char *p, u16 value) -{ - p = addHex(p, value>>8); - return addHex(p, value & 255); -} - -static char *addStr(char *p, const char *s) -{ - while(*s) { - *p++ = *s++; - } - return p; -} - -int gbDis(char *buffer, u16 address) -{ - char *p = buffer; - int instr = 1; - u16 addr = address; - sprintf(p, "%04x ", address); - p += 12; - - u8 opcode = GB_READ(address); - address++; - const char *mnen; - GBOPCODE *op; - if(opcode == 0xcb) { - opcode = GB_READ(address); - address++; - instr++; - op = cbOpcodes; - } else { - op = opcodes; - } - while(op->value != (opcode & op->mask)) op++; - mnen = op->mnen; - - u8 b0, b1; - s8 disp; - int shift; - - while(*mnen) { - if(*mnen == '%') { - mnen++; - switch(*mnen++) { - case 'W': - b0 = GB_READ(address); - address++; - b1 = GB_READ(address); - address++; - p = addHex16(p, b0|b1<<8); - instr += 2; - *p++ = 'h'; - break; - case 'B': - p = addHex(p, GB_READ(address)); - *p++ = 'h'; - address++; - instr++; - break; - case 'D': - disp = GB_READ(address); - if(disp >= 0) - *p++ = '+'; - p += sprintf(p, "%d", disp); - instr++; - break; - case 'd': - disp = GB_READ(address); - address++; - p = addHex16(p, address+disp); - *p++ = 'h'; - instr++; - break; - case 'b': - // kind of a hack, but it works :-) - *p++ = hexDigits[(opcode >> 3) & 7]; - break; - case 'r': - shift = *mnen++ - '0'; - p = addStr(p, registers[(opcode >> shift) & 7]); - break; - case 'R': - shift = *mnen++ - '0'; - p = addStr(p, registers16[(opcode >> shift) & 3]); - break; - case 't': - shift = *mnen++ - '0'; - p = addStr(p, registers16[4+((opcode >> shift) & 3)]); - break; - case 'P': - p = addHex(p, ((opcode >> 3) & 7) * 8); - break; - case 'c': - shift = *mnen++ - '0'; - p = addStr(p, cond[(opcode >> shift) & 3]); - break; - } - } else - *p++ = *mnen++; - } - for(int i = 0; i < instr; i++) { - u16 a = addr + i; - addHex(buffer+5+i*2, GB_READ(a)); - } - *p = 0; - return instr; -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include + +#include "../System.h" +#include "gbGlobals.h" + +typedef struct { + u8 mask; + u8 value; + const char *mnen; +} GBOPCODE; + +#define GB_READ(x) gbMemoryMap[(x)>>12][(x)&0xfff] + +static const char *registers[] = + { "B", "C", "D", "E", "H", "L", "(HL)", "A" }; + +static const char *registers16[] = + { "BC", "DE", "HL", "SP", // for some operations + "BC", "DE", "HL", "AF" }; // for push/pop + +static const char *cond[] = + { "NZ", "Z", "NC", "C" }; + +static char hexDigits[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + +static GBOPCODE opcodes[] = { + { 0xff, 0x00, "NOP" }, + { 0xcf, 0x01, "LD %R4,%W" }, + { 0xff, 0x02, "LD (BC),A" }, + { 0xcf, 0x03, "INC %R4" }, + { 0xc7, 0x04, "INC %r3" }, + { 0xc7, 0x05, "DEC %r3" }, + { 0xc7, 0x06, "LD %r3,%B" }, + { 0xff, 0x07, "RLCA" }, + { 0xff, 0x08, "LD (%W),SP" }, + { 0xcf, 0x09, "ADD HL,%R4" }, + { 0xff, 0x0a, "LD A,(BC)" }, + { 0xcf, 0x0b, "DEC %R4" }, + { 0xff, 0x0f, "RRCA" }, + { 0xff, 0x10, "STOP" }, + { 0xff, 0x12, "LD (DE),A" }, + { 0xff, 0x17, "RLA" }, + { 0xff, 0x18, "JR %d" }, + { 0xff, 0x1a, "LD A,(DE)" }, + { 0xff, 0x1f, "RRA" }, + { 0xe7, 0x20, "JR %c3,%d" }, + { 0xff, 0x22, "LDI (HL),A" }, + { 0xff, 0x27, "DAA" }, + { 0xff, 0x2a, "LDI A,(HL)" }, + { 0xff, 0x2f, "CPL" }, + { 0xff, 0x32, "LDD (HL),A" }, + { 0xff, 0x37, "SCF" }, + { 0xff, 0x3a, "LDD A,(HL)" }, + { 0xff, 0x3f, "CCF" }, + { 0xff, 0x76, "HALT" }, + { 0xc0, 0x40, "LD %r3,%r0" }, + { 0xf8, 0x80, "ADD A,%r0" }, + { 0xf8, 0x88, "ADC A,%r0" }, + { 0xf8, 0x90, "SUB %r0" }, + { 0xf8, 0x98, "SBC A,%r0" }, + { 0xf8, 0xa0, "AND %r0" }, + { 0xf8, 0xa8, "XOR %r0" }, + { 0xf8, 0xb0, "OR %r0" }, + { 0xf8, 0xb8, "CP %r0" }, + { 0xe7, 0xc0, "RET %c3" }, + { 0xcf, 0xc1, "POP %t4" }, + { 0xe7, 0xc2, "JP %c3,%W" }, + { 0xff, 0xc3, "JP %W" }, + { 0xe7, 0xc4, "CALL %c3,%W" }, + { 0xcf, 0xc5, "PUSH %t4" }, + { 0xff, 0xc6, "ADD A,%B" }, + { 0xc7, 0xc7, "RST %P" }, + { 0xff, 0xc9, "RET" }, + { 0xff, 0xcd, "CALL %W" }, + { 0xff, 0xce, "ADC %B" }, + { 0xff, 0xd6, "SUB %B" }, + { 0xff, 0xd9, "RETI" }, + { 0xff, 0xde, "SBC %B" }, + { 0xff, 0xe0, "LD (FF%B),A" }, + { 0xff, 0xe2, "LD (FF00h+C),A" }, + { 0xff, 0xe6, "AND %B" }, + { 0xff, 0xe8, "ADD SP,%D" }, + { 0xff, 0xe9, "LD PC,HL" }, + { 0xff, 0xea, "LD (%W),A" }, + { 0xff, 0xee, "XOR %B" }, + { 0xff, 0xf0, "LD A,(FF%B)" }, + { 0xff, 0xf2, "LD A,(FF00h+C)" }, + { 0xff, 0xf3, "DI" }, + { 0xff, 0xf6, "OR %B" }, + { 0xff, 0xf8, "LD HL,SP%D" }, + { 0xff, 0xf9, "LD SP,HL" }, + { 0xff, 0xfa, "LD A,(%W)" }, + { 0xff, 0xfb, "EI" }, + { 0xff, 0xfe, "CP %B" }, + { 0x00, 0x00, "DB %B" } +}; + +static GBOPCODE cbOpcodes[] = { + { 0xf8, 0x00, "RLC %r0" }, + { 0xf8, 0x08, "RRC %r0" }, + { 0xf8, 0x10, "RL %r0" }, + { 0xf8, 0x18, "RR %r0" }, + { 0xf8, 0x20, "SLA %r0" }, + { 0xf8, 0x28, "SRA %r0" }, + { 0xf8, 0x30, "SWAP %r0" }, + { 0xf8, 0x38, "SRL %r0" }, + { 0xc0, 0x40, "BIT %b,%r0" }, + { 0xc0, 0x80, "RES %b,%r0" }, + { 0xc0, 0xc0, "SET %b,%r0" }, + { 0x00, 0x00, "DB CBh,%B" } +}; + +static char *addHex(char *p, u8 value) +{ + *p++ = hexDigits[value >> 4]; + *p++ = hexDigits[value & 15]; + return p; +} + +static char *addHex16(char *p, u16 value) +{ + p = addHex(p, value>>8); + return addHex(p, value & 255); +} + +static char *addStr(char *p, const char *s) +{ + while(*s) { + *p++ = *s++; + } + return p; +} + +int gbDis(char *buffer, u16 address) +{ + char *p = buffer; + int instr = 1; + u16 addr = address; + sprintf(p, "%04x ", address); + p += 12; + + u8 opcode = GB_READ(address); + address++; + const char *mnen; + GBOPCODE *op; + if(opcode == 0xcb) { + opcode = GB_READ(address); + address++; + instr++; + op = cbOpcodes; + } else { + op = opcodes; + } + while(op->value != (opcode & op->mask)) op++; + mnen = op->mnen; + + u8 b0, b1; + s8 disp; + int shift; + + while(*mnen) { + if(*mnen == '%') { + mnen++; + switch(*mnen++) { + case 'W': + b0 = GB_READ(address); + address++; + b1 = GB_READ(address); + address++; + p = addHex16(p, b0|b1<<8); + instr += 2; + *p++ = 'h'; + break; + case 'B': + p = addHex(p, GB_READ(address)); + *p++ = 'h'; + address++; + instr++; + break; + case 'D': + disp = GB_READ(address); + if(disp >= 0) + *p++ = '+'; + p += sprintf(p, "%d", disp); + instr++; + break; + case 'd': + disp = GB_READ(address); + address++; + p = addHex16(p, address+disp); + *p++ = 'h'; + instr++; + break; + case 'b': + // kind of a hack, but it works :-) + *p++ = hexDigits[(opcode >> 3) & 7]; + break; + case 'r': + shift = *mnen++ - '0'; + p = addStr(p, registers[(opcode >> shift) & 7]); + break; + case 'R': + shift = *mnen++ - '0'; + p = addStr(p, registers16[(opcode >> shift) & 3]); + break; + case 't': + shift = *mnen++ - '0'; + p = addStr(p, registers16[4+((opcode >> shift) & 3)]); + break; + case 'P': + p = addHex(p, ((opcode >> 3) & 7) * 8); + break; + case 'c': + shift = *mnen++ - '0'; + p = addStr(p, cond[(opcode >> shift) & 3]); + break; + } + } else + *p++ = *mnen++; + } + for(int i = 0; i < instr; i++) { + u16 a = addr + i; + addHex(buffer+5+i*2, GB_READ(a)); + } + *p = 0; + return instr; +} diff --git a/src/dmg/gbGfx.cpp b/src/dmg/gbGfx.cpp index 59f36868..2fc20040 100644 --- a/src/dmg/gbGfx.cpp +++ b/src/dmg/gbGfx.cpp @@ -1,601 +1,601 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005-2006 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include - -#include "../agb/GBA.h" -#include "gbGlobals.h" -#include "gbSGB.h" - -u8 gbInvertTab[256] = { - 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0, - 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, - 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8, - 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, - 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4, - 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, - 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec, - 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, - 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2, - 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, - 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea, - 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, - 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6, - 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, - 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee, - 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, - 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1, - 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, - 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9, - 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, - 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5, - 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, - 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed, - 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, - 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3, - 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, - 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb, - 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, - 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7, - 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, - 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef, - 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff -}; - -u16 gbLineMix[160]; -u16 gbWindowColor[160]; -extern int inUseRegister_WY; - -void gbRenderLine() -{ - memset(gbLineMix, 0, sizeof(gbLineMix)); - u8 * bank0; - u8 * bank1; - if(gbCgbMode) { - bank0 = &gbVram[0x0000]; - bank1 = &gbVram[0x2000]; - } else { - bank0 = &gbMemory[0x8000]; - bank1 = NULL; - } - - int tile_map = 0x1800; - if((register_LCDC & 8) != 0) - tile_map = 0x1c00; - - int tile_pattern = 0x0800; - - if((register_LCDC & 16) != 0) - tile_pattern = 0x0000; - - int x = 0; - int y = register_LY; - - if(y >= 144) - return; - - int SpritesTicks = gbSpritesTicks[x]*(gbSpeed ? 2 : 4); - int sx = gbSCXLine[(gbSpeed ? 0 : 4)+SpritesTicks]; - int sy = gbSCYLine[(gbSpeed ? 11 : 5)+SpritesTicks]; - - sy+=y; - - sy &= 255; - - int tx = sx >> 3; - int ty = sy >> 3; - - int bx = 1 << (7 - (sx & 7)); - int by = sy & 7; - - int tile_map_line_y = tile_map + ty * 32; - - int tile_map_address = tile_map_line_y + tx; - - u8 attrs = 0; - if(bank1 != NULL) - attrs = bank1[tile_map_address]; - - u8 tile = bank0[tile_map_address]; - - tile_map_address++; - - if(!(register_LCDC & 0x10)) - tile ^= 0x80; - - int tile_pattern_address = tile_pattern + tile * 16 + by*2; - - if(register_LCDC & 0x80) { - if((register_LCDC & 0x01 || gbCgbMode) && (layerSettings & 0x0100)) { - while(x < 160) { - - - - u8 tile_a = 0; - u8 tile_b = 0; - - if(attrs & 0x40) { - tile_pattern_address = tile_pattern + tile * 16 + (7-by)*2; - } - - if(attrs & 0x08) { - tile_a = bank1[tile_pattern_address++]; - tile_b = bank1[tile_pattern_address]; - } else { - tile_a = bank0[tile_pattern_address++]; - tile_b = bank0[tile_pattern_address]; - } - - if(attrs & 0x20) { - tile_a = gbInvertTab[tile_a]; - tile_b = gbInvertTab[tile_b]; - } - - while(bx > 0) { - u8 c = (tile_a & bx) ? 1 : 0; - c += ((tile_b & bx) ? 2 : 0); - - gbLineBuffer[x] = c; // mark the gbLineBuffer color - - if(attrs & 0x80) - gbLineBuffer[x] |= 0x300; - - if(gbCgbMode) { - c = c + (attrs & 7)*4; - } else { - c = (gbBgpLine[x+(gbSpeed ? 5 : 11)+SpritesTicks]>>(c<<1)) &3; - if(gbSgbMode && !gbCgbMode) { - int dx = x >> 3; - int dy = y >> 3; - - int palette = gbSgbATF[dy * 20 + dx]; - - if(c == 0) - palette = 0; - - c = c + 4*palette; - } - } - gbLineMix[x] = gbColorOption ? gbColorFilter[gbPalette[c] & 0x7FFF] : - gbPalette[c] & 0x7FFF; - x++; - if(x >= 160) - break; - bx >>= 1; - } - - bx = 128; - - SpritesTicks = gbSpritesTicks[x]*(gbSpeed ? 2 : 4); - - sx = gbSCXLine[x+(gbSpeed ? 0 : 4)+SpritesTicks]; - - sy = gbSCYLine[x+(gbSpeed ? 11 : 5)+SpritesTicks]; - - - tx = ((sx+x)>>3) & 0x1f; - - sy+=y; - - sy &= 255; - - ty = sy >> 3; - - by = sy & 7; - - tile_pattern_address = tile_pattern + tile * 16 + by * 2; - - tile_map_line_y = tile_map + ty * 32; - - tile_map_address = tile_map_line_y + tx; - - if(bank1) - attrs = bank1[tile_map_line_y + tx]; - - tile = bank0[tile_map_line_y + tx]; - - if(!(register_LCDC & 0x10)) - tile ^= 0x80; - - tile_pattern_address = tile_pattern + tile * 16 + by * 2; - } - } else { - // Use gbBgp[0] instead of 0 (?) - // (this fixes white flashes on Last Bible II) - // Also added the gbColorOption (fixes Dracula Densetsu II color problems) - for(int i = 0; i < 160; i++) - { - u16 color = gbColorOption ? gbColorFilter[0x7FFF] : - 0x7FFF; - if (!gbCgbMode) - color = gbColorOption ? gbColorFilter[gbPalette[gbBgpLine[i+(gbSpeed ? 5 : 11)+gbSpritesTicks[i]*(gbSpeed ? 2 : 4)]&3] & 0x7FFF] : - gbPalette[gbBgpLine[i+(gbSpeed ? 5 : 11)+gbSpritesTicks[i]*(gbSpeed ? 2 : 4)]&3] & 0x7FFF; - gbLineMix[i] = color; - gbLineBuffer[i] = 0; - } - } - - // do the window display - // LCDC.0 also enables/disables the window in !gbCgbMode ?!?! - // (tested on real hardware) - // This fixes Last Bible II & Zankurou Musouken - if((register_LCDC & 0x01 || gbCgbMode) && (register_LCDC & 0x20) && - (layerSettings & 0x2000) && (gbWindowLine != -2)) { - int i = 0; - // Fix (accurate emulation) for most of the window display problems - // (ie. Zen - Intergalactic Ninja, Urusei Yatsura...). - if ((gbWindowLine == -1) || (gbWindowLine>144)) - { - inUseRegister_WY = oldRegister_WY; - if (register_LY>oldRegister_WY) - gbWindowLine = 146; - // for (i = 0; i<160; i++) - // gbWindowColor[i] = gbLineMix[i]; - } - - int wy = inUseRegister_WY; - - if(y >= inUseRegister_WY) { - - if (gbWindowLine == -1) - gbWindowLine = 0; - - int wx = register_WX; - int swx = 0; - wx -= 7; - - if( wx <= 159 && gbWindowLine <= 143) { - - tile_map = 0x1800; - - if((register_LCDC & 0x40) != 0) - tile_map = 0x1c00; - - - tx = 0; - ty = gbWindowLine >> 3; - - bx = 128; - by = gbWindowLine & 7; - - // Tries to emulate the 'window scrolling bug' when wx == 0 (ie. wx-7 == -7). - // Nothing close to perfect, but good enought for now... - if (wx == -7) - { - swx = 7-((gbSCXLine[0]-1) & 7); - bx >>= ((gbSCXLine[0]+((swx != 1) ? 1 : 0)) & 7); - if (swx == 1) - swx = 2; - - //bx >>= ((gbSCXLine[0]+(((swx>1) && (swx != 7)) ? 1 : 0)) & 7); - - if ((swx == 7)) - { - //wx = 0; - if ((gbWindowLine>0) || (wy == 0)) - swx = 0; - } - } - else - if(wx < 0) { - bx >>= (-wx); - wx = 0; - } - - tile_map_line_y = tile_map + ty * 32; - - tile_map_address = tile_map_line_y + tx; - - x = wx; - - tile = bank0[tile_map_address]; - u8 attrs = 0; - if(bank1) - attrs = bank1[tile_map_address]; - tile_map_address++; - - if((register_LCDC & 16) == 0) { - if(tile < 128) tile += 128; - else tile -= 128; - } - - tile_pattern_address = tile_pattern + tile * 16 + by*2; - - if (wx) - for (i = 0; i 0) { - u8 c = (tile_a & bx) != 0 ? 1 : 0; - c += ((tile_b & bx) != 0 ? 2 : 0); - - if (x>=0) - { - if(attrs & 0x80) - gbLineBuffer[x] = 0x300 + c; - else - gbLineBuffer[x] = 0x100 + c; - - if(gbCgbMode) { - c = c + (attrs & 7) * 4; - } else { - c = (gbBgpLine[x+(gbSpeed ? 5 : 11)+gbSpritesTicks[x]*(gbSpeed ? 2 : 4)]>>(c<<1)) &3; - if(gbSgbMode && !gbCgbMode) { - int dx = x >> 3; - int dy = y >> 3; - - int palette = gbSgbATF[dy * 20 + dx]; - - if(c == 0) - palette = 0; - - c = c + 4*palette; - } - } - gbLineMix[x] = gbColorOption ? gbColorFilter[gbPalette[c] & 0x7FFF] : - gbPalette[c] & 0x7FFF; - } - x++; - if(x >= 160) - break; - bx >>= 1; - } - tx++; - if(tx == 32) - tx = 0; - bx = 128; - tile = bank0[tile_map_line_y + tx]; - if(bank1) - attrs = bank1[tile_map_line_y + tx]; - - if((register_LCDC & 16) == 0) { - if(tile < 128) tile += 128; - else tile -= 128; - } - tile_pattern_address = tile_pattern + tile * 16 + by * 2; - } - - //for (i = swx; i<160; i++) - // gbLineMix[i] = gbWindowColor[i]; - gbWindowLine++; - } - } - } - else if (gbWindowLine == -2) - { - inUseRegister_WY = oldRegister_WY; - if (register_LY>oldRegister_WY) - gbWindowLine = 146; - else - gbWindowLine = 0; - } - } else { - u16 color = gbColorOption ? gbColorFilter[0x7FFF] : - 0x7FFF; - if (!gbCgbMode) - color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : - gbPalette[0] & 0x7FFF; - for(int i = 0; i < 160; i++) - { - gbLineMix[i] = color; - gbLineBuffer[i] = 0; - } - } -} - -void gbDrawSpriteTile(int tile, int x,int y,int t, int flags, - int size,int spriteNumber) -{ - u8 * bank0; - u8 * bank1; - if(gbCgbMode) { - if(register_VBK & 1) { - bank0 = &gbVram[0x0000]; - bank1 = &gbVram[0x2000]; - } else { - bank0 = &gbVram[0x0000]; - bank1 = &gbVram[0x2000]; - } - } else { - bank0 = &gbMemory[0x8000]; - bank1 = NULL; - } - - int init = 0x0000; - - for (int i = 0; i<4; i++) - { - gbObp0[i] = (gbObp0Line[x+11+gbSpritesTicks[x]*(gbSpeed ? 2 : 4)]>>(i<<1)) & 3; - gbObp1[i] = (gbObp1Line[x+11+gbSpritesTicks[x]*(gbSpeed ? 2 : 4)]>>(i<<1)) & 3; - } - u8 *pal = gbObp0; - - int flipx = (flags & 0x20); - int flipy = (flags & 0x40); - - if((flags & 0x10)) - pal = gbObp1; - - if(flipy) { - t = (size ? 15 : 7) - t; - } - - int prio = flags & 0x80; - - int address = init + tile * 16 + 2*t; - int a = 0; - int b = 0; - - if(gbCgbMode && (flags & 0x08)) { - a = bank1[address++]; - b = bank1[address++]; - } else { - a = bank0[address++]; - b = bank0[address++]; - } - - for(int xx = 0; xx < 8; xx++) { - u8 mask = 1 << (7-xx); - u8 c = 0; - if( (a & mask)) - c++; - if( (b & mask)) - c+=2; - - if(c==0) continue; - - int xxx = xx+x; - if(flipx) - xxx = (7-xx+x); - - if(xxx < 0 || xxx > 159) - continue; - - u16 color = gbLineBuffer[xxx]; - - // Fixes OAM-BG priority - if(prio && (register_LCDC & 1)) { - if(color < 0x200 && ((color & 0xFF) != 0)) - continue; - } - // Fixes OAM-BG priority for Moorhuhn 2 - if(color >= 0x300 && color != 0x300 && (register_LCDC & 1)) - continue; - else if(color >= 0x200 && color < 0x300) { - int sprite = color & 0xff; - - int spriteX = gbMemory[0xfe00 + 4 * sprite + 1] - 8; - - if(spriteX == x) { - if(sprite < spriteNumber) - continue; - } else { - if(gbCgbMode) { - if(sprite < spriteNumber) - continue; - } else { - // Fixes GB sprites priorities (was '< x + 8' before) - // ('A boy and his blob...' sprites' emulation is now correct) - if(spriteX < x) - continue; - } - } - } - - - gbLineBuffer[xxx] = 0x200 + spriteNumber; - - // make sure that sprites will work even in CGB mode - if(gbCgbMode) { - c = c + (flags & 0x07)*4 + 32; - } else { - c = pal[c]; - - if(gbSgbMode && !gbCgbMode) { - int dx = xxx >> 3; - int dy = y >> 3; - - int palette = gbSgbATF[dy * 20 + dx]; - - if(c == 0) - palette = 0; - - c = c + 4*palette; - } else { - c += 4; - } - } - - gbLineMix[xxx] = gbColorOption ? gbColorFilter[gbPalette[c] & 0x7FFF] : - gbPalette[c] & 0x7FFF; - } -} - -void gbDrawSprites(bool draw) -{ - int x = 0; - int y = 0; - int count = 0; - - int size = (register_LCDC & 4); - - if (!draw) - memset (gbSpritesTicks, 0, sizeof(gbSpritesTicks)); - - if(!(register_LCDC & 0x80)) - return; - - if((register_LCDC & 2) && (layerSettings & 0x1000)) { - int yc = register_LY; - - int address = 0xfe00; - for(int i = 0; i < 40; i++) { - y = gbMemory[address++]; - x = gbMemory[address++]; - int tile = gbMemory[address++]; - if(size) - tile &= 254; - int flags = gbMemory[address++]; - - if(x > 0 && y > 0 && x < 168 && y < 160) { - // check if sprite intersects current line - int t = yc -y + 16; - if((size && t >=0 && t < 16) || (!size && t >= 0 && t < 8)) { - if (draw) - gbDrawSpriteTile(tile,x-8,yc,t,flags,size,i); - else - { - for (int j = x-8; j<300; j++) - if (j>=0) - if (gbSpeed) - gbSpritesTicks[j] += 5; - else - gbSpritesTicks[j] += 2+(count&1); - - } - count++; - } - } - // sprite limit reached! - if(count >= 10) - break; - } - } - return; -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include + +#include "../agb/GBA.h" +#include "gbGlobals.h" +#include "gbSGB.h" + +u8 gbInvertTab[256] = { + 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0, + 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, + 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8, + 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, + 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4, + 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, + 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec, + 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, + 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2, + 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, + 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea, + 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, + 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6, + 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, + 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee, + 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, + 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1, + 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, + 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9, + 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, + 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5, + 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, + 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed, + 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, + 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3, + 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, + 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb, + 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, + 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7, + 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, + 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef, + 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff +}; + +u16 gbLineMix[160]; +u16 gbWindowColor[160]; +extern int inUseRegister_WY; + +void gbRenderLine() +{ + memset(gbLineMix, 0, sizeof(gbLineMix)); + u8 * bank0; + u8 * bank1; + if(gbCgbMode) { + bank0 = &gbVram[0x0000]; + bank1 = &gbVram[0x2000]; + } else { + bank0 = &gbMemory[0x8000]; + bank1 = NULL; + } + + int tile_map = 0x1800; + if((register_LCDC & 8) != 0) + tile_map = 0x1c00; + + int tile_pattern = 0x0800; + + if((register_LCDC & 16) != 0) + tile_pattern = 0x0000; + + int x = 0; + int y = register_LY; + + if(y >= 144) + return; + + int SpritesTicks = gbSpritesTicks[x]*(gbSpeed ? 2 : 4); + int sx = gbSCXLine[(gbSpeed ? 0 : 4)+SpritesTicks]; + int sy = gbSCYLine[(gbSpeed ? 11 : 5)+SpritesTicks]; + + sy+=y; + + sy &= 255; + + int tx = sx >> 3; + int ty = sy >> 3; + + int bx = 1 << (7 - (sx & 7)); + int by = sy & 7; + + int tile_map_line_y = tile_map + ty * 32; + + int tile_map_address = tile_map_line_y + tx; + + u8 attrs = 0; + if(bank1 != NULL) + attrs = bank1[tile_map_address]; + + u8 tile = bank0[tile_map_address]; + + tile_map_address++; + + if(!(register_LCDC & 0x10)) + tile ^= 0x80; + + int tile_pattern_address = tile_pattern + tile * 16 + by*2; + + if(register_LCDC & 0x80) { + if((register_LCDC & 0x01 || gbCgbMode) && (layerSettings & 0x0100)) { + while(x < 160) { + + + + u8 tile_a = 0; + u8 tile_b = 0; + + if(attrs & 0x40) { + tile_pattern_address = tile_pattern + tile * 16 + (7-by)*2; + } + + if(attrs & 0x08) { + tile_a = bank1[tile_pattern_address++]; + tile_b = bank1[tile_pattern_address]; + } else { + tile_a = bank0[tile_pattern_address++]; + tile_b = bank0[tile_pattern_address]; + } + + if(attrs & 0x20) { + tile_a = gbInvertTab[tile_a]; + tile_b = gbInvertTab[tile_b]; + } + + while(bx > 0) { + u8 c = (tile_a & bx) ? 1 : 0; + c += ((tile_b & bx) ? 2 : 0); + + gbLineBuffer[x] = c; // mark the gbLineBuffer color + + if(attrs & 0x80) + gbLineBuffer[x] |= 0x300; + + if(gbCgbMode) { + c = c + (attrs & 7)*4; + } else { + c = (gbBgpLine[x+(gbSpeed ? 5 : 11)+SpritesTicks]>>(c<<1)) &3; + if(gbSgbMode && !gbCgbMode) { + int dx = x >> 3; + int dy = y >> 3; + + int palette = gbSgbATF[dy * 20 + dx]; + + if(c == 0) + palette = 0; + + c = c + 4*palette; + } + } + gbLineMix[x] = gbColorOption ? gbColorFilter[gbPalette[c] & 0x7FFF] : + gbPalette[c] & 0x7FFF; + x++; + if(x >= 160) + break; + bx >>= 1; + } + + bx = 128; + + SpritesTicks = gbSpritesTicks[x]*(gbSpeed ? 2 : 4); + + sx = gbSCXLine[x+(gbSpeed ? 0 : 4)+SpritesTicks]; + + sy = gbSCYLine[x+(gbSpeed ? 11 : 5)+SpritesTicks]; + + + tx = ((sx+x)>>3) & 0x1f; + + sy+=y; + + sy &= 255; + + ty = sy >> 3; + + by = sy & 7; + + tile_pattern_address = tile_pattern + tile * 16 + by * 2; + + tile_map_line_y = tile_map + ty * 32; + + tile_map_address = tile_map_line_y + tx; + + if(bank1) + attrs = bank1[tile_map_line_y + tx]; + + tile = bank0[tile_map_line_y + tx]; + + if(!(register_LCDC & 0x10)) + tile ^= 0x80; + + tile_pattern_address = tile_pattern + tile * 16 + by * 2; + } + } else { + // Use gbBgp[0] instead of 0 (?) + // (this fixes white flashes on Last Bible II) + // Also added the gbColorOption (fixes Dracula Densetsu II color problems) + for(int i = 0; i < 160; i++) + { + u16 color = gbColorOption ? gbColorFilter[0x7FFF] : + 0x7FFF; + if (!gbCgbMode) + color = gbColorOption ? gbColorFilter[gbPalette[gbBgpLine[i+(gbSpeed ? 5 : 11)+gbSpritesTicks[i]*(gbSpeed ? 2 : 4)]&3] & 0x7FFF] : + gbPalette[gbBgpLine[i+(gbSpeed ? 5 : 11)+gbSpritesTicks[i]*(gbSpeed ? 2 : 4)]&3] & 0x7FFF; + gbLineMix[i] = color; + gbLineBuffer[i] = 0; + } + } + + // do the window display + // LCDC.0 also enables/disables the window in !gbCgbMode ?!?! + // (tested on real hardware) + // This fixes Last Bible II & Zankurou Musouken + if((register_LCDC & 0x01 || gbCgbMode) && (register_LCDC & 0x20) && + (layerSettings & 0x2000) && (gbWindowLine != -2)) { + int i = 0; + // Fix (accurate emulation) for most of the window display problems + // (ie. Zen - Intergalactic Ninja, Urusei Yatsura...). + if ((gbWindowLine == -1) || (gbWindowLine>144)) + { + inUseRegister_WY = oldRegister_WY; + if (register_LY>oldRegister_WY) + gbWindowLine = 146; + // for (i = 0; i<160; i++) + // gbWindowColor[i] = gbLineMix[i]; + } + + int wy = inUseRegister_WY; + + if(y >= inUseRegister_WY) { + + if (gbWindowLine == -1) + gbWindowLine = 0; + + int wx = register_WX; + int swx = 0; + wx -= 7; + + if( wx <= 159 && gbWindowLine <= 143) { + + tile_map = 0x1800; + + if((register_LCDC & 0x40) != 0) + tile_map = 0x1c00; + + + tx = 0; + ty = gbWindowLine >> 3; + + bx = 128; + by = gbWindowLine & 7; + + // Tries to emulate the 'window scrolling bug' when wx == 0 (ie. wx-7 == -7). + // Nothing close to perfect, but good enought for now... + if (wx == -7) + { + swx = 7-((gbSCXLine[0]-1) & 7); + bx >>= ((gbSCXLine[0]+((swx != 1) ? 1 : 0)) & 7); + if (swx == 1) + swx = 2; + + //bx >>= ((gbSCXLine[0]+(((swx>1) && (swx != 7)) ? 1 : 0)) & 7); + + if ((swx == 7)) + { + //wx = 0; + if ((gbWindowLine>0) || (wy == 0)) + swx = 0; + } + } + else + if(wx < 0) { + bx >>= (-wx); + wx = 0; + } + + tile_map_line_y = tile_map + ty * 32; + + tile_map_address = tile_map_line_y + tx; + + x = wx; + + tile = bank0[tile_map_address]; + u8 attrs = 0; + if(bank1) + attrs = bank1[tile_map_address]; + tile_map_address++; + + if((register_LCDC & 16) == 0) { + if(tile < 128) tile += 128; + else tile -= 128; + } + + tile_pattern_address = tile_pattern + tile * 16 + by*2; + + if (wx) + for (i = 0; i 0) { + u8 c = (tile_a & bx) != 0 ? 1 : 0; + c += ((tile_b & bx) != 0 ? 2 : 0); + + if (x>=0) + { + if(attrs & 0x80) + gbLineBuffer[x] = 0x300 + c; + else + gbLineBuffer[x] = 0x100 + c; + + if(gbCgbMode) { + c = c + (attrs & 7) * 4; + } else { + c = (gbBgpLine[x+(gbSpeed ? 5 : 11)+gbSpritesTicks[x]*(gbSpeed ? 2 : 4)]>>(c<<1)) &3; + if(gbSgbMode && !gbCgbMode) { + int dx = x >> 3; + int dy = y >> 3; + + int palette = gbSgbATF[dy * 20 + dx]; + + if(c == 0) + palette = 0; + + c = c + 4*palette; + } + } + gbLineMix[x] = gbColorOption ? gbColorFilter[gbPalette[c] & 0x7FFF] : + gbPalette[c] & 0x7FFF; + } + x++; + if(x >= 160) + break; + bx >>= 1; + } + tx++; + if(tx == 32) + tx = 0; + bx = 128; + tile = bank0[tile_map_line_y + tx]; + if(bank1) + attrs = bank1[tile_map_line_y + tx]; + + if((register_LCDC & 16) == 0) { + if(tile < 128) tile += 128; + else tile -= 128; + } + tile_pattern_address = tile_pattern + tile * 16 + by * 2; + } + + //for (i = swx; i<160; i++) + // gbLineMix[i] = gbWindowColor[i]; + gbWindowLine++; + } + } + } + else if (gbWindowLine == -2) + { + inUseRegister_WY = oldRegister_WY; + if (register_LY>oldRegister_WY) + gbWindowLine = 146; + else + gbWindowLine = 0; + } + } else { + u16 color = gbColorOption ? gbColorFilter[0x7FFF] : + 0x7FFF; + if (!gbCgbMode) + color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : + gbPalette[0] & 0x7FFF; + for(int i = 0; i < 160; i++) + { + gbLineMix[i] = color; + gbLineBuffer[i] = 0; + } + } +} + +void gbDrawSpriteTile(int tile, int x,int y,int t, int flags, + int size,int spriteNumber) +{ + u8 * bank0; + u8 * bank1; + if(gbCgbMode) { + if(register_VBK & 1) { + bank0 = &gbVram[0x0000]; + bank1 = &gbVram[0x2000]; + } else { + bank0 = &gbVram[0x0000]; + bank1 = &gbVram[0x2000]; + } + } else { + bank0 = &gbMemory[0x8000]; + bank1 = NULL; + } + + int init = 0x0000; + + for (int i = 0; i<4; i++) + { + gbObp0[i] = (gbObp0Line[x+11+gbSpritesTicks[x]*(gbSpeed ? 2 : 4)]>>(i<<1)) & 3; + gbObp1[i] = (gbObp1Line[x+11+gbSpritesTicks[x]*(gbSpeed ? 2 : 4)]>>(i<<1)) & 3; + } + u8 *pal = gbObp0; + + int flipx = (flags & 0x20); + int flipy = (flags & 0x40); + + if((flags & 0x10)) + pal = gbObp1; + + if(flipy) { + t = (size ? 15 : 7) - t; + } + + int prio = flags & 0x80; + + int address = init + tile * 16 + 2*t; + int a = 0; + int b = 0; + + if(gbCgbMode && (flags & 0x08)) { + a = bank1[address++]; + b = bank1[address++]; + } else { + a = bank0[address++]; + b = bank0[address++]; + } + + for(int xx = 0; xx < 8; xx++) { + u8 mask = 1 << (7-xx); + u8 c = 0; + if( (a & mask)) + c++; + if( (b & mask)) + c+=2; + + if(c==0) continue; + + int xxx = xx+x; + if(flipx) + xxx = (7-xx+x); + + if(xxx < 0 || xxx > 159) + continue; + + u16 color = gbLineBuffer[xxx]; + + // Fixes OAM-BG priority + if(prio && (register_LCDC & 1)) { + if(color < 0x200 && ((color & 0xFF) != 0)) + continue; + } + // Fixes OAM-BG priority for Moorhuhn 2 + if(color >= 0x300 && color != 0x300 && (register_LCDC & 1)) + continue; + else if(color >= 0x200 && color < 0x300) { + int sprite = color & 0xff; + + int spriteX = gbMemory[0xfe00 + 4 * sprite + 1] - 8; + + if(spriteX == x) { + if(sprite < spriteNumber) + continue; + } else { + if(gbCgbMode) { + if(sprite < spriteNumber) + continue; + } else { + // Fixes GB sprites priorities (was '< x + 8' before) + // ('A boy and his blob...' sprites' emulation is now correct) + if(spriteX < x) + continue; + } + } + } + + + gbLineBuffer[xxx] = 0x200 + spriteNumber; + + // make sure that sprites will work even in CGB mode + if(gbCgbMode) { + c = c + (flags & 0x07)*4 + 32; + } else { + c = pal[c]; + + if(gbSgbMode && !gbCgbMode) { + int dx = xxx >> 3; + int dy = y >> 3; + + int palette = gbSgbATF[dy * 20 + dx]; + + if(c == 0) + palette = 0; + + c = c + 4*palette; + } else { + c += 4; + } + } + + gbLineMix[xxx] = gbColorOption ? gbColorFilter[gbPalette[c] & 0x7FFF] : + gbPalette[c] & 0x7FFF; + } +} + +void gbDrawSprites(bool draw) +{ + int x = 0; + int y = 0; + int count = 0; + + int size = (register_LCDC & 4); + + if (!draw) + memset (gbSpritesTicks, 0, sizeof(gbSpritesTicks)); + + if(!(register_LCDC & 0x80)) + return; + + if((register_LCDC & 2) && (layerSettings & 0x1000)) { + int yc = register_LY; + + int address = 0xfe00; + for(int i = 0; i < 40; i++) { + y = gbMemory[address++]; + x = gbMemory[address++]; + int tile = gbMemory[address++]; + if(size) + tile &= 254; + int flags = gbMemory[address++]; + + if(x > 0 && y > 0 && x < 168 && y < 160) { + // check if sprite intersects current line + int t = yc -y + 16; + if((size && t >=0 && t < 16) || (!size && t >= 0 && t < 8)) { + if (draw) + gbDrawSpriteTile(tile,x-8,yc,t,flags,size,i); + else + { + for (int j = x-8; j<300; j++) + if (j>=0) + if (gbSpeed) + gbSpritesTicks[j] += 5; + else + gbSpritesTicks[j] += 2+(count&1); + + } + count++; + } + } + // sprite limit reached! + if(count >= 10) + break; + } + } + return; +} diff --git a/src/dmg/gbGlobals.cpp b/src/dmg/gbGlobals.cpp index 0bbc3ecc..4cf27c84 100644 --- a/src/dmg/gbGlobals.cpp +++ b/src/dmg/gbGlobals.cpp @@ -1,57 +1,57 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005-2006 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include "../agb/GBA.h" - -u8 *gbMemoryMap[16]; - -int gbRomSizeMask = 0; -int gbRomSize = 0; -int gbRamSizeMask = 0; -int gbRamSize = 0; -int gbTAMA5ramSize = 0; - -u8 *gbMemory = NULL; -u8 *gbVram = NULL; -u8 *gbRom = NULL; -u8 *gbRam = NULL; -u8 *gbWram = NULL; -u16 *gbLineBuffer = NULL; -u8 *gbTAMA5ram = NULL; - -u16 gbPalette[128]; -u8 gbBgp[4] = { 0, 1, 2, 3}; -u8 gbObp0[4] = { 0, 1, 2, 3}; -u8 gbObp1[4] = { 0, 1, 2, 3}; -int gbWindowLine = -1; - -bool genericflashcardEnable = false; -int gbCgbMode = 0; - -u16 gbColorFilter[32768]; -int gbColorOption = 0; -int gbPaletteOption = 0; -int gbEmulatorType = 0; -int gbBorderOn = 1; -int gbBorderAutomatic = 0; -int gbBorderLineSkip = 160; -int gbBorderRowSkip = 0; -int gbBorderColumnSkip = 0; -int gbDmaTicks = 0; - -u8 (*gbSerialFunction)(u8) = NULL; +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "../agb/GBA.h" + +u8 *gbMemoryMap[16]; + +int gbRomSizeMask = 0; +int gbRomSize = 0; +int gbRamSizeMask = 0; +int gbRamSize = 0; +int gbTAMA5ramSize = 0; + +u8 *gbMemory = NULL; +u8 *gbVram = NULL; +u8 *gbRom = NULL; +u8 *gbRam = NULL; +u8 *gbWram = NULL; +u16 *gbLineBuffer = NULL; +u8 *gbTAMA5ram = NULL; + +u16 gbPalette[128]; +u8 gbBgp[4] = { 0, 1, 2, 3}; +u8 gbObp0[4] = { 0, 1, 2, 3}; +u8 gbObp1[4] = { 0, 1, 2, 3}; +int gbWindowLine = -1; + +bool genericflashcardEnable = false; +int gbCgbMode = 0; + +u16 gbColorFilter[32768]; +int gbColorOption = 0; +int gbPaletteOption = 0; +int gbEmulatorType = 0; +int gbBorderOn = 1; +int gbBorderAutomatic = 0; +int gbBorderLineSkip = 160; +int gbBorderRowSkip = 0; +int gbBorderColumnSkip = 0; +int gbDmaTicks = 0; + +u8 (*gbSerialFunction)(u8) = NULL; diff --git a/src/dmg/gbGlobals.h b/src/dmg/gbGlobals.h index 47e2e15e..d214d0d3 100644 --- a/src/dmg/gbGlobals.h +++ b/src/dmg/gbGlobals.h @@ -1,89 +1,89 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005-2006 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -extern int gbRomSizeMask; -extern int gbRomSize; -extern int gbRamSize; -extern int gbRamSizeMask; -extern int gbTAMA5ramSize; - -extern bool useBios; -extern bool skipBios; -extern u8 *bios; - -extern u8 *gbRom; -extern u8 *gbRam; -extern u8 *gbVram; -extern u8 *gbWram; -extern u8 *gbMemory; -extern u16 *gbLineBuffer; -extern u8 *gbTAMA5ram; - -extern u8 *gbMemoryMap[16]; - -extern int gbFrameSkip; -extern u16 gbColorFilter[32768]; -extern int gbColorOption; -extern int gbPaletteOption; -extern int gbEmulatorType; -extern int gbBorderOn; -extern int gbBorderAutomatic; -extern int gbCgbMode; -extern int gbSgbMode; -extern int gbWindowLine; -extern int gbSpeed; -extern u8 gbBgp[4]; -extern u8 gbObp0[4]; -extern u8 gbObp1[4]; -extern u16 gbPalette[128]; -extern bool gbScreenOn; -extern bool gbDrawWindow; -extern u8 gbSCYLine[300]; -// gbSCXLine is used for the emulation (bug) of the SX change -// found in the Artic Zone game. -extern u8 gbSCXLine[300]; -// gbBgpLine is used for the emulation of the -// Prehistorik Man's title screen scroller. -extern u8 gbBgpLine[300]; -extern u8 gbObp0Line [300]; -extern u8 gbObp1Line [300]; -// gbSpritesTicks is used for the emulation of Parodius' Laser Beam. -extern u8 gbSpritesTicks[300]; - -extern u8 register_LCDC; -extern u8 register_LY; -extern u8 register_SCY; -extern u8 register_SCX; -extern u8 register_WY; -extern u8 register_WX; -extern u8 register_VBK; -extern u8 oldRegister_WY; - -extern int emulating; -extern bool genericflashcardEnable; - -extern int gbBorderLineSkip; -extern int gbBorderRowSkip; -extern int gbBorderColumnSkip; -extern int gbDmaTicks; - -extern void gbRenderLine(); -extern void gbDrawSprites(bool); - -extern u8 (*gbSerialFunction)(u8); +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +extern int gbRomSizeMask; +extern int gbRomSize; +extern int gbRamSize; +extern int gbRamSizeMask; +extern int gbTAMA5ramSize; + +extern bool useBios; +extern bool skipBios; +extern u8 *bios; + +extern u8 *gbRom; +extern u8 *gbRam; +extern u8 *gbVram; +extern u8 *gbWram; +extern u8 *gbMemory; +extern u16 *gbLineBuffer; +extern u8 *gbTAMA5ram; + +extern u8 *gbMemoryMap[16]; + +extern int gbFrameSkip; +extern u16 gbColorFilter[32768]; +extern int gbColorOption; +extern int gbPaletteOption; +extern int gbEmulatorType; +extern int gbBorderOn; +extern int gbBorderAutomatic; +extern int gbCgbMode; +extern int gbSgbMode; +extern int gbWindowLine; +extern int gbSpeed; +extern u8 gbBgp[4]; +extern u8 gbObp0[4]; +extern u8 gbObp1[4]; +extern u16 gbPalette[128]; +extern bool gbScreenOn; +extern bool gbDrawWindow; +extern u8 gbSCYLine[300]; +// gbSCXLine is used for the emulation (bug) of the SX change +// found in the Artic Zone game. +extern u8 gbSCXLine[300]; +// gbBgpLine is used for the emulation of the +// Prehistorik Man's title screen scroller. +extern u8 gbBgpLine[300]; +extern u8 gbObp0Line [300]; +extern u8 gbObp1Line [300]; +// gbSpritesTicks is used for the emulation of Parodius' Laser Beam. +extern u8 gbSpritesTicks[300]; + +extern u8 register_LCDC; +extern u8 register_LY; +extern u8 register_SCY; +extern u8 register_SCX; +extern u8 register_WY; +extern u8 register_WX; +extern u8 register_VBK; +extern u8 oldRegister_WY; + +extern int emulating; +extern bool genericflashcardEnable; + +extern int gbBorderLineSkip; +extern int gbBorderRowSkip; +extern int gbBorderColumnSkip; +extern int gbDmaTicks; + +extern void gbRenderLine(); +extern void gbDrawSprites(bool); + +extern u8 (*gbSerialFunction)(u8); diff --git a/src/dmg/gbMemory.cpp b/src/dmg/gbMemory.cpp index 0670bcdf..afc89232 100644 --- a/src/dmg/gbMemory.cpp +++ b/src/dmg/gbMemory.cpp @@ -1,1717 +1,1717 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005-2006 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include "../agb/GBA.h" -#include "../Port.h" -#include "gbGlobals.h" -#include "gbMemory.h" -#include "gb.h" -u8 gbDaysinMonth [12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -const u8 gbDisabledRam [8] = {0x80, 0xff, 0xf0, 0x00, 0x30, 0xbf, 0xbf, 0xbf}; -extern int gbHardware; -extern int gbGBCColorType; -extern gbRegister PC; - -mapperMBC1 gbDataMBC1 = { - 0, // RAM enable - 1, // ROM bank - 0, // RAM bank - 0, // memory model - 0, // ROM high address - 0, // RAM address - 0 // Rom Bank 0 remapping -}; - -// MBC1 ROM write registers -void mapperMBC1ROM(u16 address, u8 value) -{ - int tmpAddress = 0; - - switch(address & 0x6000) { - case 0x0000: // RAM enable register - gbDataMBC1.mapperRAMEnable = ( ( value & 0x0a) == 0x0a ? 1 : 0); - break; - case 0x2000: // ROM bank select - // value = value & 0x1f; - if ((value == 1) && (address == 0x2100)) - gbDataMBC1.mapperRomBank0Remapping = 1; - - if((value & 0x1f) == 0) - value += 1; - if(value == gbDataMBC1.mapperROMBank) - break; - - tmpAddress = value << 14; - - // check current model - if (gbDataMBC1.mapperRomBank0Remapping == 3) { - tmpAddress = (value & 0xf) << 14; - tmpAddress |= (gbDataMBC1.mapperROMHighAddress & 3) << 18; - } - else - if(gbDataMBC1.mapperMemoryModel == 0) { - // model is 16/8, so we have a high address in use - tmpAddress |= (gbDataMBC1.mapperROMHighAddress & 3) << 19; - } - - tmpAddress &= gbRomSizeMask; - gbDataMBC1.mapperROMBank = value; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - break; - case 0x4000: // RAM bank select - if(gbDataMBC1.mapperMemoryModel == 1) { - if (!gbRamSize) - { - if (gbDataMBC1.mapperRomBank0Remapping == 3) - { - gbDataMBC1.mapperROMHighAddress = value & 0x03; - tmpAddress = (gbDataMBC1.mapperROMHighAddress) << 18; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x00] = &gbRom[tmpAddress]; - gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; - gbMemoryMap[0x04] = &gbRom[tmpAddress + 0x4000]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x5000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x6000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x7000]; - } - else gbDataMBC1.mapperRomBank0Remapping = 0; - } - // 4/32 model, RAM bank switching provided - value = value & 0x03; - if(value == gbDataMBC1.mapperRAMBank) - break; - tmpAddress = value << 13; - tmpAddress &= gbRamSizeMask; - if(gbRamSize) { - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - } - gbDataMBC1.mapperRAMBank = value; - gbDataMBC1.mapperRAMAddress = tmpAddress; - - if (gbDataMBC1.mapperRomBank0Remapping != 3) - gbDataMBC1.mapperROMHighAddress = 0; - } else { - // 16/8, set the high address - gbDataMBC1.mapperROMHighAddress = value & 0x03; - tmpAddress = gbDataMBC1.mapperROMBank << 14; - tmpAddress |= (gbDataMBC1.mapperROMHighAddress) << 19; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - if(gbRamSize) { - gbMemoryMap[0x0a] = &gbRam[0]; - gbMemoryMap[0x0b] = &gbRam[0x1000]; - } - - gbDataMBC1.mapperRAMBank = 0; - } - break; - case 0x6000: // memory model select - gbDataMBC1.mapperMemoryModel = value & 1; - - if(gbDataMBC1.mapperMemoryModel == 1) { - // 4/32 model, RAM bank switching provided - - value = gbDataMBC1.mapperRAMBank & 0x03; - tmpAddress = value << 13; - tmpAddress &= gbRamSizeMask; - if(gbRamSize) { - gbMemoryMap[0x0a] = &gbRam[gbDataMBC1.mapperRAMAddress]; - gbMemoryMap[0x0b] = &gbRam[gbDataMBC1.mapperRAMAddress + 0x1000]; - gbDataMBC1.mapperRomBank0Remapping = 0; - } - else gbDataMBC1.mapperRomBank0Remapping |=2; - - gbDataMBC1.mapperRAMBank = value; - gbDataMBC1.mapperRAMAddress = tmpAddress; - - tmpAddress = gbDataMBC1.mapperROMBank << 14; - - - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - } else { - // 16/8, set the high address - - tmpAddress = gbDataMBC1.mapperROMBank << 14; - tmpAddress |= (gbDataMBC1.mapperROMHighAddress) << 19; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - if(gbRamSize) { - gbMemoryMap[0x0a] = &gbRam[0]; - gbMemoryMap[0x0b] = &gbRam[0x1000]; - } - } - break; - } -} - -// MBC1 RAM write -void mapperMBC1RAM(u16 address, u8 value) -{ - if(gbDataMBC1.mapperRAMEnable) { - if(gbRamSize) { - gbMemoryMap[address >> 12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - } -} - -// MBC1 read RAM -u8 mapperMBC1ReadRAM(u16 address) -{ - - if(gbDataMBC1.mapperRAMEnable) - return gbMemoryMap[address>>12][address & 0x0fff]; - - if (!genericflashcardEnable) - return 0xff; - else - if ((address & 0x1000) >= 0x1000) - { - // The value returned when reading RAM while it's disabled - // is constant, exept for the GBASP hardware. - // (actually, is the address that read is out of the ROM, the returned value if 0xff...) - if (PC.W>=0xff80) - return 0xff; - else - if ((gbHardware & 0x08) && (gbGBCColorType == 2)) - { - if (address & 1) - return 0xfb; - else - return 0x7a; - } - else - return 0x0a; - } - else - return gbDisabledRam[address & 7]; -} - -void memoryUpdateMapMBC1() -{ - int tmpAddress = gbDataMBC1.mapperROMBank << 14; - - // check current model - if (gbDataMBC1.mapperRomBank0Remapping == 3) { - tmpAddress = (gbDataMBC1.mapperROMHighAddress & 3) << 18; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x00] = &gbRom[tmpAddress]; - gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; - - tmpAddress |= (gbDataMBC1.mapperROMBank & 0xf) << 14; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - } - else - { - if(gbDataMBC1.mapperMemoryModel == 0) { - // model is 16/8, so we have a high address in use - tmpAddress |= (gbDataMBC1.mapperROMHighAddress & 3) << 19; - } - - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - } - - if((gbRamSize) && (gbDataMBC1.mapperMemoryModel == 1)){ - gbMemoryMap[0x0a] = &gbRam[gbDataMBC1.mapperRAMAddress]; - gbMemoryMap[0x0b] = &gbRam[gbDataMBC1.mapperRAMAddress + 0x1000]; - } -} - -mapperMBC2 gbDataMBC2 = { - 0, // RAM enable - 1 // ROM bank -}; - -// MBC2 ROM write registers -void mapperMBC2ROM(u16 address, u8 value) -{ - switch(address & 0x6000) { - case 0x0000: // RAM enable - if(!(address & 0x0100)) { - gbDataMBC2.mapperRAMEnable = (value & 0x0f) == 0x0a; - } - break; - case 0x2000: // ROM bank select - if(address & 0x0100) { - value &= 0x0f; - - if(value == 0) - value = 1; - if(gbDataMBC2.mapperROMBank != value) { - gbDataMBC2.mapperROMBank = value; - - int tmpAddress = value << 14; - - tmpAddress &= gbRomSizeMask; - - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - } - } - break; - } -} - -// MBC2 RAM write -void mapperMBC2RAM(u16 address, u8 value) -{ - if(gbDataMBC2.mapperRAMEnable) { - if(gbRamSize && address < 0xa200) { - gbMemoryMap[address >> 12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - } -} - -void memoryUpdateMapMBC2() -{ - int tmpAddress = gbDataMBC2.mapperROMBank << 14; - - tmpAddress &= gbRomSizeMask; - - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; -} - -mapperMBC3 gbDataMBC3 = { - 0, // RAM enable - 1, // ROM bank - 0, // RAM bank - 0, // RAM address - 0, // timer clock latch - 0, // timer clock register - 0, // timer seconds - 0, // timer minutes - 0, // timer hours - 0, // timer days - 0, // timer control - 0, // timer latched seconds - 0, // timer latched minutes - 0, // timer latched hours - 0, // timer latched days - 0, // timer latched control - (time_t)-1 // last time -}; - -void memoryUpdateMBC3Clock() -{ - time_t now = time(NULL); - time_t diff = now - gbDataMBC3.mapperLastTime; - if(diff > 0) { - // update the clock according to the last update time - gbDataMBC3.mapperSeconds += (int)(diff % 60); - if(gbDataMBC3.mapperSeconds > 59) { - gbDataMBC3.mapperSeconds -= 60; - gbDataMBC3.mapperMinutes++; - } - - diff /= 60; - - gbDataMBC3.mapperMinutes += (int)(diff % 60); - if(gbDataMBC3.mapperMinutes > 59) { - gbDataMBC3.mapperMinutes -= 60; - gbDataMBC3.mapperHours++; - } - - diff /= 60; - - gbDataMBC3.mapperHours += (int)(diff % 24); - if(gbDataMBC3.mapperHours > 23) { - gbDataMBC3.mapperHours -= 24; - gbDataMBC3.mapperDays++; - } - diff /= 24; - - gbDataMBC3.mapperDays += (int)(diff & 0xffffffff); - if(gbDataMBC3.mapperDays > 255) { - if(gbDataMBC3.mapperDays > 511) { - gbDataMBC3.mapperDays %= 512; - gbDataMBC3.mapperControl |= 0x80; - } - gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) | - (gbDataMBC3.mapperDays>255 ? 1 : 0); - } - } - gbDataMBC3.mapperLastTime = now; -} - -// MBC3 ROM write registers -void mapperMBC3ROM(u16 address, u8 value) -{ - int tmpAddress = 0; - - switch(address & 0x6000) { - case 0x0000: // RAM enable register - gbDataMBC3.mapperRAMEnable = ( ( value & 0x0a) == 0x0a ? 1 : 0); - break; - case 0x2000: // ROM bank select - value = value & 0x7f; - if(value == 0) - value = 1; - if(value == gbDataMBC3.mapperROMBank) - break; - - tmpAddress = value << 14; - - tmpAddress &= gbRomSizeMask; - gbDataMBC3.mapperROMBank = value; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - break; - case 0x4000: // RAM bank select - if(value < 8) { - if(value == gbDataMBC3.mapperRAMBank) - break; - tmpAddress = value << 13; - tmpAddress &= gbRamSizeMask; - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - gbDataMBC3.mapperRAMBank = value; - gbDataMBC3.mapperRAMAddress = tmpAddress; - } else { - if(gbDataMBC3.mapperRAMEnable) { - gbDataMBC3.mapperRAMBank = -1; - - gbDataMBC3.mapperClockRegister = value; - } - } - break; - case 0x6000: // clock latch - if(gbDataMBC3.mapperClockLatch == 0 && value == 1) { - memoryUpdateMBC3Clock(); - gbDataMBC3.mapperLSeconds = gbDataMBC3.mapperSeconds; - gbDataMBC3.mapperLMinutes = gbDataMBC3.mapperMinutes; - gbDataMBC3.mapperLHours = gbDataMBC3.mapperHours; - gbDataMBC3.mapperLDays = gbDataMBC3.mapperDays; - gbDataMBC3.mapperLControl = gbDataMBC3.mapperControl; - } - if(value == 0x00 || value == 0x01) - gbDataMBC3.mapperClockLatch = value; - break; - } -} - -// MBC3 RAM write -void mapperMBC3RAM(u16 address, u8 value) -{ - if(gbDataMBC3.mapperRAMEnable) { - if(gbDataMBC3.mapperRAMBank != -1) { - if(gbRamSize) { - gbMemoryMap[address>>12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - } else { - time(&gbDataMBC3.mapperLastTime); - switch(gbDataMBC3.mapperClockRegister) { - case 0x08: - gbDataMBC3.mapperSeconds = value; - break; - case 0x09: - gbDataMBC3.mapperMinutes = value; - break; - case 0x0a: - gbDataMBC3.mapperHours = value; - break; - case 0x0b: - gbDataMBC3.mapperDays = value; - break; - case 0x0c: - if(gbDataMBC3.mapperControl & 0x80) - gbDataMBC3.mapperControl = 0x80 | value; - else - gbDataMBC3.mapperControl = value; - break; - } - } - } -} - -// MBC3 read RAM -u8 mapperMBC3ReadRAM(u16 address) -{ - if(gbDataMBC3.mapperRAMEnable) { - if(gbDataMBC3.mapperRAMBank != -1) { - return gbMemoryMap[address>>12][address & 0x0fff]; - } - - switch(gbDataMBC3.mapperClockRegister) { - case 0x08: - return gbDataMBC3.mapperLSeconds; - break; - case 0x09: - return gbDataMBC3.mapperLMinutes; - break; - case 0x0a: - return gbDataMBC3.mapperLHours; - break; - case 0x0b: - return gbDataMBC3.mapperLDays; - break; - case 0x0c: - return gbDataMBC3.mapperLControl; - } - } - - if (!genericflashcardEnable) - return 0xff; - else - if ((address & 0x1000) >= 0x1000) - { - // The value returned when reading RAM while it's disabled - // is constant, exept for the GBASP hardware. - // (actually, is the address that read is out of the ROM, the returned value if 0xff...) - if (PC.W>=0xff80) - return 0xff; - else - if ((gbHardware & 0x08) && (gbGBCColorType == 2)) - { - if (address & 1) - return 0xfb; - else - return 0x7a; - } - else - return 0x0a; - } - else - return gbDisabledRam[address & 7]; -} - -void memoryUpdateMapMBC3() -{ - int tmpAddress = gbDataMBC3.mapperROMBank << 14; - - tmpAddress &= gbRomSizeMask; - - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - if(gbDataMBC3.mapperRAMBank >= 0 && gbRamSize) { - tmpAddress = gbDataMBC3.mapperRAMBank << 13; - tmpAddress &= gbRamSizeMask; - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - } -} - -mapperMBC5 gbDataMBC5 = { - 0, // RAM enable - 1, // ROM bank - 0, // RAM bank - 0, // ROM high address - 0, // RAM address - 0 // is rumble cartridge? -}; - -// MBC5 ROM write registers -void mapperMBC5ROM(u16 address, u8 value) -{ - int tmpAddress = 0; - - switch(address & 0x6000) { - case 0x0000: // RAM enable register - gbDataMBC5.mapperRAMEnable = ( ( value & 0x0a) == 0x0a ? 1 : 0); - break; - case 0x2000: // ROM bank select - - if(address < 0x3000) { - value = value & 0xff; - if(value == gbDataMBC5.mapperROMBank) - break; - - tmpAddress = (value << 14) | (gbDataMBC5.mapperROMHighAddress << 22) ; - - tmpAddress &= gbRomSizeMask; - gbDataMBC5.mapperROMBank = value; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - } else { - value = value & 1; - if(value == gbDataMBC5.mapperROMHighAddress) - break; - - tmpAddress = (gbDataMBC5.mapperROMBank << 14) | (value << 22); - - tmpAddress &= gbRomSizeMask; - gbDataMBC5.mapperROMHighAddress = value; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - } - break; - case 0x4000: // RAM bank select - if(gbDataMBC5.isRumbleCartridge) - value &= 0x07; - else - value &= 0x0f; - if(value == gbDataMBC5.mapperRAMBank) - break; - tmpAddress = value << 13; - tmpAddress &= gbRamSizeMask; - if(gbRamSize) { - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - - gbDataMBC5.mapperRAMBank = value; - gbDataMBC5.mapperRAMAddress = tmpAddress; - } - break; - } -} - -// MBC5 RAM write -void mapperMBC5RAM(u16 address, u8 value) -{ - if(gbDataMBC5.mapperRAMEnable) { - if(gbRamSize) { - gbMemoryMap[address >> 12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - } -} - -// MBC5 read RAM -u8 mapperMBC5ReadRAM(u16 address) -{ - - if(gbDataMBC5.mapperRAMEnable) - return gbMemoryMap[address>>12][address & 0x0fff]; - - if (!genericflashcardEnable) - return 0xff; - else - if ((address & 0x1000) >= 0x1000) - { - // The value returned when reading RAM while it's disabled - // is constant, exept for the GBASP hardware. - // (actually, is the address that read is out of the ROM, the returned value if 0xff...) - if (PC.W>=0xff80) - return 0xff; - else - if ((gbHardware & 0x08) && (gbGBCColorType == 2)) - { - if (address & 1) - return 0xfb; - else - return 0x7a; - } - else - return 0x0a; - } - else - return gbDisabledRam[address & 7]; -} - -void memoryUpdateMapMBC5() -{ - int tmpAddress = (gbDataMBC5.mapperROMBank << 14) | - (gbDataMBC5.mapperROMHighAddress << 22) ; - - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - if(gbRamSize) { - tmpAddress = gbDataMBC5.mapperRAMBank << 13; - tmpAddress &= gbRamSizeMask; - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - } -} - -mapperMBC7 gbDataMBC7 = { - 0, // RAM enable - 1, // ROM bank - 0, // RAM bank - 0, // RAM address - 0, // chip select - 0, // ?? - 0, // mapper state - 0, // buffer for receiving serial data - 0, // idle state - 0, // count of bits received - 0, // command received - 0, // address received - 0, // write enable - 0, // value to return on ram -}; - -// MBC7 ROM write registers -void mapperMBC7ROM(u16 address, u8 value) -{ - int tmpAddress = 0; - - switch(address & 0x6000) { - case 0x0000: - break; - case 0x2000: // ROM bank select - value = value & 0x7f; - if(value == 0) - value = 1; - - if(value == gbDataMBC7.mapperROMBank) - break; - - tmpAddress = (value << 14); - - tmpAddress &= gbRomSizeMask; - gbDataMBC7.mapperROMBank = value; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - break; - case 0x4000: // RAM bank select/enable - if(value < 8) { - tmpAddress = (value&3) << 13; - tmpAddress &= gbRamSizeMask; - gbMemoryMap[0x0a] = &gbMemory[0xa000]; - gbMemoryMap[0x0b] = &gbMemory[0xb000]; - - gbDataMBC7.mapperRAMBank = value; - gbDataMBC7.mapperRAMAddress = tmpAddress; - gbDataMBC7.mapperRAMEnable = 0; - } else { - gbDataMBC7.mapperRAMEnable = 0; - } - break; - } -} - -// MBC7 read RAM -u8 mapperMBC7ReadRAM(u16 address) -{ - switch(address & 0xa0f0) { - case 0xa000: - case 0xa010: - case 0xa060: - case 0xa070: - return 0; - case 0xa020: - // sensor X low byte - return systemGetSensorX() & 255; - case 0xa030: - // sensor X high byte - return systemGetSensorX() >> 8; - case 0xa040: - // sensor Y low byte - return systemGetSensorY() & 255; - case 0xa050: - // sensor Y high byte - return systemGetSensorY() >> 8; - case 0xa080: - return gbDataMBC7.value; - } - - if (!genericflashcardEnable) - return 0xff; - else - if ((address & 0x1000) >= 0x1000) - { - // The value returned when reading RAM while it's disabled - // is constant, exept for the GBASP hardware. - // (actually, is the address that read is out of the ROM, the returned value if 0xff...) - if (PC.W>=0xff80) - return 0xff; - else - if ((gbHardware & 0x08) && (gbGBCColorType == 2)) - { - if (address & 1) - return 0xfb; - else - return 0x7a; - } - else - return 0x0a; - } - else - return gbDisabledRam[address & 7]; -} - -// MBC7 RAM write -void mapperMBC7RAM(u16 address, u8 value) -{ - if(address == 0xa080) { - // special processing needed - int oldCs = gbDataMBC7.cs,oldSk=gbDataMBC7.sk; - - gbDataMBC7.cs=value>>7; - gbDataMBC7.sk=(value>>6)&1; - - if(!oldCs && gbDataMBC7.cs) { - if(gbDataMBC7.state==5) { - if(gbDataMBC7.writeEnable) { - gbMemory[0xa000+gbDataMBC7.address*2]=gbDataMBC7.buffer>>8; - gbMemory[0xa000+gbDataMBC7.address*2+1]=gbDataMBC7.buffer&0xff; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - gbDataMBC7.state=0; - gbDataMBC7.value=1; - } else { - gbDataMBC7.idle=true; - gbDataMBC7.state=0; - } - } - - if(!oldSk && gbDataMBC7.sk) { - if(gbDataMBC7.idle) { - if(value & 0x02) { - gbDataMBC7.idle=false; - gbDataMBC7.count=0; - gbDataMBC7.state=1; - } - } else { - switch(gbDataMBC7.state) { - case 1: - // receiving command - gbDataMBC7.buffer <<= 1; - gbDataMBC7.buffer |= (value & 0x02)?1:0; - gbDataMBC7.count++; - if(gbDataMBC7.count==2) { - // finished receiving command - gbDataMBC7.state=2; - gbDataMBC7.count=0; - gbDataMBC7.code=gbDataMBC7.buffer & 3; - } - break; - case 2: - // receive address - gbDataMBC7.buffer <<= 1; - gbDataMBC7.buffer |= (value&0x02)?1:0; - gbDataMBC7.count++; - if(gbDataMBC7.count==8) { - // finish receiving - gbDataMBC7.state=3; - gbDataMBC7.count=0; - gbDataMBC7.address=gbDataMBC7.buffer&0xff; - if(gbDataMBC7.code==0) { - if((gbDataMBC7.address>>6)==0) { - gbDataMBC7.writeEnable=0; - gbDataMBC7.state=0; - } else if((gbDataMBC7.address>>6) == 3) { - gbDataMBC7.writeEnable=1; - gbDataMBC7.state=0; - } - } - } - break; - case 3: - gbDataMBC7.buffer <<= 1; - gbDataMBC7.buffer |= (value&0x02)?1:0; - gbDataMBC7.count++; - - switch(gbDataMBC7.code) { - case 0: - if(gbDataMBC7.count==16) { - if((gbDataMBC7.address>>6)==0) { - gbDataMBC7.writeEnable = 0; - gbDataMBC7.state=0; - } else if((gbDataMBC7.address>>6)==1) { - if (gbDataMBC7.writeEnable) { - for(int i=0;i<256;i++) { - gbMemory[0xa000+i*2] = gbDataMBC7.buffer >> 8; - gbMemory[0xa000+i*2+1] = gbDataMBC7.buffer & 0xff; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - } - gbDataMBC7.state=5; - } else if((gbDataMBC7.address>>6) == 2) { - if (gbDataMBC7.writeEnable) { - for(int i=0;i<256;i++) - WRITE16LE((u16 *)&gbMemory[0xa000+i*2], 0xffff); - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - gbDataMBC7.state=5; - } else if((gbDataMBC7.address>>6)==3) { - gbDataMBC7.writeEnable = 1; - gbDataMBC7.state=0; - } - gbDataMBC7.count=0; - } - break; - case 1: - if(gbDataMBC7.count==16) { - gbDataMBC7.count=0; - gbDataMBC7.state=5; - gbDataMBC7.value=0; - } - break; - case 2: - if(gbDataMBC7.count==1) { - gbDataMBC7.state=4; - gbDataMBC7.count=0; - gbDataMBC7.buffer = (gbMemory[0xa000+gbDataMBC7.address*2]<<8)| - (gbMemory[0xa000+gbDataMBC7.address*2+1]); - } - break; - case 3: - if(gbDataMBC7.count==16) { - gbDataMBC7.count=0; - gbDataMBC7.state=5; - gbDataMBC7.value=0; - gbDataMBC7.buffer=0xffff; - } - break; - } - break; - } - } - } - - if (oldSk && !gbDataMBC7.sk) { - if (gbDataMBC7.state==4) { - gbDataMBC7.value = (gbDataMBC7.buffer & 0x8000)?1:0; - gbDataMBC7.buffer <<= 1; - gbDataMBC7.count++; - if (gbDataMBC7.count==16) { - gbDataMBC7.count=0; - gbDataMBC7.state=0; - } - } - } - } -} - -void memoryUpdateMapMBC7() -{ - int tmpAddress = (gbDataMBC7.mapperROMBank << 14); - - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; -} - -mapperHuC1 gbDataHuC1 = { - 0, // RAM enable - 1, // ROM bank - 0, // RAM bank - 0, // memory model - 0, // ROM high address - 0 // RAM address -}; - -// HuC1 ROM write registers -void mapperHuC1ROM(u16 address, u8 value) -{ - int tmpAddress = 0; - - switch(address & 0x6000) { - case 0x0000: // RAM enable register - gbDataHuC1.mapperRAMEnable = ( ( value & 0x0a) == 0x0a ? 1 : 0); - break; - case 0x2000: // ROM bank select - value = value & 0x3f; - if(value == 0) - value = 1; - if(value == gbDataHuC1.mapperROMBank) - break; - - tmpAddress = value << 14; - - tmpAddress &= gbRomSizeMask; - gbDataHuC1.mapperROMBank = value; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - break; - case 0x4000: // RAM bank select - if(gbDataHuC1.mapperMemoryModel == 1) { - // 4/32 model, RAM bank switching provided - value = value & 0x03; - if(value == gbDataHuC1.mapperRAMBank) - break; - tmpAddress = value << 13; - tmpAddress &= gbRamSizeMask; - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - gbDataHuC1.mapperRAMBank = value; - gbDataHuC1.mapperRAMAddress = tmpAddress; - } else { - // 16/8, set the high address - gbDataHuC1.mapperROMHighAddress = value & 0x03; - tmpAddress = gbDataHuC1.mapperROMBank << 14; - tmpAddress |= (gbDataHuC1.mapperROMHighAddress) << 19; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - } - break; - case 0x6000: // memory model select - gbDataHuC1.mapperMemoryModel = value & 1; - break; - } -} - -// HuC1 RAM write -void mapperHuC1RAM(u16 address, u8 value) -{ - if(gbDataHuC1.mapperRAMEnable) { - if(gbRamSize) { - gbMemoryMap[address >> 12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - } -} - -void memoryUpdateMapHuC1() -{ - int tmpAddress = gbDataHuC1.mapperROMBank << 14; - - tmpAddress &= gbRomSizeMask; - - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - if(gbRamSize) { - tmpAddress = gbDataHuC1.mapperRAMBank << 13; - tmpAddress &= gbRamSizeMask; - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - } -} - -mapperHuC3 gbDataHuC3 = { - 0, // RAM enable - 1, // ROM bank - 0, // RAM bank - 0, // RAM address - 0, // RAM flag - 0 // RAM read value -}; - - -// HuC3 ROM write registers -void mapperHuC3ROM(u16 address, u8 value) -{ - int tmpAddress = 0; - - switch(address & 0x6000) { - case 0x0000: // RAM enable register - gbDataHuC3.mapperRAMEnable = ( value == 0x0a ? 1 : 0); - gbDataHuC3.mapperRAMFlag = value; - if(gbDataHuC3.mapperRAMFlag != 0x0a) - gbDataHuC3.mapperRAMBank = -1; - break; - case 0x2000: // ROM bank select - value = value & 0x7f; - if(value == 0) - value = 1; - if(value == gbDataHuC3.mapperROMBank) - break; - - tmpAddress = value << 14; - - tmpAddress &= gbRomSizeMask; - gbDataHuC3.mapperROMBank = value; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - break; - case 0x4000: // RAM bank select - value = value & 0x03; - if(value == gbDataHuC3.mapperRAMBank) - break; - tmpAddress = value << 13; - tmpAddress &= gbRamSizeMask; - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - gbDataHuC3.mapperRAMBank = value; - gbDataHuC3.mapperRAMAddress = tmpAddress; - break; - case 0x6000: // nothing to do! - break; - } -} - -// HuC3 read RAM -u8 mapperHuC3ReadRAM(u16 address) -{ - if(gbDataHuC3.mapperRAMFlag > 0x0b && - gbDataHuC3.mapperRAMFlag < 0x0e) { - if(gbDataHuC3.mapperRAMFlag != 0x0c) - return 1; - return gbDataHuC3.mapperRAMValue; - } else - return gbMemoryMap[address >> 12][address & 0x0fff]; -} - -// HuC3 RAM write -void mapperHuC3RAM(u16 address, u8 value) -{ - int *p; - - if(gbDataHuC3.mapperRAMFlag < 0x0b || - gbDataHuC3.mapperRAMFlag > 0x0e) { - if(gbDataHuC3.mapperRAMEnable) { - if(gbRamSize) { - gbMemoryMap[address >> 12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - } - } else { - if(gbDataHuC3.mapperRAMFlag == 0x0b) { - if(value == 0x62) { - gbDataHuC3.mapperRAMValue = 1; - } else { - switch(value & 0xf0) { - case 0x10: - p = &gbDataHuC3.mapperRegister2; - gbDataHuC3.mapperRAMValue = *(p+gbDataHuC3.mapperRegister1++); - if(gbDataHuC3.mapperRegister1 > 6) - gbDataHuC3.mapperRegister1 = 0; - break; - case 0x30: - p = &gbDataHuC3.mapperRegister2; - *(p+gbDataHuC3.mapperRegister1++) = value & 0x0f; - if(gbDataHuC3.mapperRegister1 > 6) - gbDataHuC3.mapperRegister1 = 0; - gbDataHuC3.mapperAddress = - (gbDataHuC3.mapperRegister6 << 24) | - (gbDataHuC3.mapperRegister5 << 16) | - (gbDataHuC3.mapperRegister4 << 8) | - (gbDataHuC3.mapperRegister3 << 4) | - (gbDataHuC3.mapperRegister2); - break; - case 0x40: - gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0xf0) | - (value & 0x0f); - gbDataHuC3.mapperRegister2 = (gbDataHuC3.mapperAddress & 0x0f); - gbDataHuC3.mapperRegister3 = ((gbDataHuC3.mapperAddress>>4)&0x0f); - gbDataHuC3.mapperRegister4 = ((gbDataHuC3.mapperAddress>>8)&0x0f); - gbDataHuC3.mapperRegister5 = ((gbDataHuC3.mapperAddress>>16)&0x0f); - gbDataHuC3.mapperRegister6 = ((gbDataHuC3.mapperAddress>>24)&0x0f); - gbDataHuC3.mapperRegister7 = 0; - gbDataHuC3.mapperRegister8 = 0; - gbDataHuC3.mapperRAMValue = 0; - break; - case 0x50: - gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0x0f) | - ((value << 4)&0x0f); - break; - default: - gbDataHuC3.mapperRAMValue = 1; - break; - } - } - } - } -} - -void memoryUpdateMapHuC3() -{ - int tmpAddress = gbDataHuC3.mapperROMBank << 14; - - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - if(gbRamSize) { - tmpAddress = gbDataHuC3.mapperRAMBank << 13; - tmpAddress &= gbRamSizeMask; - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - } -} - -// TAMA5 (for Tamagotchi 3 (gb)). -// Very basic (and ugly :p) support, only rom bank switching is actually working... -mapperTAMA5 gbDataTAMA5 = { - 1, // RAM enable - 1, // ROM bank - 0, // RAM bank - 0, // RAM address - 0, // RAM Byte select - 0, // mapper command number - 0, // mapper last command; - 0, // commands 0x0 - 0, // commands 0x1 - 0, // commands 0x2 - 0, // commands 0x3 - 0, // commands 0x4 - 0, // commands 0x5 - 0, // commands 0x6 - 0, // commands 0x7 - 0, // commands 0x8 - 0, // commands 0x9 - 0, // commands 0xa - 0, // commands 0xb - 0, // commands 0xc - 0, // commands 0xd - 0, // commands 0xe - 0, // commands 0xf - 0, // register - 0, // timer clock latch - 0, // timer clock register - 0, // timer seconds - 0, // timer minutes - 0, // timer hours - 0, // timer days - 0, // timer months - 0, // timer years - 0, // timer control - 0, // timer latched seconds - 0, // timer latched minutes - 0, // timer latched hours - 0, // timer latched days - 0, // timer latched months - 0, // timer latched years - 0, // timer latched control - (time_t)-1 // last time -}; - - -void memoryUpdateTAMA5Clock() -{ - if ((gbDataTAMA5.mapperYears & 3) == 0) - gbDaysinMonth[1] = 29; - else - gbDaysinMonth[1] = 28; - - time_t now = time(NULL); - time_t diff = now - gbDataTAMA5.mapperLastTime; - if(diff > 0) { - // update the clock according to the last update time - gbDataTAMA5.mapperSeconds += (int)(diff % 60); - if(gbDataTAMA5.mapperSeconds > 59) { - gbDataTAMA5.mapperSeconds -= 60; - gbDataTAMA5.mapperMinutes++; - } - - diff /= 60; - - gbDataTAMA5.mapperMinutes += (int)(diff % 60); - if(gbDataTAMA5.mapperMinutes > 59) { - gbDataTAMA5.mapperMinutes -= 60; - gbDataTAMA5.mapperHours++; - } - - diff /= 60; - - gbDataTAMA5.mapperHours += (int)(diff % 24); - diff /= 24; - if(gbDataTAMA5.mapperHours > 23) { - gbDataTAMA5.mapperHours -= 24; - diff++; - - } - - time_t days = diff; - while (days) - { - gbDataTAMA5.mapperDays++; - days--; - if (gbDataTAMA5.mapperDays>gbDaysinMonth[gbDataTAMA5.mapperMonths-1]) - { - gbDataTAMA5.mapperDays = 1; - gbDataTAMA5.mapperMonths++; - if (gbDataTAMA5.mapperMonths>12) - { - gbDataTAMA5.mapperMonths = 1; - gbDataTAMA5.mapperYears++; - if ((gbDataTAMA5.mapperYears & 3) == 0) - gbDaysinMonth[1] = 29; - else - gbDaysinMonth[1] = 28; - } - } - } - } - gbDataTAMA5.mapperLastTime = now; - -} - - - -// TAMA5 RAM write -void mapperTAMA5RAM(u16 address, u8 value) -{ - if ((address & 0xffff) <= 0xa001) - { - switch (address & 1) - { - case 0: // 'Values' Register - { - value &= 0xf; - gbDataTAMA5.mapperCommands[gbDataTAMA5.mapperCommandNumber] = value; - gbMemoryMap[0xa][0] = value; - - int test = gbDataTAMA5.mapperCommands[gbDataTAMA5.mapperCommandNumber & 0x0e] | - (gbDataTAMA5.mapperCommands[(gbDataTAMA5.mapperCommandNumber & 0x0e) +1]<<4); - - if ((gbDataTAMA5.mapperCommandNumber & 0xe) == 0) // Read Command !!! - { - gbDataTAMA5.mapperROMBank = gbDataTAMA5.mapperCommands[0] | - (gbDataTAMA5.mapperCommands[1]<<4); - - int tmpAddress = (gbDataTAMA5.mapperROMBank << 14); - - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - gbDataTAMA5.mapperCommands[0x0f] = 0; - } - else if ((gbDataTAMA5.mapperCommandNumber & 0xe) == 4) - { - gbDataTAMA5.mapperCommands[0x0f] = 1; - if (gbDataTAMA5.mapperCommandNumber == 4) - gbDataTAMA5.mapperCommands[5] =0; // correct ? - } - else if ((gbDataTAMA5.mapperCommandNumber & 0xe) == 6) - { - gbDataTAMA5.mapperRamByteSelect = (gbDataTAMA5.mapperCommands[7]<<4) | - (gbDataTAMA5.mapperCommands[6]&0x0f); - - // Write Commands !!! - if (gbDataTAMA5.mapperCommands[0x0f] && (gbDataTAMA5.mapperCommandNumber == 7)) - { - int data = gbDataTAMA5.mapperCommands[0x04] & 0x0f | - (gbDataTAMA5.mapperCommands[0x05] <<4); - - // Not sure when the write command should reset... - // but it doesn't seem to matter. - // gbDataTAMA5.mapperCommands[0x0f] = 0; - - if (gbDataTAMA5.mapperRamByteSelect == 0x8) // Timer stuff - { - switch (data & 0xf) - { - case 0x7: - gbDataTAMA5.mapperDays = ((gbDataTAMA5.mapperDays)/10)*10 + (data >> 4); - break; - case 0x8: - gbDataTAMA5.mapperDays = (gbDataTAMA5.mapperDays%10) + (data >>4)*10; - break; - case 0x9: - gbDataTAMA5.mapperMonths = ((gbDataTAMA5.mapperMonths)/10)*10 + (data >> 4); - break; - case 0xa: - gbDataTAMA5.mapperMonths = (gbDataTAMA5.mapperMonths%10) + (data >>4)*10; - break; - case 0xb: - gbDataTAMA5.mapperYears = ((gbDataTAMA5.mapperYears)%1000) + (data >> 4)*1000; - break; - case 0xc: - gbDataTAMA5.mapperYears = (gbDataTAMA5.mapperYears%100) + (gbDataTAMA5.mapperYears/1000)*1000 + - (data >>4)*100; - break; - default : - break; - } - } - else if (gbDataTAMA5.mapperRamByteSelect == 0x18) // Timer stuff again - { - memoryUpdateTAMA5Clock(); - gbDataTAMA5.mapperLSeconds = gbDataTAMA5.mapperSeconds; - gbDataTAMA5.mapperLMinutes = gbDataTAMA5.mapperMinutes; - gbDataTAMA5.mapperLHours = gbDataTAMA5.mapperHours; - gbDataTAMA5.mapperLDays = gbDataTAMA5.mapperDays; - gbDataTAMA5.mapperLMonths = gbDataTAMA5.mapperMonths; - gbDataTAMA5.mapperLYears = gbDataTAMA5.mapperYears; - gbDataTAMA5.mapperLControl = gbDataTAMA5.mapperControl; - - int seconds = (gbDataTAMA5.mapperLSeconds / 10)*16 + gbDataTAMA5.mapperLSeconds %10; - int secondsL = (gbDataTAMA5.mapperLSeconds % 10); - int secondsH = (gbDataTAMA5.mapperLSeconds / 10); - int minutes = (gbDataTAMA5.mapperLMinutes / 10)*16 + gbDataTAMA5.mapperLMinutes %10; - int hours = (gbDataTAMA5.mapperLHours / 10)*16 + gbDataTAMA5.mapperLHours %10; - int DaysL = gbDataTAMA5.mapperLDays % 10; - int DaysH = gbDataTAMA5.mapperLDays /10; - int MonthsL = gbDataTAMA5.mapperLMonths % 10; - int MonthsH = gbDataTAMA5.mapperLMonths / 10; - int Years3 = (gbDataTAMA5.mapperLYears / 100) % 10; - int Years4 = (gbDataTAMA5.mapperLYears / 1000); - - switch (data & 0x0f) - { - // I guess cases 0 and 1 are used for secondsL and secondsH - // so the game would update the timer values on screen when - // the seconds reset to 0... ? - case 0x0: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = secondsL; - break; - case 0x1: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = secondsH; - break; - case 0x7: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = DaysL; // days low - break; - case 0x8: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = DaysH; // days high - break; - case 0x9: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = MonthsL; // month low - break; - case 0xa: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = MonthsH; // month high - break; - case 0xb: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = Years4; // years 4th digit - break; - case 0xc: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = Years3; // years 3rd digit - break; - default : - break; - } - - gbTAMA5ram[0x54] = seconds; // incorrect ? (not used by the game) ? - gbTAMA5ram[0x64] = minutes; - gbTAMA5ram[0x74] = hours; - gbTAMA5ram[0x84] = DaysH*16+DaysL; // incorrect ? (not used by the game) ? - gbTAMA5ram[0x94] = MonthsH*16+MonthsL; // incorrect ? (not used by the game) ? - - time(&gbDataTAMA5.mapperLastTime); - - gbMemoryMap[0xa][0] = 1; - } - else if (gbDataTAMA5.mapperRamByteSelect == 0x28) // Timer stuff again - { - if ((data & 0xf) == 0xb) - gbDataTAMA5.mapperYears = ((gbDataTAMA5.mapperYears>>2)<<2) + (data & 3); - } - else if (gbDataTAMA5.mapperRamByteSelect == 0x44) - { - gbDataTAMA5.mapperMinutes = (data/16)*10 + data%16; - } - else if (gbDataTAMA5.mapperRamByteSelect == 0x54) - { - gbDataTAMA5.mapperHours = (data/16)*10 + data%16; - } - else - { - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = data; - } - } - } - } - break; - case 1: // 'Commands' Register - { - gbMemoryMap[0xa][1] = gbDataTAMA5.mapperCommandNumber = value; - - // This should be only a 'is the flashrom ready ?' command. - // However as I couldn't find any 'copy' command - // (that seems to be needed for the saving system to work) - // I put it there... - if (value == 0x0a) - { - for (int i = 0; i<0x10; i++) - for (int j = 0; j<0x10; j++) - if (!(j&2)) - gbTAMA5ram[(i*0x10)+j | 2] = gbTAMA5ram[(i*0x10)+j]; - // Enable this to see the content of the flashrom in 0xe000 - /*for (int k = 0; k<0x100; k++) - gbMemoryMap[0xe][k] = gbTAMA5ram[k];*/ - - gbMemoryMap[0xa][0] = gbDataTAMA5.mapperRAMEnable = 1; - } - else - { - if ((value & 0x0e) == 0x0c) - { - gbDataTAMA5.mapperRamByteSelect = gbDataTAMA5.mapperCommands[6] | - (gbDataTAMA5.mapperCommands[7]<<4); - - u8 byte = gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect]; - - gbMemoryMap[0xa][0] = (value & 1) ? byte >> 4 : byte & 0x0f; - - gbDataTAMA5.mapperCommands[0x0f] = 0; - } - } - break; - } - } - } - else - { - if(gbDataTAMA5.mapperRAMEnable) { - if(gbDataTAMA5.mapperRAMBank != -1) { - if(gbRamSize) { - gbMemoryMap[address>>12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - } - } - } -} - - -// TAMA5 read RAM -u8 mapperTAMA5ReadRAM(u16 address) -{ - return gbMemoryMap[address>>12][address & 0xfff]; -} - - -void memoryUpdateMapTAMA5() -{ - int tmpAddress = (gbDataTAMA5.mapperROMBank << 14); - - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - if(gbRamSize) { - tmpAddress = 0 << 13; - tmpAddress &= gbRamSizeMask; - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - } -} - -// MMM01 Used in Momotarou collection (however the rom is corrupted) -mapperMMM01 gbDataMMM01 ={ - 0, // RAM enable - 1, // ROM bank - 0, // RAM bank - 0, // memory model - 0, // ROM high address - 0, // RAM address - 0 // Rom Bank 0 remapping -}; - -// MMM01 ROM write registers -void mapperMMM01ROM(u16 address, u8 value) -{ - int tmpAddress = 0; - - switch(address & 0x6000) { - case 0x0000: // RAM enable register - gbDataMMM01.mapperRAMEnable = ( ( value & 0x0a) == 0x0a ? 1 : 0); - break; - case 0x2000: // ROM bank select - // value = value & 0x1f; - if(value == 0) - value = 1; - if(value == gbDataMMM01.mapperROMBank) - break; - - tmpAddress = value << 14; - - // check current model - if(gbDataMMM01.mapperMemoryModel == 0) { - // model is 16/8, so we have a high address in use - tmpAddress |= (gbDataMMM01.mapperROMHighAddress) << 19; - } - else - tmpAddress |= gbDataMMM01.mapperRomBank0Remapping << 18; - - tmpAddress &= gbRomSizeMask; - gbDataMMM01.mapperROMBank = value; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - break; - case 0x4000: // RAM bank select - if(gbDataMMM01.mapperMemoryModel == 1) { - // 4/32 model, RAM bank switching provided - value = value & 0x03; - if(value == gbDataMBC1.mapperRAMBank) - break; - tmpAddress = value << 13; - tmpAddress &= gbRamSizeMask; - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - gbDataMMM01.mapperRAMBank = value; - gbDataMMM01.mapperRAMAddress = tmpAddress; - } else { - // 16/8, set the high address - gbDataMMM01.mapperROMHighAddress = value & 0x03; - tmpAddress = gbDataMMM01.mapperROMBank << 14; - tmpAddress |= (gbDataMMM01.mapperROMHighAddress) << 19; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - gbDataMMM01.mapperRomBank0Remapping = ((value<<1) | (value & 0x40 ? 1 : 0)) & 0xff; - tmpAddress = gbDataMMM01.mapperRomBank0Remapping << 18; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x00] = &gbRom[tmpAddress]; - gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; - } - break; - case 0x6000: // memory model select - gbDataMMM01.mapperMemoryModel = value & 1; - break; - } -} - -// MMM01 RAM write -void mapperMMM01RAM(u16 address, u8 value) -{ - if(gbDataMMM01.mapperRAMEnable) { - if(gbRamSize) { - gbMemoryMap[address >> 12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - } -} - -void memoryUpdateMapMMM01() -{ - int tmpAddress = gbDataMMM01.mapperROMBank << 14; - - // check current model - if(gbDataMMM01.mapperMemoryModel == 1) { - // model is 16/8, so we have a high address in use - tmpAddress |= (gbDataMMM01.mapperROMHighAddress) << 19; - } - - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - tmpAddress = gbDataMMM01.mapperRomBank0Remapping << 18; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x00] = &gbRom[tmpAddress]; - gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; - - if(gbRamSize) { - gbMemoryMap[0x0a] = &gbRam[gbDataMMM01.mapperRAMAddress]; - gbMemoryMap[0x0b] = &gbRam[gbDataMMM01.mapperRAMAddress + 0x1000]; - } -} - -// GameGenie ROM write registers -void mapperGGROM(u16 address, u8 value) -{ - int tmpAddress = 0; - - switch(address & 0x6000) { - case 0x0000: // RAM enable register - break; - case 0x2000: // GameGenie has only a half bank - break; - case 0x4000: // GameGenie has no RAM - if ((address >=0x4001) && (address <= 0x4020)) // GG Hardware Registers - gbMemoryMap[address >> 12][address & 0x0fff] = value; - break; - case 0x6000: // GameGenie has only a half bank - break; - } -} - - -// GS3 Used to emulate the GS V3.0 rom bank switching -mapperGS3 gbDataGS3 = { 1 }; // ROM bank - -void mapperGS3ROM(u16 address, u8 value) -{ - int tmpAddress = 0; - - switch(address & 0x6000) { - case 0x0000: // GS has no ram - break; - case 0x2000: // GS has no 'classic' ROM bank select - break; - case 0x4000: // GS has no ram - break; - case 0x6000: // 0x6000 area is RW, and used for GS hardware registers - - if (address == 0x7FE1) // This is the (half) ROM bank select register - { - if(value == gbDataGS3.mapperROMBank) - break; - tmpAddress = value << 13; - - tmpAddress &= gbRomSizeMask; - gbDataGS3.mapperROMBank = value; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - } - else - gbMemoryMap[address>>12][address & 0x0fff] = value; - break; - } -} - -void memoryUpdateMapGS3() -{ - int tmpAddress = gbDataGS3.mapperROMBank << 13; - - tmpAddress &= gbRomSizeMask; - // GS can only change a half ROM bank - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "../agb/GBA.h" +#include "../Port.h" +#include "gbGlobals.h" +#include "gbMemory.h" +#include "gb.h" +u8 gbDaysinMonth [12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +const u8 gbDisabledRam [8] = {0x80, 0xff, 0xf0, 0x00, 0x30, 0xbf, 0xbf, 0xbf}; +extern int gbHardware; +extern int gbGBCColorType; +extern gbRegister PC; + +mapperMBC1 gbDataMBC1 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // memory model + 0, // ROM high address + 0, // RAM address + 0 // Rom Bank 0 remapping +}; + +// MBC1 ROM write registers +void mapperMBC1ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch(address & 0x6000) { + case 0x0000: // RAM enable register + gbDataMBC1.mapperRAMEnable = ( ( value & 0x0a) == 0x0a ? 1 : 0); + break; + case 0x2000: // ROM bank select + // value = value & 0x1f; + if ((value == 1) && (address == 0x2100)) + gbDataMBC1.mapperRomBank0Remapping = 1; + + if((value & 0x1f) == 0) + value += 1; + if(value == gbDataMBC1.mapperROMBank) + break; + + tmpAddress = value << 14; + + // check current model + if (gbDataMBC1.mapperRomBank0Remapping == 3) { + tmpAddress = (value & 0xf) << 14; + tmpAddress |= (gbDataMBC1.mapperROMHighAddress & 3) << 18; + } + else + if(gbDataMBC1.mapperMemoryModel == 0) { + // model is 16/8, so we have a high address in use + tmpAddress |= (gbDataMBC1.mapperROMHighAddress & 3) << 19; + } + + tmpAddress &= gbRomSizeMask; + gbDataMBC1.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + break; + case 0x4000: // RAM bank select + if(gbDataMBC1.mapperMemoryModel == 1) { + if (!gbRamSize) + { + if (gbDataMBC1.mapperRomBank0Remapping == 3) + { + gbDataMBC1.mapperROMHighAddress = value & 0x03; + tmpAddress = (gbDataMBC1.mapperROMHighAddress) << 18; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x00] = &gbRom[tmpAddress]; + gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; + gbMemoryMap[0x04] = &gbRom[tmpAddress + 0x4000]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x5000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x6000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x7000]; + } + else gbDataMBC1.mapperRomBank0Remapping = 0; + } + // 4/32 model, RAM bank switching provided + value = value & 0x03; + if(value == gbDataMBC1.mapperRAMBank) + break; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + if(gbRamSize) { + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } + gbDataMBC1.mapperRAMBank = value; + gbDataMBC1.mapperRAMAddress = tmpAddress; + + if (gbDataMBC1.mapperRomBank0Remapping != 3) + gbDataMBC1.mapperROMHighAddress = 0; + } else { + // 16/8, set the high address + gbDataMBC1.mapperROMHighAddress = value & 0x03; + tmpAddress = gbDataMBC1.mapperROMBank << 14; + tmpAddress |= (gbDataMBC1.mapperROMHighAddress) << 19; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + if(gbRamSize) { + gbMemoryMap[0x0a] = &gbRam[0]; + gbMemoryMap[0x0b] = &gbRam[0x1000]; + } + + gbDataMBC1.mapperRAMBank = 0; + } + break; + case 0x6000: // memory model select + gbDataMBC1.mapperMemoryModel = value & 1; + + if(gbDataMBC1.mapperMemoryModel == 1) { + // 4/32 model, RAM bank switching provided + + value = gbDataMBC1.mapperRAMBank & 0x03; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + if(gbRamSize) { + gbMemoryMap[0x0a] = &gbRam[gbDataMBC1.mapperRAMAddress]; + gbMemoryMap[0x0b] = &gbRam[gbDataMBC1.mapperRAMAddress + 0x1000]; + gbDataMBC1.mapperRomBank0Remapping = 0; + } + else gbDataMBC1.mapperRomBank0Remapping |=2; + + gbDataMBC1.mapperRAMBank = value; + gbDataMBC1.mapperRAMAddress = tmpAddress; + + tmpAddress = gbDataMBC1.mapperROMBank << 14; + + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + } else { + // 16/8, set the high address + + tmpAddress = gbDataMBC1.mapperROMBank << 14; + tmpAddress |= (gbDataMBC1.mapperROMHighAddress) << 19; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + if(gbRamSize) { + gbMemoryMap[0x0a] = &gbRam[0]; + gbMemoryMap[0x0b] = &gbRam[0x1000]; + } + } + break; + } +} + +// MBC1 RAM write +void mapperMBC1RAM(u16 address, u8 value) +{ + if(gbDataMBC1.mapperRAMEnable) { + if(gbRamSize) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } +} + +// MBC1 read RAM +u8 mapperMBC1ReadRAM(u16 address) +{ + + if(gbDataMBC1.mapperRAMEnable) + return gbMemoryMap[address>>12][address & 0x0fff]; + + if (!genericflashcardEnable) + return 0xff; + else + if ((address & 0x1000) >= 0x1000) + { + // The value returned when reading RAM while it's disabled + // is constant, exept for the GBASP hardware. + // (actually, is the address that read is out of the ROM, the returned value if 0xff...) + if (PC.W>=0xff80) + return 0xff; + else + if ((gbHardware & 0x08) && (gbGBCColorType == 2)) + { + if (address & 1) + return 0xfb; + else + return 0x7a; + } + else + return 0x0a; + } + else + return gbDisabledRam[address & 7]; +} + +void memoryUpdateMapMBC1() +{ + int tmpAddress = gbDataMBC1.mapperROMBank << 14; + + // check current model + if (gbDataMBC1.mapperRomBank0Remapping == 3) { + tmpAddress = (gbDataMBC1.mapperROMHighAddress & 3) << 18; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x00] = &gbRom[tmpAddress]; + gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; + + tmpAddress |= (gbDataMBC1.mapperROMBank & 0xf) << 14; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + } + else + { + if(gbDataMBC1.mapperMemoryModel == 0) { + // model is 16/8, so we have a high address in use + tmpAddress |= (gbDataMBC1.mapperROMHighAddress & 3) << 19; + } + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + } + + if((gbRamSize) && (gbDataMBC1.mapperMemoryModel == 1)){ + gbMemoryMap[0x0a] = &gbRam[gbDataMBC1.mapperRAMAddress]; + gbMemoryMap[0x0b] = &gbRam[gbDataMBC1.mapperRAMAddress + 0x1000]; + } +} + +mapperMBC2 gbDataMBC2 = { + 0, // RAM enable + 1 // ROM bank +}; + +// MBC2 ROM write registers +void mapperMBC2ROM(u16 address, u8 value) +{ + switch(address & 0x6000) { + case 0x0000: // RAM enable + if(!(address & 0x0100)) { + gbDataMBC2.mapperRAMEnable = (value & 0x0f) == 0x0a; + } + break; + case 0x2000: // ROM bank select + if(address & 0x0100) { + value &= 0x0f; + + if(value == 0) + value = 1; + if(gbDataMBC2.mapperROMBank != value) { + gbDataMBC2.mapperROMBank = value; + + int tmpAddress = value << 14; + + tmpAddress &= gbRomSizeMask; + + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + } + } + break; + } +} + +// MBC2 RAM write +void mapperMBC2RAM(u16 address, u8 value) +{ + if(gbDataMBC2.mapperRAMEnable) { + if(gbRamSize && address < 0xa200) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } +} + +void memoryUpdateMapMBC2() +{ + int tmpAddress = gbDataMBC2.mapperROMBank << 14; + + tmpAddress &= gbRomSizeMask; + + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; +} + +mapperMBC3 gbDataMBC3 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // RAM address + 0, // timer clock latch + 0, // timer clock register + 0, // timer seconds + 0, // timer minutes + 0, // timer hours + 0, // timer days + 0, // timer control + 0, // timer latched seconds + 0, // timer latched minutes + 0, // timer latched hours + 0, // timer latched days + 0, // timer latched control + (time_t)-1 // last time +}; + +void memoryUpdateMBC3Clock() +{ + time_t now = time(NULL); + time_t diff = now - gbDataMBC3.mapperLastTime; + if(diff > 0) { + // update the clock according to the last update time + gbDataMBC3.mapperSeconds += (int)(diff % 60); + if(gbDataMBC3.mapperSeconds > 59) { + gbDataMBC3.mapperSeconds -= 60; + gbDataMBC3.mapperMinutes++; + } + + diff /= 60; + + gbDataMBC3.mapperMinutes += (int)(diff % 60); + if(gbDataMBC3.mapperMinutes > 59) { + gbDataMBC3.mapperMinutes -= 60; + gbDataMBC3.mapperHours++; + } + + diff /= 60; + + gbDataMBC3.mapperHours += (int)(diff % 24); + if(gbDataMBC3.mapperHours > 23) { + gbDataMBC3.mapperHours -= 24; + gbDataMBC3.mapperDays++; + } + diff /= 24; + + gbDataMBC3.mapperDays += (int)(diff & 0xffffffff); + if(gbDataMBC3.mapperDays > 255) { + if(gbDataMBC3.mapperDays > 511) { + gbDataMBC3.mapperDays %= 512; + gbDataMBC3.mapperControl |= 0x80; + } + gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) | + (gbDataMBC3.mapperDays>255 ? 1 : 0); + } + } + gbDataMBC3.mapperLastTime = now; +} + +// MBC3 ROM write registers +void mapperMBC3ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch(address & 0x6000) { + case 0x0000: // RAM enable register + gbDataMBC3.mapperRAMEnable = ( ( value & 0x0a) == 0x0a ? 1 : 0); + break; + case 0x2000: // ROM bank select + value = value & 0x7f; + if(value == 0) + value = 1; + if(value == gbDataMBC3.mapperROMBank) + break; + + tmpAddress = value << 14; + + tmpAddress &= gbRomSizeMask; + gbDataMBC3.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + break; + case 0x4000: // RAM bank select + if(value < 8) { + if(value == gbDataMBC3.mapperRAMBank) + break; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + gbDataMBC3.mapperRAMBank = value; + gbDataMBC3.mapperRAMAddress = tmpAddress; + } else { + if(gbDataMBC3.mapperRAMEnable) { + gbDataMBC3.mapperRAMBank = -1; + + gbDataMBC3.mapperClockRegister = value; + } + } + break; + case 0x6000: // clock latch + if(gbDataMBC3.mapperClockLatch == 0 && value == 1) { + memoryUpdateMBC3Clock(); + gbDataMBC3.mapperLSeconds = gbDataMBC3.mapperSeconds; + gbDataMBC3.mapperLMinutes = gbDataMBC3.mapperMinutes; + gbDataMBC3.mapperLHours = gbDataMBC3.mapperHours; + gbDataMBC3.mapperLDays = gbDataMBC3.mapperDays; + gbDataMBC3.mapperLControl = gbDataMBC3.mapperControl; + } + if(value == 0x00 || value == 0x01) + gbDataMBC3.mapperClockLatch = value; + break; + } +} + +// MBC3 RAM write +void mapperMBC3RAM(u16 address, u8 value) +{ + if(gbDataMBC3.mapperRAMEnable) { + if(gbDataMBC3.mapperRAMBank != -1) { + if(gbRamSize) { + gbMemoryMap[address>>12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } else { + time(&gbDataMBC3.mapperLastTime); + switch(gbDataMBC3.mapperClockRegister) { + case 0x08: + gbDataMBC3.mapperSeconds = value; + break; + case 0x09: + gbDataMBC3.mapperMinutes = value; + break; + case 0x0a: + gbDataMBC3.mapperHours = value; + break; + case 0x0b: + gbDataMBC3.mapperDays = value; + break; + case 0x0c: + if(gbDataMBC3.mapperControl & 0x80) + gbDataMBC3.mapperControl = 0x80 | value; + else + gbDataMBC3.mapperControl = value; + break; + } + } + } +} + +// MBC3 read RAM +u8 mapperMBC3ReadRAM(u16 address) +{ + if(gbDataMBC3.mapperRAMEnable) { + if(gbDataMBC3.mapperRAMBank != -1) { + return gbMemoryMap[address>>12][address & 0x0fff]; + } + + switch(gbDataMBC3.mapperClockRegister) { + case 0x08: + return gbDataMBC3.mapperLSeconds; + break; + case 0x09: + return gbDataMBC3.mapperLMinutes; + break; + case 0x0a: + return gbDataMBC3.mapperLHours; + break; + case 0x0b: + return gbDataMBC3.mapperLDays; + break; + case 0x0c: + return gbDataMBC3.mapperLControl; + } + } + + if (!genericflashcardEnable) + return 0xff; + else + if ((address & 0x1000) >= 0x1000) + { + // The value returned when reading RAM while it's disabled + // is constant, exept for the GBASP hardware. + // (actually, is the address that read is out of the ROM, the returned value if 0xff...) + if (PC.W>=0xff80) + return 0xff; + else + if ((gbHardware & 0x08) && (gbGBCColorType == 2)) + { + if (address & 1) + return 0xfb; + else + return 0x7a; + } + else + return 0x0a; + } + else + return gbDisabledRam[address & 7]; +} + +void memoryUpdateMapMBC3() +{ + int tmpAddress = gbDataMBC3.mapperROMBank << 14; + + tmpAddress &= gbRomSizeMask; + + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + if(gbDataMBC3.mapperRAMBank >= 0 && gbRamSize) { + tmpAddress = gbDataMBC3.mapperRAMBank << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } +} + +mapperMBC5 gbDataMBC5 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // ROM high address + 0, // RAM address + 0 // is rumble cartridge? +}; + +// MBC5 ROM write registers +void mapperMBC5ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch(address & 0x6000) { + case 0x0000: // RAM enable register + gbDataMBC5.mapperRAMEnable = ( ( value & 0x0a) == 0x0a ? 1 : 0); + break; + case 0x2000: // ROM bank select + + if(address < 0x3000) { + value = value & 0xff; + if(value == gbDataMBC5.mapperROMBank) + break; + + tmpAddress = (value << 14) | (gbDataMBC5.mapperROMHighAddress << 22) ; + + tmpAddress &= gbRomSizeMask; + gbDataMBC5.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + } else { + value = value & 1; + if(value == gbDataMBC5.mapperROMHighAddress) + break; + + tmpAddress = (gbDataMBC5.mapperROMBank << 14) | (value << 22); + + tmpAddress &= gbRomSizeMask; + gbDataMBC5.mapperROMHighAddress = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + } + break; + case 0x4000: // RAM bank select + if(gbDataMBC5.isRumbleCartridge) + value &= 0x07; + else + value &= 0x0f; + if(value == gbDataMBC5.mapperRAMBank) + break; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + if(gbRamSize) { + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + + gbDataMBC5.mapperRAMBank = value; + gbDataMBC5.mapperRAMAddress = tmpAddress; + } + break; + } +} + +// MBC5 RAM write +void mapperMBC5RAM(u16 address, u8 value) +{ + if(gbDataMBC5.mapperRAMEnable) { + if(gbRamSize) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } +} + +// MBC5 read RAM +u8 mapperMBC5ReadRAM(u16 address) +{ + + if(gbDataMBC5.mapperRAMEnable) + return gbMemoryMap[address>>12][address & 0x0fff]; + + if (!genericflashcardEnable) + return 0xff; + else + if ((address & 0x1000) >= 0x1000) + { + // The value returned when reading RAM while it's disabled + // is constant, exept for the GBASP hardware. + // (actually, is the address that read is out of the ROM, the returned value if 0xff...) + if (PC.W>=0xff80) + return 0xff; + else + if ((gbHardware & 0x08) && (gbGBCColorType == 2)) + { + if (address & 1) + return 0xfb; + else + return 0x7a; + } + else + return 0x0a; + } + else + return gbDisabledRam[address & 7]; +} + +void memoryUpdateMapMBC5() +{ + int tmpAddress = (gbDataMBC5.mapperROMBank << 14) | + (gbDataMBC5.mapperROMHighAddress << 22) ; + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + if(gbRamSize) { + tmpAddress = gbDataMBC5.mapperRAMBank << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } +} + +mapperMBC7 gbDataMBC7 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // RAM address + 0, // chip select + 0, // ?? + 0, // mapper state + 0, // buffer for receiving serial data + 0, // idle state + 0, // count of bits received + 0, // command received + 0, // address received + 0, // write enable + 0, // value to return on ram +}; + +// MBC7 ROM write registers +void mapperMBC7ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch(address & 0x6000) { + case 0x0000: + break; + case 0x2000: // ROM bank select + value = value & 0x7f; + if(value == 0) + value = 1; + + if(value == gbDataMBC7.mapperROMBank) + break; + + tmpAddress = (value << 14); + + tmpAddress &= gbRomSizeMask; + gbDataMBC7.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + break; + case 0x4000: // RAM bank select/enable + if(value < 8) { + tmpAddress = (value&3) << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbMemory[0xa000]; + gbMemoryMap[0x0b] = &gbMemory[0xb000]; + + gbDataMBC7.mapperRAMBank = value; + gbDataMBC7.mapperRAMAddress = tmpAddress; + gbDataMBC7.mapperRAMEnable = 0; + } else { + gbDataMBC7.mapperRAMEnable = 0; + } + break; + } +} + +// MBC7 read RAM +u8 mapperMBC7ReadRAM(u16 address) +{ + switch(address & 0xa0f0) { + case 0xa000: + case 0xa010: + case 0xa060: + case 0xa070: + return 0; + case 0xa020: + // sensor X low byte + return systemGetSensorX() & 255; + case 0xa030: + // sensor X high byte + return systemGetSensorX() >> 8; + case 0xa040: + // sensor Y low byte + return systemGetSensorY() & 255; + case 0xa050: + // sensor Y high byte + return systemGetSensorY() >> 8; + case 0xa080: + return gbDataMBC7.value; + } + + if (!genericflashcardEnable) + return 0xff; + else + if ((address & 0x1000) >= 0x1000) + { + // The value returned when reading RAM while it's disabled + // is constant, exept for the GBASP hardware. + // (actually, is the address that read is out of the ROM, the returned value if 0xff...) + if (PC.W>=0xff80) + return 0xff; + else + if ((gbHardware & 0x08) && (gbGBCColorType == 2)) + { + if (address & 1) + return 0xfb; + else + return 0x7a; + } + else + return 0x0a; + } + else + return gbDisabledRam[address & 7]; +} + +// MBC7 RAM write +void mapperMBC7RAM(u16 address, u8 value) +{ + if(address == 0xa080) { + // special processing needed + int oldCs = gbDataMBC7.cs,oldSk=gbDataMBC7.sk; + + gbDataMBC7.cs=value>>7; + gbDataMBC7.sk=(value>>6)&1; + + if(!oldCs && gbDataMBC7.cs) { + if(gbDataMBC7.state==5) { + if(gbDataMBC7.writeEnable) { + gbMemory[0xa000+gbDataMBC7.address*2]=gbDataMBC7.buffer>>8; + gbMemory[0xa000+gbDataMBC7.address*2+1]=gbDataMBC7.buffer&0xff; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + gbDataMBC7.state=0; + gbDataMBC7.value=1; + } else { + gbDataMBC7.idle=true; + gbDataMBC7.state=0; + } + } + + if(!oldSk && gbDataMBC7.sk) { + if(gbDataMBC7.idle) { + if(value & 0x02) { + gbDataMBC7.idle=false; + gbDataMBC7.count=0; + gbDataMBC7.state=1; + } + } else { + switch(gbDataMBC7.state) { + case 1: + // receiving command + gbDataMBC7.buffer <<= 1; + gbDataMBC7.buffer |= (value & 0x02)?1:0; + gbDataMBC7.count++; + if(gbDataMBC7.count==2) { + // finished receiving command + gbDataMBC7.state=2; + gbDataMBC7.count=0; + gbDataMBC7.code=gbDataMBC7.buffer & 3; + } + break; + case 2: + // receive address + gbDataMBC7.buffer <<= 1; + gbDataMBC7.buffer |= (value&0x02)?1:0; + gbDataMBC7.count++; + if(gbDataMBC7.count==8) { + // finish receiving + gbDataMBC7.state=3; + gbDataMBC7.count=0; + gbDataMBC7.address=gbDataMBC7.buffer&0xff; + if(gbDataMBC7.code==0) { + if((gbDataMBC7.address>>6)==0) { + gbDataMBC7.writeEnable=0; + gbDataMBC7.state=0; + } else if((gbDataMBC7.address>>6) == 3) { + gbDataMBC7.writeEnable=1; + gbDataMBC7.state=0; + } + } + } + break; + case 3: + gbDataMBC7.buffer <<= 1; + gbDataMBC7.buffer |= (value&0x02)?1:0; + gbDataMBC7.count++; + + switch(gbDataMBC7.code) { + case 0: + if(gbDataMBC7.count==16) { + if((gbDataMBC7.address>>6)==0) { + gbDataMBC7.writeEnable = 0; + gbDataMBC7.state=0; + } else if((gbDataMBC7.address>>6)==1) { + if (gbDataMBC7.writeEnable) { + for(int i=0;i<256;i++) { + gbMemory[0xa000+i*2] = gbDataMBC7.buffer >> 8; + gbMemory[0xa000+i*2+1] = gbDataMBC7.buffer & 0xff; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } + gbDataMBC7.state=5; + } else if((gbDataMBC7.address>>6) == 2) { + if (gbDataMBC7.writeEnable) { + for(int i=0;i<256;i++) + WRITE16LE((u16 *)&gbMemory[0xa000+i*2], 0xffff); + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + gbDataMBC7.state=5; + } else if((gbDataMBC7.address>>6)==3) { + gbDataMBC7.writeEnable = 1; + gbDataMBC7.state=0; + } + gbDataMBC7.count=0; + } + break; + case 1: + if(gbDataMBC7.count==16) { + gbDataMBC7.count=0; + gbDataMBC7.state=5; + gbDataMBC7.value=0; + } + break; + case 2: + if(gbDataMBC7.count==1) { + gbDataMBC7.state=4; + gbDataMBC7.count=0; + gbDataMBC7.buffer = (gbMemory[0xa000+gbDataMBC7.address*2]<<8)| + (gbMemory[0xa000+gbDataMBC7.address*2+1]); + } + break; + case 3: + if(gbDataMBC7.count==16) { + gbDataMBC7.count=0; + gbDataMBC7.state=5; + gbDataMBC7.value=0; + gbDataMBC7.buffer=0xffff; + } + break; + } + break; + } + } + } + + if (oldSk && !gbDataMBC7.sk) { + if (gbDataMBC7.state==4) { + gbDataMBC7.value = (gbDataMBC7.buffer & 0x8000)?1:0; + gbDataMBC7.buffer <<= 1; + gbDataMBC7.count++; + if (gbDataMBC7.count==16) { + gbDataMBC7.count=0; + gbDataMBC7.state=0; + } + } + } + } +} + +void memoryUpdateMapMBC7() +{ + int tmpAddress = (gbDataMBC7.mapperROMBank << 14); + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; +} + +mapperHuC1 gbDataHuC1 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // memory model + 0, // ROM high address + 0 // RAM address +}; + +// HuC1 ROM write registers +void mapperHuC1ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch(address & 0x6000) { + case 0x0000: // RAM enable register + gbDataHuC1.mapperRAMEnable = ( ( value & 0x0a) == 0x0a ? 1 : 0); + break; + case 0x2000: // ROM bank select + value = value & 0x3f; + if(value == 0) + value = 1; + if(value == gbDataHuC1.mapperROMBank) + break; + + tmpAddress = value << 14; + + tmpAddress &= gbRomSizeMask; + gbDataHuC1.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + break; + case 0x4000: // RAM bank select + if(gbDataHuC1.mapperMemoryModel == 1) { + // 4/32 model, RAM bank switching provided + value = value & 0x03; + if(value == gbDataHuC1.mapperRAMBank) + break; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + gbDataHuC1.mapperRAMBank = value; + gbDataHuC1.mapperRAMAddress = tmpAddress; + } else { + // 16/8, set the high address + gbDataHuC1.mapperROMHighAddress = value & 0x03; + tmpAddress = gbDataHuC1.mapperROMBank << 14; + tmpAddress |= (gbDataHuC1.mapperROMHighAddress) << 19; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + } + break; + case 0x6000: // memory model select + gbDataHuC1.mapperMemoryModel = value & 1; + break; + } +} + +// HuC1 RAM write +void mapperHuC1RAM(u16 address, u8 value) +{ + if(gbDataHuC1.mapperRAMEnable) { + if(gbRamSize) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } +} + +void memoryUpdateMapHuC1() +{ + int tmpAddress = gbDataHuC1.mapperROMBank << 14; + + tmpAddress &= gbRomSizeMask; + + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + if(gbRamSize) { + tmpAddress = gbDataHuC1.mapperRAMBank << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } +} + +mapperHuC3 gbDataHuC3 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // RAM address + 0, // RAM flag + 0 // RAM read value +}; + + +// HuC3 ROM write registers +void mapperHuC3ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch(address & 0x6000) { + case 0x0000: // RAM enable register + gbDataHuC3.mapperRAMEnable = ( value == 0x0a ? 1 : 0); + gbDataHuC3.mapperRAMFlag = value; + if(gbDataHuC3.mapperRAMFlag != 0x0a) + gbDataHuC3.mapperRAMBank = -1; + break; + case 0x2000: // ROM bank select + value = value & 0x7f; + if(value == 0) + value = 1; + if(value == gbDataHuC3.mapperROMBank) + break; + + tmpAddress = value << 14; + + tmpAddress &= gbRomSizeMask; + gbDataHuC3.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + break; + case 0x4000: // RAM bank select + value = value & 0x03; + if(value == gbDataHuC3.mapperRAMBank) + break; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + gbDataHuC3.mapperRAMBank = value; + gbDataHuC3.mapperRAMAddress = tmpAddress; + break; + case 0x6000: // nothing to do! + break; + } +} + +// HuC3 read RAM +u8 mapperHuC3ReadRAM(u16 address) +{ + if(gbDataHuC3.mapperRAMFlag > 0x0b && + gbDataHuC3.mapperRAMFlag < 0x0e) { + if(gbDataHuC3.mapperRAMFlag != 0x0c) + return 1; + return gbDataHuC3.mapperRAMValue; + } else + return gbMemoryMap[address >> 12][address & 0x0fff]; +} + +// HuC3 RAM write +void mapperHuC3RAM(u16 address, u8 value) +{ + int *p; + + if(gbDataHuC3.mapperRAMFlag < 0x0b || + gbDataHuC3.mapperRAMFlag > 0x0e) { + if(gbDataHuC3.mapperRAMEnable) { + if(gbRamSize) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } + } else { + if(gbDataHuC3.mapperRAMFlag == 0x0b) { + if(value == 0x62) { + gbDataHuC3.mapperRAMValue = 1; + } else { + switch(value & 0xf0) { + case 0x10: + p = &gbDataHuC3.mapperRegister2; + gbDataHuC3.mapperRAMValue = *(p+gbDataHuC3.mapperRegister1++); + if(gbDataHuC3.mapperRegister1 > 6) + gbDataHuC3.mapperRegister1 = 0; + break; + case 0x30: + p = &gbDataHuC3.mapperRegister2; + *(p+gbDataHuC3.mapperRegister1++) = value & 0x0f; + if(gbDataHuC3.mapperRegister1 > 6) + gbDataHuC3.mapperRegister1 = 0; + gbDataHuC3.mapperAddress = + (gbDataHuC3.mapperRegister6 << 24) | + (gbDataHuC3.mapperRegister5 << 16) | + (gbDataHuC3.mapperRegister4 << 8) | + (gbDataHuC3.mapperRegister3 << 4) | + (gbDataHuC3.mapperRegister2); + break; + case 0x40: + gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0xf0) | + (value & 0x0f); + gbDataHuC3.mapperRegister2 = (gbDataHuC3.mapperAddress & 0x0f); + gbDataHuC3.mapperRegister3 = ((gbDataHuC3.mapperAddress>>4)&0x0f); + gbDataHuC3.mapperRegister4 = ((gbDataHuC3.mapperAddress>>8)&0x0f); + gbDataHuC3.mapperRegister5 = ((gbDataHuC3.mapperAddress>>16)&0x0f); + gbDataHuC3.mapperRegister6 = ((gbDataHuC3.mapperAddress>>24)&0x0f); + gbDataHuC3.mapperRegister7 = 0; + gbDataHuC3.mapperRegister8 = 0; + gbDataHuC3.mapperRAMValue = 0; + break; + case 0x50: + gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0x0f) | + ((value << 4)&0x0f); + break; + default: + gbDataHuC3.mapperRAMValue = 1; + break; + } + } + } + } +} + +void memoryUpdateMapHuC3() +{ + int tmpAddress = gbDataHuC3.mapperROMBank << 14; + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + if(gbRamSize) { + tmpAddress = gbDataHuC3.mapperRAMBank << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } +} + +// TAMA5 (for Tamagotchi 3 (gb)). +// Very basic (and ugly :p) support, only rom bank switching is actually working... +mapperTAMA5 gbDataTAMA5 = { + 1, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // RAM address + 0, // RAM Byte select + 0, // mapper command number + 0, // mapper last command; + 0, // commands 0x0 + 0, // commands 0x1 + 0, // commands 0x2 + 0, // commands 0x3 + 0, // commands 0x4 + 0, // commands 0x5 + 0, // commands 0x6 + 0, // commands 0x7 + 0, // commands 0x8 + 0, // commands 0x9 + 0, // commands 0xa + 0, // commands 0xb + 0, // commands 0xc + 0, // commands 0xd + 0, // commands 0xe + 0, // commands 0xf + 0, // register + 0, // timer clock latch + 0, // timer clock register + 0, // timer seconds + 0, // timer minutes + 0, // timer hours + 0, // timer days + 0, // timer months + 0, // timer years + 0, // timer control + 0, // timer latched seconds + 0, // timer latched minutes + 0, // timer latched hours + 0, // timer latched days + 0, // timer latched months + 0, // timer latched years + 0, // timer latched control + (time_t)-1 // last time +}; + + +void memoryUpdateTAMA5Clock() +{ + if ((gbDataTAMA5.mapperYears & 3) == 0) + gbDaysinMonth[1] = 29; + else + gbDaysinMonth[1] = 28; + + time_t now = time(NULL); + time_t diff = now - gbDataTAMA5.mapperLastTime; + if(diff > 0) { + // update the clock according to the last update time + gbDataTAMA5.mapperSeconds += (int)(diff % 60); + if(gbDataTAMA5.mapperSeconds > 59) { + gbDataTAMA5.mapperSeconds -= 60; + gbDataTAMA5.mapperMinutes++; + } + + diff /= 60; + + gbDataTAMA5.mapperMinutes += (int)(diff % 60); + if(gbDataTAMA5.mapperMinutes > 59) { + gbDataTAMA5.mapperMinutes -= 60; + gbDataTAMA5.mapperHours++; + } + + diff /= 60; + + gbDataTAMA5.mapperHours += (int)(diff % 24); + diff /= 24; + if(gbDataTAMA5.mapperHours > 23) { + gbDataTAMA5.mapperHours -= 24; + diff++; + + } + + time_t days = diff; + while (days) + { + gbDataTAMA5.mapperDays++; + days--; + if (gbDataTAMA5.mapperDays>gbDaysinMonth[gbDataTAMA5.mapperMonths-1]) + { + gbDataTAMA5.mapperDays = 1; + gbDataTAMA5.mapperMonths++; + if (gbDataTAMA5.mapperMonths>12) + { + gbDataTAMA5.mapperMonths = 1; + gbDataTAMA5.mapperYears++; + if ((gbDataTAMA5.mapperYears & 3) == 0) + gbDaysinMonth[1] = 29; + else + gbDaysinMonth[1] = 28; + } + } + } + } + gbDataTAMA5.mapperLastTime = now; + +} + + + +// TAMA5 RAM write +void mapperTAMA5RAM(u16 address, u8 value) +{ + if ((address & 0xffff) <= 0xa001) + { + switch (address & 1) + { + case 0: // 'Values' Register + { + value &= 0xf; + gbDataTAMA5.mapperCommands[gbDataTAMA5.mapperCommandNumber] = value; + gbMemoryMap[0xa][0] = value; + + int test = gbDataTAMA5.mapperCommands[gbDataTAMA5.mapperCommandNumber & 0x0e] | + (gbDataTAMA5.mapperCommands[(gbDataTAMA5.mapperCommandNumber & 0x0e) +1]<<4); + + if ((gbDataTAMA5.mapperCommandNumber & 0xe) == 0) // Read Command !!! + { + gbDataTAMA5.mapperROMBank = gbDataTAMA5.mapperCommands[0] | + (gbDataTAMA5.mapperCommands[1]<<4); + + int tmpAddress = (gbDataTAMA5.mapperROMBank << 14); + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + gbDataTAMA5.mapperCommands[0x0f] = 0; + } + else if ((gbDataTAMA5.mapperCommandNumber & 0xe) == 4) + { + gbDataTAMA5.mapperCommands[0x0f] = 1; + if (gbDataTAMA5.mapperCommandNumber == 4) + gbDataTAMA5.mapperCommands[5] =0; // correct ? + } + else if ((gbDataTAMA5.mapperCommandNumber & 0xe) == 6) + { + gbDataTAMA5.mapperRamByteSelect = (gbDataTAMA5.mapperCommands[7]<<4) | + (gbDataTAMA5.mapperCommands[6]&0x0f); + + // Write Commands !!! + if (gbDataTAMA5.mapperCommands[0x0f] && (gbDataTAMA5.mapperCommandNumber == 7)) + { + int data = gbDataTAMA5.mapperCommands[0x04] & 0x0f | + (gbDataTAMA5.mapperCommands[0x05] <<4); + + // Not sure when the write command should reset... + // but it doesn't seem to matter. + // gbDataTAMA5.mapperCommands[0x0f] = 0; + + if (gbDataTAMA5.mapperRamByteSelect == 0x8) // Timer stuff + { + switch (data & 0xf) + { + case 0x7: + gbDataTAMA5.mapperDays = ((gbDataTAMA5.mapperDays)/10)*10 + (data >> 4); + break; + case 0x8: + gbDataTAMA5.mapperDays = (gbDataTAMA5.mapperDays%10) + (data >>4)*10; + break; + case 0x9: + gbDataTAMA5.mapperMonths = ((gbDataTAMA5.mapperMonths)/10)*10 + (data >> 4); + break; + case 0xa: + gbDataTAMA5.mapperMonths = (gbDataTAMA5.mapperMonths%10) + (data >>4)*10; + break; + case 0xb: + gbDataTAMA5.mapperYears = ((gbDataTAMA5.mapperYears)%1000) + (data >> 4)*1000; + break; + case 0xc: + gbDataTAMA5.mapperYears = (gbDataTAMA5.mapperYears%100) + (gbDataTAMA5.mapperYears/1000)*1000 + + (data >>4)*100; + break; + default : + break; + } + } + else if (gbDataTAMA5.mapperRamByteSelect == 0x18) // Timer stuff again + { + memoryUpdateTAMA5Clock(); + gbDataTAMA5.mapperLSeconds = gbDataTAMA5.mapperSeconds; + gbDataTAMA5.mapperLMinutes = gbDataTAMA5.mapperMinutes; + gbDataTAMA5.mapperLHours = gbDataTAMA5.mapperHours; + gbDataTAMA5.mapperLDays = gbDataTAMA5.mapperDays; + gbDataTAMA5.mapperLMonths = gbDataTAMA5.mapperMonths; + gbDataTAMA5.mapperLYears = gbDataTAMA5.mapperYears; + gbDataTAMA5.mapperLControl = gbDataTAMA5.mapperControl; + + int seconds = (gbDataTAMA5.mapperLSeconds / 10)*16 + gbDataTAMA5.mapperLSeconds %10; + int secondsL = (gbDataTAMA5.mapperLSeconds % 10); + int secondsH = (gbDataTAMA5.mapperLSeconds / 10); + int minutes = (gbDataTAMA5.mapperLMinutes / 10)*16 + gbDataTAMA5.mapperLMinutes %10; + int hours = (gbDataTAMA5.mapperLHours / 10)*16 + gbDataTAMA5.mapperLHours %10; + int DaysL = gbDataTAMA5.mapperLDays % 10; + int DaysH = gbDataTAMA5.mapperLDays /10; + int MonthsL = gbDataTAMA5.mapperLMonths % 10; + int MonthsH = gbDataTAMA5.mapperLMonths / 10; + int Years3 = (gbDataTAMA5.mapperLYears / 100) % 10; + int Years4 = (gbDataTAMA5.mapperLYears / 1000); + + switch (data & 0x0f) + { + // I guess cases 0 and 1 are used for secondsL and secondsH + // so the game would update the timer values on screen when + // the seconds reset to 0... ? + case 0x0: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = secondsL; + break; + case 0x1: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = secondsH; + break; + case 0x7: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = DaysL; // days low + break; + case 0x8: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = DaysH; // days high + break; + case 0x9: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = MonthsL; // month low + break; + case 0xa: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = MonthsH; // month high + break; + case 0xb: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = Years4; // years 4th digit + break; + case 0xc: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = Years3; // years 3rd digit + break; + default : + break; + } + + gbTAMA5ram[0x54] = seconds; // incorrect ? (not used by the game) ? + gbTAMA5ram[0x64] = minutes; + gbTAMA5ram[0x74] = hours; + gbTAMA5ram[0x84] = DaysH*16+DaysL; // incorrect ? (not used by the game) ? + gbTAMA5ram[0x94] = MonthsH*16+MonthsL; // incorrect ? (not used by the game) ? + + time(&gbDataTAMA5.mapperLastTime); + + gbMemoryMap[0xa][0] = 1; + } + else if (gbDataTAMA5.mapperRamByteSelect == 0x28) // Timer stuff again + { + if ((data & 0xf) == 0xb) + gbDataTAMA5.mapperYears = ((gbDataTAMA5.mapperYears>>2)<<2) + (data & 3); + } + else if (gbDataTAMA5.mapperRamByteSelect == 0x44) + { + gbDataTAMA5.mapperMinutes = (data/16)*10 + data%16; + } + else if (gbDataTAMA5.mapperRamByteSelect == 0x54) + { + gbDataTAMA5.mapperHours = (data/16)*10 + data%16; + } + else + { + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = data; + } + } + } + } + break; + case 1: // 'Commands' Register + { + gbMemoryMap[0xa][1] = gbDataTAMA5.mapperCommandNumber = value; + + // This should be only a 'is the flashrom ready ?' command. + // However as I couldn't find any 'copy' command + // (that seems to be needed for the saving system to work) + // I put it there... + if (value == 0x0a) + { + for (int i = 0; i<0x10; i++) + for (int j = 0; j<0x10; j++) + if (!(j&2)) + gbTAMA5ram[(i*0x10)+j | 2] = gbTAMA5ram[(i*0x10)+j]; + // Enable this to see the content of the flashrom in 0xe000 + /*for (int k = 0; k<0x100; k++) + gbMemoryMap[0xe][k] = gbTAMA5ram[k];*/ + + gbMemoryMap[0xa][0] = gbDataTAMA5.mapperRAMEnable = 1; + } + else + { + if ((value & 0x0e) == 0x0c) + { + gbDataTAMA5.mapperRamByteSelect = gbDataTAMA5.mapperCommands[6] | + (gbDataTAMA5.mapperCommands[7]<<4); + + u8 byte = gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect]; + + gbMemoryMap[0xa][0] = (value & 1) ? byte >> 4 : byte & 0x0f; + + gbDataTAMA5.mapperCommands[0x0f] = 0; + } + } + break; + } + } + } + else + { + if(gbDataTAMA5.mapperRAMEnable) { + if(gbDataTAMA5.mapperRAMBank != -1) { + if(gbRamSize) { + gbMemoryMap[address>>12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } + } + } +} + + +// TAMA5 read RAM +u8 mapperTAMA5ReadRAM(u16 address) +{ + return gbMemoryMap[address>>12][address & 0xfff]; +} + + +void memoryUpdateMapTAMA5() +{ + int tmpAddress = (gbDataTAMA5.mapperROMBank << 14); + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + if(gbRamSize) { + tmpAddress = 0 << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } +} + +// MMM01 Used in Momotarou collection (however the rom is corrupted) +mapperMMM01 gbDataMMM01 ={ + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // memory model + 0, // ROM high address + 0, // RAM address + 0 // Rom Bank 0 remapping +}; + +// MMM01 ROM write registers +void mapperMMM01ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch(address & 0x6000) { + case 0x0000: // RAM enable register + gbDataMMM01.mapperRAMEnable = ( ( value & 0x0a) == 0x0a ? 1 : 0); + break; + case 0x2000: // ROM bank select + // value = value & 0x1f; + if(value == 0) + value = 1; + if(value == gbDataMMM01.mapperROMBank) + break; + + tmpAddress = value << 14; + + // check current model + if(gbDataMMM01.mapperMemoryModel == 0) { + // model is 16/8, so we have a high address in use + tmpAddress |= (gbDataMMM01.mapperROMHighAddress) << 19; + } + else + tmpAddress |= gbDataMMM01.mapperRomBank0Remapping << 18; + + tmpAddress &= gbRomSizeMask; + gbDataMMM01.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + break; + case 0x4000: // RAM bank select + if(gbDataMMM01.mapperMemoryModel == 1) { + // 4/32 model, RAM bank switching provided + value = value & 0x03; + if(value == gbDataMBC1.mapperRAMBank) + break; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + gbDataMMM01.mapperRAMBank = value; + gbDataMMM01.mapperRAMAddress = tmpAddress; + } else { + // 16/8, set the high address + gbDataMMM01.mapperROMHighAddress = value & 0x03; + tmpAddress = gbDataMMM01.mapperROMBank << 14; + tmpAddress |= (gbDataMMM01.mapperROMHighAddress) << 19; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + gbDataMMM01.mapperRomBank0Remapping = ((value<<1) | (value & 0x40 ? 1 : 0)) & 0xff; + tmpAddress = gbDataMMM01.mapperRomBank0Remapping << 18; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x00] = &gbRom[tmpAddress]; + gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; + } + break; + case 0x6000: // memory model select + gbDataMMM01.mapperMemoryModel = value & 1; + break; + } +} + +// MMM01 RAM write +void mapperMMM01RAM(u16 address, u8 value) +{ + if(gbDataMMM01.mapperRAMEnable) { + if(gbRamSize) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } +} + +void memoryUpdateMapMMM01() +{ + int tmpAddress = gbDataMMM01.mapperROMBank << 14; + + // check current model + if(gbDataMMM01.mapperMemoryModel == 1) { + // model is 16/8, so we have a high address in use + tmpAddress |= (gbDataMMM01.mapperROMHighAddress) << 19; + } + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + tmpAddress = gbDataMMM01.mapperRomBank0Remapping << 18; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x00] = &gbRom[tmpAddress]; + gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; + + if(gbRamSize) { + gbMemoryMap[0x0a] = &gbRam[gbDataMMM01.mapperRAMAddress]; + gbMemoryMap[0x0b] = &gbRam[gbDataMMM01.mapperRAMAddress + 0x1000]; + } +} + +// GameGenie ROM write registers +void mapperGGROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch(address & 0x6000) { + case 0x0000: // RAM enable register + break; + case 0x2000: // GameGenie has only a half bank + break; + case 0x4000: // GameGenie has no RAM + if ((address >=0x4001) && (address <= 0x4020)) // GG Hardware Registers + gbMemoryMap[address >> 12][address & 0x0fff] = value; + break; + case 0x6000: // GameGenie has only a half bank + break; + } +} + + +// GS3 Used to emulate the GS V3.0 rom bank switching +mapperGS3 gbDataGS3 = { 1 }; // ROM bank + +void mapperGS3ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch(address & 0x6000) { + case 0x0000: // GS has no ram + break; + case 0x2000: // GS has no 'classic' ROM bank select + break; + case 0x4000: // GS has no ram + break; + case 0x6000: // 0x6000 area is RW, and used for GS hardware registers + + if (address == 0x7FE1) // This is the (half) ROM bank select register + { + if(value == gbDataGS3.mapperROMBank) + break; + tmpAddress = value << 13; + + tmpAddress &= gbRomSizeMask; + gbDataGS3.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + } + else + gbMemoryMap[address>>12][address & 0x0fff] = value; + break; + } +} + +void memoryUpdateMapGS3() +{ + int tmpAddress = gbDataGS3.mapperROMBank << 13; + + tmpAddress &= gbRomSizeMask; + // GS can only change a half ROM bank + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; +} diff --git a/src/dmg/gbMemory.h b/src/dmg/gbMemory.h index 1032639c..ef714d19 100644 --- a/src/dmg/gbMemory.h +++ b/src/dmg/gbMemory.h @@ -1,206 +1,206 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004-2006 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include - -struct mapperMBC1 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperMemoryModel; - int mapperROMHighAddress; - int mapperRAMAddress; - int mapperRomBank0Remapping; -}; - -struct mapperMBC2 { - int mapperRAMEnable; - int mapperROMBank; -}; - -struct mapperMBC3 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperRAMAddress; - int mapperClockLatch; - int mapperClockRegister; - int mapperSeconds; - int mapperMinutes; - int mapperHours; - int mapperDays; - int mapperControl; - int mapperLSeconds; - int mapperLMinutes; - int mapperLHours; - int mapperLDays; - int mapperLControl; - time_t mapperLastTime; -}; - -struct mapperMBC5 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperROMHighAddress; - int mapperRAMAddress; - int isRumbleCartridge; -}; - -struct mapperMBC7 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperRAMAddress; - int cs; - int sk; - int state; - int buffer; - int idle; - int count; - int code; - int address; - int writeEnable; - int value; -}; - -struct mapperHuC1 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperMemoryModel; - int mapperROMHighAddress; - int mapperRAMAddress; -}; - -struct mapperHuC3 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperRAMAddress; - int mapperAddress; - int mapperRAMFlag; - int mapperRAMValue; - int mapperRegister1; - int mapperRegister2; - int mapperRegister3; - int mapperRegister4; - int mapperRegister5; - int mapperRegister6; - int mapperRegister7; - int mapperRegister8; -}; - -struct mapperTAMA5 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperRAMAddress; - int mapperRamByteSelect; - int mapperCommandNumber; - int mapperLastCommandNumber; - int mapperCommands[0x10]; - int mapperRegister; - int mapperClockLatch; - int mapperClockRegister; - int mapperSeconds; - int mapperMinutes; - int mapperHours; - int mapperDays; - int mapperMonths; - int mapperYears; - int mapperControl; - int mapperLSeconds; - int mapperLMinutes; - int mapperLHours; - int mapperLDays; - int mapperLMonths; - int mapperLYears; - int mapperLControl; - time_t mapperLastTime; -}; - -struct mapperMMM01 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperMemoryModel; - int mapperROMHighAddress; - int mapperRAMAddress; - int mapperRomBank0Remapping; -}; - -struct mapperGS3 { - int mapperROMBank; -}; - -extern mapperMBC1 gbDataMBC1; -extern mapperMBC2 gbDataMBC2; -extern mapperMBC3 gbDataMBC3; -extern mapperMBC5 gbDataMBC5; -extern mapperHuC1 gbDataHuC1; -extern mapperHuC3 gbDataHuC3; -extern mapperTAMA5 gbDataTAMA5; -extern mapperMMM01 gbDataMMM01; -extern mapperGS3 gbDataGS3; - -void mapperMBC1ROM(u16,u8); -void mapperMBC1RAM(u16,u8); -u8 mapperMBC1ReadRAM(u16); -void mapperMBC2ROM(u16,u8); -void mapperMBC2RAM(u16,u8); -void mapperMBC3ROM(u16,u8); -void mapperMBC3RAM(u16,u8); -u8 mapperMBC3ReadRAM(u16); -void mapperMBC5ROM(u16,u8); -void mapperMBC5RAM(u16,u8); -u8 mapperMBC5ReadRAM(u16); -void mapperMBC7ROM(u16,u8); -void mapperMBC7RAM(u16,u8); -u8 mapperMBC7ReadRAM(u16); -void mapperHuC1ROM(u16,u8); -void mapperHuC1RAM(u16,u8); -void mapperHuC3ROM(u16,u8); -void mapperHuC3RAM(u16,u8); -u8 mapperHuC3ReadRAM(u16); -void mapperTAMA5RAM(u16,u8); -u8 mapperTAMA5ReadRAM(u16); -void memoryUpdateTAMA5Clock(); -void mapperMMM01ROM(u16,u8); -void mapperMMM01RAM(u16,u8); -void mapperGGROM(u16,u8); -void mapperGS3ROM(u16,u8); -//extern void (*mapper)(u16,u8); -//extern void (*mapperRAM)(u16,u8); -//extern u8 (*mapperReadRAM)(u16); - -extern void memoryUpdateMapMBC1(); -extern void memoryUpdateMapMBC2(); -extern void memoryUpdateMapMBC3(); -extern void memoryUpdateMapMBC5(); -extern void memoryUpdateMapMBC7(); -extern void memoryUpdateMapHuC1(); -extern void memoryUpdateMapHuC3(); -extern void memoryUpdateMapTAMA5(); -extern void memoryUpdateMapMMM01(); -extern void memoryUpdateMapGS3(); - - - - +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004-2006 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include + +struct mapperMBC1 { + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperMemoryModel; + int mapperROMHighAddress; + int mapperRAMAddress; + int mapperRomBank0Remapping; +}; + +struct mapperMBC2 { + int mapperRAMEnable; + int mapperROMBank; +}; + +struct mapperMBC3 { + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperRAMAddress; + int mapperClockLatch; + int mapperClockRegister; + int mapperSeconds; + int mapperMinutes; + int mapperHours; + int mapperDays; + int mapperControl; + int mapperLSeconds; + int mapperLMinutes; + int mapperLHours; + int mapperLDays; + int mapperLControl; + time_t mapperLastTime; +}; + +struct mapperMBC5 { + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperROMHighAddress; + int mapperRAMAddress; + int isRumbleCartridge; +}; + +struct mapperMBC7 { + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperRAMAddress; + int cs; + int sk; + int state; + int buffer; + int idle; + int count; + int code; + int address; + int writeEnable; + int value; +}; + +struct mapperHuC1 { + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperMemoryModel; + int mapperROMHighAddress; + int mapperRAMAddress; +}; + +struct mapperHuC3 { + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperRAMAddress; + int mapperAddress; + int mapperRAMFlag; + int mapperRAMValue; + int mapperRegister1; + int mapperRegister2; + int mapperRegister3; + int mapperRegister4; + int mapperRegister5; + int mapperRegister6; + int mapperRegister7; + int mapperRegister8; +}; + +struct mapperTAMA5 { + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperRAMAddress; + int mapperRamByteSelect; + int mapperCommandNumber; + int mapperLastCommandNumber; + int mapperCommands[0x10]; + int mapperRegister; + int mapperClockLatch; + int mapperClockRegister; + int mapperSeconds; + int mapperMinutes; + int mapperHours; + int mapperDays; + int mapperMonths; + int mapperYears; + int mapperControl; + int mapperLSeconds; + int mapperLMinutes; + int mapperLHours; + int mapperLDays; + int mapperLMonths; + int mapperLYears; + int mapperLControl; + time_t mapperLastTime; +}; + +struct mapperMMM01 { + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperMemoryModel; + int mapperROMHighAddress; + int mapperRAMAddress; + int mapperRomBank0Remapping; +}; + +struct mapperGS3 { + int mapperROMBank; +}; + +extern mapperMBC1 gbDataMBC1; +extern mapperMBC2 gbDataMBC2; +extern mapperMBC3 gbDataMBC3; +extern mapperMBC5 gbDataMBC5; +extern mapperHuC1 gbDataHuC1; +extern mapperHuC3 gbDataHuC3; +extern mapperTAMA5 gbDataTAMA5; +extern mapperMMM01 gbDataMMM01; +extern mapperGS3 gbDataGS3; + +void mapperMBC1ROM(u16,u8); +void mapperMBC1RAM(u16,u8); +u8 mapperMBC1ReadRAM(u16); +void mapperMBC2ROM(u16,u8); +void mapperMBC2RAM(u16,u8); +void mapperMBC3ROM(u16,u8); +void mapperMBC3RAM(u16,u8); +u8 mapperMBC3ReadRAM(u16); +void mapperMBC5ROM(u16,u8); +void mapperMBC5RAM(u16,u8); +u8 mapperMBC5ReadRAM(u16); +void mapperMBC7ROM(u16,u8); +void mapperMBC7RAM(u16,u8); +u8 mapperMBC7ReadRAM(u16); +void mapperHuC1ROM(u16,u8); +void mapperHuC1RAM(u16,u8); +void mapperHuC3ROM(u16,u8); +void mapperHuC3RAM(u16,u8); +u8 mapperHuC3ReadRAM(u16); +void mapperTAMA5RAM(u16,u8); +u8 mapperTAMA5ReadRAM(u16); +void memoryUpdateTAMA5Clock(); +void mapperMMM01ROM(u16,u8); +void mapperMMM01RAM(u16,u8); +void mapperGGROM(u16,u8); +void mapperGS3ROM(u16,u8); +//extern void (*mapper)(u16,u8); +//extern void (*mapperRAM)(u16,u8); +//extern u8 (*mapperReadRAM)(u16); + +extern void memoryUpdateMapMBC1(); +extern void memoryUpdateMapMBC2(); +extern void memoryUpdateMapMBC3(); +extern void memoryUpdateMapMBC5(); +extern void memoryUpdateMapMBC7(); +extern void memoryUpdateMapHuC1(); +extern void memoryUpdateMapHuC3(); +extern void memoryUpdateMapTAMA5(); +extern void memoryUpdateMapMMM01(); +extern void memoryUpdateMapGS3(); + + + + diff --git a/src/dmg/gbPrinter.cpp b/src/dmg/gbPrinter.cpp index 3c2f2872..c3fda855 100644 --- a/src/dmg/gbPrinter.cpp +++ b/src/dmg/gbPrinter.cpp @@ -1,229 +1,229 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include -#include -#include "../agb/GBA.h" - -u8 gbPrinterStatus = 0; -int gbPrinterState = 0; -u8 gbPrinterData[0x280*9]; -u8 gbPrinterPacket[0x400]; -int gbPrinterCount = 0; -int gbPrinterDataCount = 0; -int gbPrinterDataSize = 0; -int gbPrinterResult = 0; - -bool gbPrinterCheckCRC() -{ - u16 crc = 0; - - for(int i = 2; i < (6+gbPrinterDataSize); i++) { - crc += gbPrinterPacket[i]; - } - - int msgCrc = gbPrinterPacket[6+gbPrinterDataSize] + - (gbPrinterPacket[7+gbPrinterDataSize]<<8); - - return msgCrc == crc; -} - -void gbPrinterReset() -{ - gbPrinterState = 0; - gbPrinterDataSize = 0; - gbPrinterDataCount = 0; - gbPrinterCount = 0; - gbPrinterStatus = 0; - gbPrinterResult = 0; -} - -void gbPrinterShowData() -{ - systemGbPrint(gbPrinterData, - gbPrinterPacket[6], - gbPrinterPacket[7], - gbPrinterPacket[8], - gbPrinterPacket[9]); - /* - allegro_init(); - install_keyboard(); - set_gfx_mode(GFX_AUTODETECT, 160, 144, 0, 0); - PALETTE pal; - pal[0].r = 255; - pal[0].g = 255; - pal[0].b = 255; - pal[1].r = 168; - pal[1].g = 168; - pal[1].b = 168; - pal[2].r = 96; - pal[2].g = 96; - pal[2].b = 96; - pal[3].r = 0; - pal[3].g = 0; - pal[3].b = 0; - set_palette(pal); - acquire_screen(); - u8 *data = gbPrinterData; - for(int y = 0; y < 0x12; y++) { - for(int x = 0; x < 0x14; x++) { - for(int k = 0; k < 8; k++) { - int a = *data++; - int b = *data++; - for(int j = 0; j < 8; j++) { - int mask = 1 << (7-j); - int c = 0; - if(a & mask) - c++; - if(b & mask) - c+=2; - putpixel(screen, x*8+j, y*8+k, c); - } - } - } - } - release_screen(); - while(!keypressed()) { - } - */ -} - -void gbPrinterReceiveData() -{ - if(gbPrinterPacket[3]) { // compressed - u8 *data = &gbPrinterPacket[6]; - u8 *dest = &gbPrinterData[gbPrinterDataCount]; - int len = 0; - while(len < gbPrinterDataSize) { - u8 control = *data++; - if(control & 0x80) { // repeated data - control &= 0x7f; - control += 2; - memset(dest, *data++, control); - len += control; - dest += control; - } else { // raw data - control++; - memcpy(dest, data, control); - dest += control; - data += control; - len += control; - } - } - } else { - memcpy(&gbPrinterData[gbPrinterDataCount], - &gbPrinterPacket[6], - gbPrinterDataSize); - gbPrinterDataCount += gbPrinterDataSize; - } -} - -void gbPrinterCommand() -{ - switch(gbPrinterPacket[2]) { - case 0x01: - // reset/initialize packet - gbPrinterDataCount = 0; - gbPrinterStatus = 0; - break; - case 0x02: - // print packet - gbPrinterShowData(); - break; - case 0x04: - // data packet - gbPrinterReceiveData(); - break; - case 0x0f: - // NUL packet - break; - } -} - -u8 gbPrinterSend(u8 b) -{ - switch(gbPrinterState) { - case 0: - gbPrinterCount = 0; - // receiving preamble - if(b == 0x88) { - gbPrinterPacket[gbPrinterCount++] = b; - gbPrinterState++; - } else { - // todo: handle failure - gbPrinterReset(); - } - break; - case 1: - // receiving preamble - if(b == 0x33) { - gbPrinterPacket[gbPrinterCount++] = b; - gbPrinterState++; - } else { - // todo: handle failure - gbPrinterReset(); - } - break; - case 2: - // receiving header - gbPrinterPacket[gbPrinterCount++] = b; - if(gbPrinterCount == 6) { - gbPrinterState++; - gbPrinterDataSize = gbPrinterPacket[4] + (gbPrinterPacket[5]<<8); - } - break; - case 3: - // receiving data - if(gbPrinterDataSize) { - gbPrinterPacket[gbPrinterCount++] = b; - if(gbPrinterCount == (6+gbPrinterDataSize)) { - gbPrinterState++; - } - break; - } - gbPrinterState++; - // intentionally move to next if no data to receive - case 4: - // receiving CRC - gbPrinterPacket[gbPrinterCount++] = b; - gbPrinterState++; - break; - case 5: - // receiving CRC-2 - gbPrinterPacket[gbPrinterCount++] = b; - if(gbPrinterCheckCRC()) { - gbPrinterCommand(); - } - gbPrinterState++; - break; - case 6: - // receiving dummy 1 - gbPrinterPacket[gbPrinterCount++] = b; - gbPrinterResult = 0x81; - gbPrinterState++; - break; - case 7: - // receiving dummy 2 - gbPrinterPacket[gbPrinterCount++] = b; - gbPrinterResult = gbPrinterStatus; - gbPrinterState = 0; - gbPrinterCount = 0; - break; - } - return gbPrinterResult; -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include +#include "../agb/GBA.h" + +u8 gbPrinterStatus = 0; +int gbPrinterState = 0; +u8 gbPrinterData[0x280*9]; +u8 gbPrinterPacket[0x400]; +int gbPrinterCount = 0; +int gbPrinterDataCount = 0; +int gbPrinterDataSize = 0; +int gbPrinterResult = 0; + +bool gbPrinterCheckCRC() +{ + u16 crc = 0; + + for(int i = 2; i < (6+gbPrinterDataSize); i++) { + crc += gbPrinterPacket[i]; + } + + int msgCrc = gbPrinterPacket[6+gbPrinterDataSize] + + (gbPrinterPacket[7+gbPrinterDataSize]<<8); + + return msgCrc == crc; +} + +void gbPrinterReset() +{ + gbPrinterState = 0; + gbPrinterDataSize = 0; + gbPrinterDataCount = 0; + gbPrinterCount = 0; + gbPrinterStatus = 0; + gbPrinterResult = 0; +} + +void gbPrinterShowData() +{ + systemGbPrint(gbPrinterData, + gbPrinterPacket[6], + gbPrinterPacket[7], + gbPrinterPacket[8], + gbPrinterPacket[9]); + /* + allegro_init(); + install_keyboard(); + set_gfx_mode(GFX_AUTODETECT, 160, 144, 0, 0); + PALETTE pal; + pal[0].r = 255; + pal[0].g = 255; + pal[0].b = 255; + pal[1].r = 168; + pal[1].g = 168; + pal[1].b = 168; + pal[2].r = 96; + pal[2].g = 96; + pal[2].b = 96; + pal[3].r = 0; + pal[3].g = 0; + pal[3].b = 0; + set_palette(pal); + acquire_screen(); + u8 *data = gbPrinterData; + for(int y = 0; y < 0x12; y++) { + for(int x = 0; x < 0x14; x++) { + for(int k = 0; k < 8; k++) { + int a = *data++; + int b = *data++; + for(int j = 0; j < 8; j++) { + int mask = 1 << (7-j); + int c = 0; + if(a & mask) + c++; + if(b & mask) + c+=2; + putpixel(screen, x*8+j, y*8+k, c); + } + } + } + } + release_screen(); + while(!keypressed()) { + } + */ +} + +void gbPrinterReceiveData() +{ + if(gbPrinterPacket[3]) { // compressed + u8 *data = &gbPrinterPacket[6]; + u8 *dest = &gbPrinterData[gbPrinterDataCount]; + int len = 0; + while(len < gbPrinterDataSize) { + u8 control = *data++; + if(control & 0x80) { // repeated data + control &= 0x7f; + control += 2; + memset(dest, *data++, control); + len += control; + dest += control; + } else { // raw data + control++; + memcpy(dest, data, control); + dest += control; + data += control; + len += control; + } + } + } else { + memcpy(&gbPrinterData[gbPrinterDataCount], + &gbPrinterPacket[6], + gbPrinterDataSize); + gbPrinterDataCount += gbPrinterDataSize; + } +} + +void gbPrinterCommand() +{ + switch(gbPrinterPacket[2]) { + case 0x01: + // reset/initialize packet + gbPrinterDataCount = 0; + gbPrinterStatus = 0; + break; + case 0x02: + // print packet + gbPrinterShowData(); + break; + case 0x04: + // data packet + gbPrinterReceiveData(); + break; + case 0x0f: + // NUL packet + break; + } +} + +u8 gbPrinterSend(u8 b) +{ + switch(gbPrinterState) { + case 0: + gbPrinterCount = 0; + // receiving preamble + if(b == 0x88) { + gbPrinterPacket[gbPrinterCount++] = b; + gbPrinterState++; + } else { + // todo: handle failure + gbPrinterReset(); + } + break; + case 1: + // receiving preamble + if(b == 0x33) { + gbPrinterPacket[gbPrinterCount++] = b; + gbPrinterState++; + } else { + // todo: handle failure + gbPrinterReset(); + } + break; + case 2: + // receiving header + gbPrinterPacket[gbPrinterCount++] = b; + if(gbPrinterCount == 6) { + gbPrinterState++; + gbPrinterDataSize = gbPrinterPacket[4] + (gbPrinterPacket[5]<<8); + } + break; + case 3: + // receiving data + if(gbPrinterDataSize) { + gbPrinterPacket[gbPrinterCount++] = b; + if(gbPrinterCount == (6+gbPrinterDataSize)) { + gbPrinterState++; + } + break; + } + gbPrinterState++; + // intentionally move to next if no data to receive + case 4: + // receiving CRC + gbPrinterPacket[gbPrinterCount++] = b; + gbPrinterState++; + break; + case 5: + // receiving CRC-2 + gbPrinterPacket[gbPrinterCount++] = b; + if(gbPrinterCheckCRC()) { + gbPrinterCommand(); + } + gbPrinterState++; + break; + case 6: + // receiving dummy 1 + gbPrinterPacket[gbPrinterCount++] = b; + gbPrinterResult = 0x81; + gbPrinterState++; + break; + case 7: + // receiving dummy 2 + gbPrinterPacket[gbPrinterCount++] = b; + gbPrinterResult = gbPrinterStatus; + gbPrinterState = 0; + gbPrinterCount = 0; + break; + } + return gbPrinterResult; +} diff --git a/src/dmg/gbPrinter.h b/src/dmg/gbPrinter.h index 20a97659..9bebd4e3 100644 --- a/src/dmg/gbPrinter.h +++ b/src/dmg/gbPrinter.h @@ -1,20 +1,20 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -extern u8 gbPrinterSend(u8 b); +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +extern u8 gbPrinterSend(u8 b); diff --git a/src/dmg/gbSGB.cpp b/src/dmg/gbSGB.cpp index d10c0cd1..677d1ad9 100644 --- a/src/dmg/gbSGB.cpp +++ b/src/dmg/gbSGB.cpp @@ -1,917 +1,917 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005-2006 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include -#include - -#include "../System.h" -#include "../Port.h" -#include "../Util.h" -#include "gb.h" -#include "gbGlobals.h" - -extern u8 *pix; -extern bool speedup; -extern bool gbSgbResetFlag; - -#define GBSGB_NONE 0 -#define GBSGB_RESET 1 -#define GBSGB_PACKET_TRANSMIT 2 - -u8 *gbSgbBorderChar = NULL; -u8 *gbSgbBorder = NULL; - -int gbSgbCGBSupport = 0; -int gbSgbMask = 0; -int gbSgbMode = 0; -int gbSgbPacketState = GBSGB_NONE; -int gbSgbBit = 0; -int gbSgbPacketTimeout = 0; -int GBSGB_PACKET_TIMEOUT = 66666; -u8 gbSgbPacket[16*7]; -int gbSgbPacketNBits = 0; -int gbSgbPacketByte = 0; -int gbSgbPacketNumber = 0; -int gbSgbMultiplayer = 0; -int gbSgbFourPlayers = 0; -u8 gbSgbNextController = 0x0f; -u8 gbSgbReadingController = 0; -u16 gbSgbSCPPalette[4*512]; -u8 gbSgbATF[20 * 18]; -u8 gbSgbATFList[45 * 20 * 18]; -u8 gbSgbScreenBuffer[4160]; - -inline void gbSgbDraw24Bit(u8 *p, u16 v) -{ - *((u32*) p) = systemColorMap32[v]; -} - -inline void gbSgbDraw32Bit(u32 *p, u16 v) -{ - *p = systemColorMap32[v]; -} - -inline void gbSgbDraw16Bit(u16 *p, u16 v) -{ - *p = systemColorMap16[v]; -} - -void gbSgbReset() -{ - gbSgbPacketTimeout = 0; - gbSgbCGBSupport = 0; - gbSgbMask = 0; - gbSgbPacketState = GBSGB_NONE; - gbSgbBit = 0; - gbSgbPacketNBits = 0; - gbSgbPacketNumber = 0; - gbSgbMultiplayer = 0; - gbSgbFourPlayers = 0; - gbSgbNextController = 0x0f; - gbSgbReadingController = 0; - - memset(gbSgbSCPPalette, 0, 512*4); - memset(gbSgbATF, 0, 20*18); - memset(gbSgbATFList, 0, 45 * 20 * 18); - memset(gbSgbPacket, 0, 16 * 7); - memset(gbSgbBorderChar, 0, 32*256); - memset(gbSgbBorder, 0, 2048); - - int i; - for(i = 1; i < 2048; i+=2) { - gbSgbBorder[i] = 1 << 2; - } - - for(i = 0; i < 32; i++) { - gbPalette[i*4] = (0x1f) | (0x1f << 5) | (0x1f << 10); - gbPalette[i*4+1] = (0x15) | (0x15 << 5) | (0x15 << 10); - gbPalette[i*4+2] = (0x0c) | (0x0c << 5) | (0x0c << 10); - gbPalette[i*4+3] = 0; - } -} - -void gbSgbInit() -{ - gbSgbBorderChar = (u8 *)malloc(32 * 256); - gbSgbBorder = (u8 *)malloc(2048); - - gbSgbReset(); -} - -void gbSgbShutdown() -{ - if(gbSgbBorderChar != NULL) { - free(gbSgbBorderChar); - gbSgbBorderChar = NULL; - } - - if(gbSgbBorder != NULL) { - free(gbSgbBorder); - gbSgbBorder = NULL; - } -} - -void gbSgbFillScreen(u16 color) -{ - switch(systemColorDepth) { - case 16: - { - for(int y = 0; y < 144; y++) { - int yLine = (y+gbBorderRowSkip+1)*(gbBorderLineSkip+2) + - gbBorderColumnSkip; - u16 *dest = (u16*)pix + yLine; - for(register int x = 0; x < 160; x++) - gbSgbDraw16Bit(dest++, color); - } - } - break; - case 24: - { - for(int y = 0; y < 144; y++) { - int yLine = (y+gbBorderRowSkip)*gbBorderLineSkip + gbBorderColumnSkip; - u8 *dest = (u8 *)pix + yLine*3; - for(register int x = 0; x < 160; x++) { - gbSgbDraw24Bit(dest, color); - dest += 3; - } - } - } - break; - case 32: - { - for(int y = 0; y < 144; y++) { - int yLine = (y+gbBorderRowSkip+1)*(gbBorderLineSkip+1) + gbBorderColumnSkip; - u32 *dest = (u32 *)pix + yLine; - for(register int x = 0; x < 160; x++) { - gbSgbDraw32Bit(dest++, color); - } - } - } - break; - } -} - -#define getmem(x) gbMemoryMap[(x) >> 12][(x) & 0xfff] - -void gbSgbRenderScreenToBuffer() -{ - u16 mapAddress = 0x9800; - - if(register_LCDC & 0x08) - mapAddress = 0x9c00; - - u16 patternAddress = 0x8800; - - int flag = 1; - - if(register_LCDC & 0x10) { - patternAddress = 0x8000; - flag = 0; - } - - u8 *toAddress = gbSgbScreenBuffer; - - for(int i = 0; i < 13; i++) { - for(int j = 0; j < 20; j++) { - int tile = getmem(mapAddress); - mapAddress++; - - if(flag) { - if(tile > 127) - tile -= 128; - else - tile += 128; - } - for(int k = 0; k < 16; k++) - *toAddress++ = getmem(patternAddress + tile*16 + k); - } - mapAddress += 12; - } -} - -void gbSgbDrawBorderTile(int x, int y, int tile, int attr) -{ - u16 *dest = (u16*)pix + ((y+1) * (256+2)) + x; - u8 *dest8 = (u8*)pix + ((y*256)+x)*3; - u32 *dest32 = (u32*)pix + ((y+1)*257) + x; - - u8 *tileAddress = &gbSgbBorderChar[tile * 32]; - u8 *tileAddress2 = &gbSgbBorderChar[tile * 32 + 16]; - - u8 l = 8; - - u8 palette = ((attr >> 2 ) & 7); - - if(palette < 4) - palette += 4; - - palette *= 16; - - u8 xx = 0; - u8 yy = 0; - - int flipX = attr & 0x40; - int flipY = attr & 0x80; - - while(l > 0) { - u8 mask = 0x80; - u8 a = *tileAddress++; - u8 b = *tileAddress++; - u8 c = *tileAddress2++; - u8 d = *tileAddress2++; - - while(mask > 0) { - - u8 color = 0; - if(a & mask) - color++; - if(b & mask) - color+=2; - if(c & mask) - color+=4; - if(d & mask) - color+=8; - - u8 xxx = xx; - u8 yyy = yy; - - if(flipX) - xxx = 7 - xx; - if(flipY) - yyy = 7 - yy; - - u16 c = gbPalette[palette + color]; - - // Fix for Super Snaky ??? - // (it allows SGB borders to not redraw on the GB screen) - //if(!color) - // c = gbPalette[0]; - if(((yy < 40 || yy >= 184) || (xx < 48 || xx >= 208)) && (color || (gbSgbResetFlag == true))) { - switch(systemColorDepth) { - case 16: - gbSgbDraw16Bit(dest + yyy*(256+2) + xxx, c); - break; - case 24: - gbSgbDraw24Bit(dest8 + (yyy*256+xxx)*3, c); - break; - case 32: - gbSgbDraw32Bit(dest32 + yyy*(256+1)+xxx, c); - break; - } - } - - mask >>= 1; - - xx++; - } - yy++; - xx = 0; - l--; - mask = 0x80; - } -} - -void gbSgbRenderBorder() -{ - if(gbBorderOn) { - u8 *fromAddress = gbSgbBorder; - - for(u8 y = 0; y < 28; y++) { - for(u8 x = 0; x< 32; x++) { - u8 tile = *fromAddress++; - u8 attr = *fromAddress++; - - gbSgbDrawBorderTile(x*8,y*8,tile,attr); - } - } - } -} - -void gbSgbPicture() -{ - gbSgbRenderScreenToBuffer(); - - memcpy(gbSgbBorder, gbSgbScreenBuffer, 2048); - - u16 *paletteAddr = (u16 *)&gbSgbScreenBuffer[2048]; - - for(int i = 64; i < 128; i++) { - gbPalette[i] = READ16LE(paletteAddr++); - } - - gbSgbCGBSupport |= 4; - - if(gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4) { - gbBorderOn = 1; - systemGbBorderOn(); - } - - if(gbBorderOn && !gbSgbMask) - gbSgbRenderBorder(); - - if(gbSgbMode && gbCgbMode && gbSgbCGBSupport > 4) { - gbSgbCGBSupport = 0; - gbSgbMode = 0; - gbSgbMask = 0; - gbSgbRenderBorder(); - gbReset(); - } - - if(gbSgbCGBSupport > 4) - gbSgbCGBSupport = 0; -} - -void gbSgbSetPalette(int a,int b,u16 *p) -{ - u16 bit00 = READ16LE(p++); - int i; - - for(i = 1; i < 4; i++) { - gbPalette[a*4+i] = READ16LE(p++); - } - - for(i = 1; i < 4; i++) { - gbPalette[b*4+i] = READ16LE(p++); - } - - gbPalette[0] = gbPalette[4] = gbPalette[8] = gbPalette[12] = bit00; - if(gbBorderOn && !gbSgbMask) - gbSgbRenderBorder(); -} - -void gbSgbScpPalette() -{ - gbSgbRenderScreenToBuffer(); - - u16 *fromAddress = (u16 *)gbSgbScreenBuffer; - - for(int i = 0; i < 512*4; i++) { - gbSgbSCPPalette[i] = READ16LE(fromAddress++); - } -} - -void gbSgbSetATF(int n) -{ - if(n < 0) - n = 0; - if(n > 44) - n = 44; - memcpy(gbSgbATF,&gbSgbATFList[n * 20 * 18], 20 * 18); - - if(gbSgbPacket[1] & 0x40) { - gbSgbMask = 0; - if(gbBorderOn) - gbSgbRenderBorder(); - } -} - -void gbSgbSetPalette() -{ - u16 pal = READ16LE((((u16 *)&gbSgbPacket[1])))&511; - memcpy(&gbPalette[0], &gbSgbSCPPalette[pal*4], 4 * sizeof(u16)); - - pal = READ16LE((((u16 *)&gbSgbPacket[3])))&511; - memcpy(&gbPalette[4], &gbSgbSCPPalette[pal*4], 4 * sizeof(u16)); - - pal = READ16LE((((u16 *)&gbSgbPacket[5])))&511; - memcpy(&gbPalette[8], &gbSgbSCPPalette[pal*4], 4 * sizeof(u16)); - - pal = READ16LE((((u16 *)&gbSgbPacket[7])))&511; - memcpy(&gbPalette[12], &gbSgbSCPPalette[pal*4], 4 * sizeof(u16)); - - u8 atf = gbSgbPacket[9]; - - if(atf & 0x80) { - gbSgbSetATF(atf & 0x3f); - } - - if(atf & 0x40) { - gbSgbMask = 0; - if(gbBorderOn) - gbSgbRenderBorder(); - } -} - -void gbSgbAttributeBlock() -{ - u8 *fromAddress = &gbSgbPacket[1]; - - u8 nDataSet = *fromAddress++; - if(nDataSet > 12) - nDataSet = 12; - if(nDataSet == 0) - nDataSet = 1; - - while(nDataSet) { - u8 controlCode = (*fromAddress++) & 7; - u8 paletteDesignation = (*fromAddress++) & 0x3f; - u8 startH = (*fromAddress++) & 0x1f; - u8 startV = (*fromAddress++) & 0x1f; - u8 endH = (*fromAddress++) & 0x1f; - u8 endV = (*fromAddress++) & 0x1f; - - u8 * toAddress = gbSgbATF; - - for(u8 y = 0; y < 18; y++) { - for(u8 x = 0; x < 20; x++) { - if(x < startH || y < startV || - x > endH || y > endV) { - // outside - if(controlCode & 0x04) - *toAddress = (paletteDesignation >> 4) & 0x03; - } else if(x > startH && x < endH && - y > startV && y < endV) { - // inside - if(controlCode & 0x01) - *toAddress = paletteDesignation & 0x03; - } else { - // surrounding line - if(controlCode & 0x02) - *toAddress = (paletteDesignation>>2) & 0x03; - else if(controlCode == 0x01) - *toAddress = paletteDesignation & 0x03; - } - toAddress++; - } - } - nDataSet--; - } -} - -void gbSgbSetColumnPalette(u8 col, u8 p) -{ - // if(col < 0) - // col = 0; - if(col > 19) - col = 19; - - p &= 3; - - u8 *toAddress = &gbSgbATF[col]; - - for(u8 y = 0; y < 18; y++) { - *toAddress = p; - toAddress += 20; - } -} - -void gbSgbSetRowPalette(u8 row, u8 p) -{ - // if(row < 0) - // row = 0; - if(row > 17) - row = 17; - - p &= 3; - - u8 *toAddress = &gbSgbATF[row*20]; - - for(u8 x = 0; x < 20; x++) { - *toAddress++ = p; - } -} - -void gbSgbAttributeDivide() -{ - u8 control = gbSgbPacket[1]; - u8 coord = gbSgbPacket[2]; - u8 colorBR = control & 3; - u8 colorAL = (control >> 2) & 3; - u8 colorOL = (control >> 4) & 3; - - if(control & 0x40) { - if(coord > 17) - coord = 17; - - for(u8 i = 0; i < 18; i++) { - if(i < coord) - gbSgbSetRowPalette(i, colorAL); - else if ( i > coord) - gbSgbSetRowPalette(i, colorBR); - else - gbSgbSetRowPalette(i, colorOL); - } - } else { - if(coord > 19) - coord = 19; - - for(u8 i = 0; i < 20; i++) { - if(i < coord) - gbSgbSetColumnPalette(i, colorAL); - else if ( i > coord) - gbSgbSetColumnPalette(i, colorBR); - else - gbSgbSetColumnPalette(i, colorOL); - } - } -} - -void gbSgbAttributeLine() -{ - u8 *fromAddress = &gbSgbPacket[1]; - - u8 nDataSet = *fromAddress++; - - if(nDataSet > 0x6e) - nDataSet = 0x6e; - - while(nDataSet) { - u8 line = *fromAddress++; - u8 num = line & 0x1f; - u8 pal = (line >> 5) & 0x03; - if(line & 0x80) { - if(num > 17) - num = 17; - gbSgbSetRowPalette(num,pal); - } else { - if(num > 19) - num = 19; - gbSgbSetColumnPalette(num,pal); - } - nDataSet--; - } -} - -void gbSgbAttributeCharacter() -{ - u8 startH = gbSgbPacket[1] & 0x1f; - u8 startV = gbSgbPacket[2] & 0x1f; - int nDataSet = READ16LE(((u16 *)&gbSgbPacket[3])); - int style = gbSgbPacket[5] & 1; - if(startH > 19) - startH = 19; - if(startV > 17) - startV = 17; - - u8 s = 6; - u8 *fromAddress = &gbSgbPacket[6]; - u8 v = *fromAddress++; - - if(style) { - while(nDataSet) { - u8 p = (v >> s) & 3; - gbSgbATF[startV * 20 + startH] = p; - startV++; - if(startV == 18) { - startV = 0; - startH++; - if(startH == 20) - break; - } - - if(s) - s -= 2; - else { - s = 6; - v = *fromAddress++; - nDataSet--; - } - } - } else { - while(nDataSet) { - u8 p = (v >> s) & 3; - gbSgbATF[startV * 20 + startH] = p; - startH++; - if(startH == 20) { - startH = 0; - startV++; - if(startV == 18) - break; - } - - if(s) - s -= 2; - else { - s = 6; - v = *fromAddress++; - nDataSet--; - } - } - } -} - -void gbSgbSetATFList() -{ - gbSgbRenderScreenToBuffer(); - - u8 *fromAddress = gbSgbScreenBuffer; - u8 *toAddress = gbSgbATFList; - - for(int i = 0; i < 45; i++) { - for(int j = 0; j < 90; j++) { - u8 v = *fromAddress++; - u8 s = 6; - if(i == 2) - s = 6; - for(int k = 0; k < 4; k++) { - *toAddress++ = (v >> s) & 0x03; - s -= 2; - } - } - } -} - -void gbSgbMaskEnable() -{ - int gbSgbMaskFlag = gbSgbPacket[1] & 3; - - gbSgbMask = gbSgbMaskFlag; - - switch(gbSgbMaskFlag) { - case 1: - break; - case 2: - gbSgbFillScreen(0x0000); - // memset(&gbPalette[0], 0, 128*sizeof(u16)); - break; - case 3: - gbSgbFillScreen(gbPalette[0]); - break; - } - if(!gbSgbMask) { - if(gbBorderOn) - gbSgbRenderBorder(); - } -} - -void gbSgbChrTransfer() -{ - gbSgbRenderScreenToBuffer(); - - int address = (gbSgbPacket[1] & 1) * (128*32); - - if(gbSgbPacket[1] & 1) - gbSgbCGBSupport |= 2; - else - gbSgbCGBSupport |= 1; - - memcpy(&gbSgbBorderChar[address], gbSgbScreenBuffer, 128 * 32); - - if(gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4) { - gbBorderOn = 1; - systemGbBorderOn(); - } - - if(gbBorderOn && !gbSgbMask) - gbSgbRenderBorder(); - - if(gbSgbMode && gbCgbMode && gbSgbCGBSupport == 7) { - gbSgbCGBSupport = 0; - gbSgbMode = 0; - gbSgbMask = 0; - gbSgbRenderBorder(); - gbReset(); - } - - if(gbSgbCGBSupport > 4) - gbSgbCGBSupport = 0; -} - -void gbSgbMultiRequest() -{ - if(gbSgbPacket[1] & 1) { - gbSgbMultiplayer = 1; - if(gbSgbPacket[1] & 2) - gbSgbFourPlayers = 1; - else - gbSgbFourPlayers = 0; - gbSgbNextController = 0x0e; - } else { - gbSgbFourPlayers = 0; - gbSgbMultiplayer = 0; - gbSgbNextController = 0x0f; - } -} - -void gbSgbCommand() -{ - int command = gbSgbPacket[0] >> 3; - // int nPacket = gbSgbPacket[0] & 7; - - switch(command) { - case 0x00: - gbSgbSetPalette(0,1,(u16 *)&gbSgbPacket[1]); - break; - case 0x01: - gbSgbSetPalette(2,3,(u16 *)&gbSgbPacket[1]); - break; - case 0x02: - gbSgbSetPalette(0,3,(u16 *)&gbSgbPacket[1]); - break; - case 0x03: - gbSgbSetPalette(1,2,(u16 *)&gbSgbPacket[1]); - break; - case 0x04: - gbSgbAttributeBlock(); - break; - case 0x05: - gbSgbAttributeLine(); - break; - case 0x06: - gbSgbAttributeDivide(); - break; - case 0x07: - gbSgbAttributeCharacter(); - break; - case 0x0a: - gbSgbSetPalette(); - break; - case 0x0b: - gbSgbScpPalette(); - break; - case 0x11: - gbSgbMultiRequest(); - break; - case 0x13: - gbSgbChrTransfer(); - break; - case 0x14: - gbSgbPicture(); - break; - case 0x15: - gbSgbSetATFList(); - break; - case 0x16: - gbSgbSetATF(gbSgbPacket[1] & 0x3f); - break; - case 0x17: - gbSgbMaskEnable(); - break; - } -} - -void gbSgbResetPacketState() -{ - gbSgbPacketState = GBSGB_NONE; - gbSgbPacketTimeout = 0; -} - -void gbSgbDoBitTransfer(u8 value) -{ - value = value & 0x30; - switch(gbSgbPacketState) { - case GBSGB_NONE: - if(value == 0) { - gbSgbPacketState = GBSGB_RESET; - gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; - } else if (value == 0x30) { - if(gbSgbMultiplayer) { - if((gbSgbReadingController & 7) == 7) { - gbSgbReadingController = 0; - if(gbSgbMultiplayer) { - gbSgbNextController--; - if(gbSgbFourPlayers) { - if(gbSgbNextController == 0x0b) - gbSgbNextController = 0x0f; - } else { - if(gbSgbNextController == 0x0d) - gbSgbNextController = 0x0f; - } - } - } else { - gbSgbReadingController &= 3; - } - } - gbSgbPacketTimeout = 0; - } else { - if(value == 0x10) - gbSgbReadingController |= 0x2; - else if(value == 0x20) - gbSgbReadingController |= 0x01; - gbSgbPacketTimeout = 0; - } - gbSgbPacketTimeout = 0; - break; - case GBSGB_RESET: - if(value == 0x30) { - gbSgbPacketState = GBSGB_PACKET_TRANSMIT; - gbSgbPacketByte = 0; - gbSgbPacketNBits = 0; - gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; - } else if(value == 0x00) { - gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; - gbSgbPacketState = GBSGB_RESET; - } else { - gbSgbPacketState = GBSGB_NONE; - gbSgbPacketTimeout = 0; - } - break; - case GBSGB_PACKET_TRANSMIT: - if(value == 0) { - gbSgbPacketState = GBSGB_RESET; - gbSgbPacketTimeout = 0; - } else if (value == 0x30){ - if(gbSgbPacketNBits == 128) { - gbSgbPacketNBits = 0; - gbSgbPacketByte = 0; - gbSgbPacketNumber++; - gbSgbPacketTimeout = 0; - if(gbSgbPacketNumber == (gbSgbPacket[0] & 7)) { - gbSgbCommand(); - gbSgbPacketNumber = 0; - gbSgbPacketState = GBSGB_NONE; - gbSgbPacketTimeout = 0; - } - } else { - if(gbSgbPacketNBits < 128) { - gbSgbPacket[gbSgbPacketNumber * 16 + gbSgbPacketByte] >>= 1; - gbSgbPacket[gbSgbPacketNumber * 16 + gbSgbPacketByte] |= gbSgbBit; - gbSgbPacketNBits++; - if(!(gbSgbPacketNBits & 7)) { - gbSgbPacketByte++; - } - gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; - } - } - } else { - if(value == 0x20) - gbSgbBit = 0x00; - else - gbSgbBit = 0x80; - gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; - } - gbSgbReadingController = 0; - break; - default: - gbSgbPacketState = GBSGB_NONE; - gbSgbPacketTimeout = 0; - break; - } -} - -variable_desc gbSgbSaveStruct[] = { - { &gbSgbMask, sizeof(int) }, - { &gbSgbPacketState, sizeof(int) }, - { &gbSgbBit, sizeof(int) }, - { &gbSgbPacketNBits, sizeof(int) }, - { &gbSgbPacketByte, sizeof(int) }, - { &gbSgbPacketNumber, sizeof(int) }, - { &gbSgbMultiplayer, sizeof(int) }, - { &gbSgbNextController, sizeof(u8) }, - { &gbSgbReadingController, sizeof(u8) }, - { NULL, 0 } -}; - -variable_desc gbSgbSaveStructV3[] = { - { &gbSgbMask, sizeof(int) }, - { &gbSgbPacketState, sizeof(int) }, - { &gbSgbBit, sizeof(int) }, - { &gbSgbPacketNBits, sizeof(int) }, - { &gbSgbPacketByte, sizeof(int) }, - { &gbSgbPacketNumber, sizeof(int) }, - { &gbSgbMultiplayer, sizeof(int) }, - { &gbSgbNextController, sizeof(u8) }, - { &gbSgbReadingController, sizeof(u8) }, - { &gbSgbFourPlayers, sizeof(int) }, - { NULL, 0 } -}; - -void gbSgbSaveGame(gzFile gzFile) -{ - utilWriteData(gzFile, gbSgbSaveStructV3); - - utilGzWrite(gzFile, gbSgbBorder, 2048); - utilGzWrite(gzFile, gbSgbBorderChar, 32*256); - - utilGzWrite(gzFile, gbSgbPacket, 16*7); - - utilGzWrite(gzFile, gbSgbSCPPalette, 4 * 512 * sizeof(u16)); - utilGzWrite(gzFile, gbSgbATF, 20 * 18); - utilGzWrite(gzFile, gbSgbATFList, 45 * 20 * 18); -} - -void gbSgbReadGame(gzFile gzFile, int version) -{ - if(version >= 3) - utilReadData(gzFile, gbSgbSaveStructV3); - else { - utilReadData(gzFile, gbSgbSaveStruct); - gbSgbFourPlayers = 0; - } - - if(version >= 8) { - utilGzRead(gzFile, gbSgbBorder, 2048); - utilGzRead(gzFile, gbSgbBorderChar, 32*256); - } - - utilGzRead(gzFile, gbSgbPacket, 16*7); - - utilGzRead(gzFile, gbSgbSCPPalette, 4 * 512 * sizeof(u16)); - utilGzRead(gzFile, gbSgbATF, 20 * 18); - utilGzRead(gzFile, gbSgbATFList, 45 * 20 * 18); -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include + +#include "../System.h" +#include "../Port.h" +#include "../Util.h" +#include "gb.h" +#include "gbGlobals.h" + +extern u8 *pix; +extern bool speedup; +extern bool gbSgbResetFlag; + +#define GBSGB_NONE 0 +#define GBSGB_RESET 1 +#define GBSGB_PACKET_TRANSMIT 2 + +u8 *gbSgbBorderChar = NULL; +u8 *gbSgbBorder = NULL; + +int gbSgbCGBSupport = 0; +int gbSgbMask = 0; +int gbSgbMode = 0; +int gbSgbPacketState = GBSGB_NONE; +int gbSgbBit = 0; +int gbSgbPacketTimeout = 0; +int GBSGB_PACKET_TIMEOUT = 66666; +u8 gbSgbPacket[16*7]; +int gbSgbPacketNBits = 0; +int gbSgbPacketByte = 0; +int gbSgbPacketNumber = 0; +int gbSgbMultiplayer = 0; +int gbSgbFourPlayers = 0; +u8 gbSgbNextController = 0x0f; +u8 gbSgbReadingController = 0; +u16 gbSgbSCPPalette[4*512]; +u8 gbSgbATF[20 * 18]; +u8 gbSgbATFList[45 * 20 * 18]; +u8 gbSgbScreenBuffer[4160]; + +inline void gbSgbDraw24Bit(u8 *p, u16 v) +{ + *((u32*) p) = systemColorMap32[v]; +} + +inline void gbSgbDraw32Bit(u32 *p, u16 v) +{ + *p = systemColorMap32[v]; +} + +inline void gbSgbDraw16Bit(u16 *p, u16 v) +{ + *p = systemColorMap16[v]; +} + +void gbSgbReset() +{ + gbSgbPacketTimeout = 0; + gbSgbCGBSupport = 0; + gbSgbMask = 0; + gbSgbPacketState = GBSGB_NONE; + gbSgbBit = 0; + gbSgbPacketNBits = 0; + gbSgbPacketNumber = 0; + gbSgbMultiplayer = 0; + gbSgbFourPlayers = 0; + gbSgbNextController = 0x0f; + gbSgbReadingController = 0; + + memset(gbSgbSCPPalette, 0, 512*4); + memset(gbSgbATF, 0, 20*18); + memset(gbSgbATFList, 0, 45 * 20 * 18); + memset(gbSgbPacket, 0, 16 * 7); + memset(gbSgbBorderChar, 0, 32*256); + memset(gbSgbBorder, 0, 2048); + + int i; + for(i = 1; i < 2048; i+=2) { + gbSgbBorder[i] = 1 << 2; + } + + for(i = 0; i < 32; i++) { + gbPalette[i*4] = (0x1f) | (0x1f << 5) | (0x1f << 10); + gbPalette[i*4+1] = (0x15) | (0x15 << 5) | (0x15 << 10); + gbPalette[i*4+2] = (0x0c) | (0x0c << 5) | (0x0c << 10); + gbPalette[i*4+3] = 0; + } +} + +void gbSgbInit() +{ + gbSgbBorderChar = (u8 *)malloc(32 * 256); + gbSgbBorder = (u8 *)malloc(2048); + + gbSgbReset(); +} + +void gbSgbShutdown() +{ + if(gbSgbBorderChar != NULL) { + free(gbSgbBorderChar); + gbSgbBorderChar = NULL; + } + + if(gbSgbBorder != NULL) { + free(gbSgbBorder); + gbSgbBorder = NULL; + } +} + +void gbSgbFillScreen(u16 color) +{ + switch(systemColorDepth) { + case 16: + { + for(int y = 0; y < 144; y++) { + int yLine = (y+gbBorderRowSkip+1)*(gbBorderLineSkip+2) + + gbBorderColumnSkip; + u16 *dest = (u16*)pix + yLine; + for(register int x = 0; x < 160; x++) + gbSgbDraw16Bit(dest++, color); + } + } + break; + case 24: + { + for(int y = 0; y < 144; y++) { + int yLine = (y+gbBorderRowSkip)*gbBorderLineSkip + gbBorderColumnSkip; + u8 *dest = (u8 *)pix + yLine*3; + for(register int x = 0; x < 160; x++) { + gbSgbDraw24Bit(dest, color); + dest += 3; + } + } + } + break; + case 32: + { + for(int y = 0; y < 144; y++) { + int yLine = (y+gbBorderRowSkip+1)*(gbBorderLineSkip+1) + gbBorderColumnSkip; + u32 *dest = (u32 *)pix + yLine; + for(register int x = 0; x < 160; x++) { + gbSgbDraw32Bit(dest++, color); + } + } + } + break; + } +} + +#define getmem(x) gbMemoryMap[(x) >> 12][(x) & 0xfff] + +void gbSgbRenderScreenToBuffer() +{ + u16 mapAddress = 0x9800; + + if(register_LCDC & 0x08) + mapAddress = 0x9c00; + + u16 patternAddress = 0x8800; + + int flag = 1; + + if(register_LCDC & 0x10) { + patternAddress = 0x8000; + flag = 0; + } + + u8 *toAddress = gbSgbScreenBuffer; + + for(int i = 0; i < 13; i++) { + for(int j = 0; j < 20; j++) { + int tile = getmem(mapAddress); + mapAddress++; + + if(flag) { + if(tile > 127) + tile -= 128; + else + tile += 128; + } + for(int k = 0; k < 16; k++) + *toAddress++ = getmem(patternAddress + tile*16 + k); + } + mapAddress += 12; + } +} + +void gbSgbDrawBorderTile(int x, int y, int tile, int attr) +{ + u16 *dest = (u16*)pix + ((y+1) * (256+2)) + x; + u8 *dest8 = (u8*)pix + ((y*256)+x)*3; + u32 *dest32 = (u32*)pix + ((y+1)*257) + x; + + u8 *tileAddress = &gbSgbBorderChar[tile * 32]; + u8 *tileAddress2 = &gbSgbBorderChar[tile * 32 + 16]; + + u8 l = 8; + + u8 palette = ((attr >> 2 ) & 7); + + if(palette < 4) + palette += 4; + + palette *= 16; + + u8 xx = 0; + u8 yy = 0; + + int flipX = attr & 0x40; + int flipY = attr & 0x80; + + while(l > 0) { + u8 mask = 0x80; + u8 a = *tileAddress++; + u8 b = *tileAddress++; + u8 c = *tileAddress2++; + u8 d = *tileAddress2++; + + while(mask > 0) { + + u8 color = 0; + if(a & mask) + color++; + if(b & mask) + color+=2; + if(c & mask) + color+=4; + if(d & mask) + color+=8; + + u8 xxx = xx; + u8 yyy = yy; + + if(flipX) + xxx = 7 - xx; + if(flipY) + yyy = 7 - yy; + + u16 c = gbPalette[palette + color]; + + // Fix for Super Snaky ??? + // (it allows SGB borders to not redraw on the GB screen) + //if(!color) + // c = gbPalette[0]; + if(((yy < 40 || yy >= 184) || (xx < 48 || xx >= 208)) && (color || (gbSgbResetFlag == true))) { + switch(systemColorDepth) { + case 16: + gbSgbDraw16Bit(dest + yyy*(256+2) + xxx, c); + break; + case 24: + gbSgbDraw24Bit(dest8 + (yyy*256+xxx)*3, c); + break; + case 32: + gbSgbDraw32Bit(dest32 + yyy*(256+1)+xxx, c); + break; + } + } + + mask >>= 1; + + xx++; + } + yy++; + xx = 0; + l--; + mask = 0x80; + } +} + +void gbSgbRenderBorder() +{ + if(gbBorderOn) { + u8 *fromAddress = gbSgbBorder; + + for(u8 y = 0; y < 28; y++) { + for(u8 x = 0; x< 32; x++) { + u8 tile = *fromAddress++; + u8 attr = *fromAddress++; + + gbSgbDrawBorderTile(x*8,y*8,tile,attr); + } + } + } +} + +void gbSgbPicture() +{ + gbSgbRenderScreenToBuffer(); + + memcpy(gbSgbBorder, gbSgbScreenBuffer, 2048); + + u16 *paletteAddr = (u16 *)&gbSgbScreenBuffer[2048]; + + for(int i = 64; i < 128; i++) { + gbPalette[i] = READ16LE(paletteAddr++); + } + + gbSgbCGBSupport |= 4; + + if(gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4) { + gbBorderOn = 1; + systemGbBorderOn(); + } + + if(gbBorderOn && !gbSgbMask) + gbSgbRenderBorder(); + + if(gbSgbMode && gbCgbMode && gbSgbCGBSupport > 4) { + gbSgbCGBSupport = 0; + gbSgbMode = 0; + gbSgbMask = 0; + gbSgbRenderBorder(); + gbReset(); + } + + if(gbSgbCGBSupport > 4) + gbSgbCGBSupport = 0; +} + +void gbSgbSetPalette(int a,int b,u16 *p) +{ + u16 bit00 = READ16LE(p++); + int i; + + for(i = 1; i < 4; i++) { + gbPalette[a*4+i] = READ16LE(p++); + } + + for(i = 1; i < 4; i++) { + gbPalette[b*4+i] = READ16LE(p++); + } + + gbPalette[0] = gbPalette[4] = gbPalette[8] = gbPalette[12] = bit00; + if(gbBorderOn && !gbSgbMask) + gbSgbRenderBorder(); +} + +void gbSgbScpPalette() +{ + gbSgbRenderScreenToBuffer(); + + u16 *fromAddress = (u16 *)gbSgbScreenBuffer; + + for(int i = 0; i < 512*4; i++) { + gbSgbSCPPalette[i] = READ16LE(fromAddress++); + } +} + +void gbSgbSetATF(int n) +{ + if(n < 0) + n = 0; + if(n > 44) + n = 44; + memcpy(gbSgbATF,&gbSgbATFList[n * 20 * 18], 20 * 18); + + if(gbSgbPacket[1] & 0x40) { + gbSgbMask = 0; + if(gbBorderOn) + gbSgbRenderBorder(); + } +} + +void gbSgbSetPalette() +{ + u16 pal = READ16LE((((u16 *)&gbSgbPacket[1])))&511; + memcpy(&gbPalette[0], &gbSgbSCPPalette[pal*4], 4 * sizeof(u16)); + + pal = READ16LE((((u16 *)&gbSgbPacket[3])))&511; + memcpy(&gbPalette[4], &gbSgbSCPPalette[pal*4], 4 * sizeof(u16)); + + pal = READ16LE((((u16 *)&gbSgbPacket[5])))&511; + memcpy(&gbPalette[8], &gbSgbSCPPalette[pal*4], 4 * sizeof(u16)); + + pal = READ16LE((((u16 *)&gbSgbPacket[7])))&511; + memcpy(&gbPalette[12], &gbSgbSCPPalette[pal*4], 4 * sizeof(u16)); + + u8 atf = gbSgbPacket[9]; + + if(atf & 0x80) { + gbSgbSetATF(atf & 0x3f); + } + + if(atf & 0x40) { + gbSgbMask = 0; + if(gbBorderOn) + gbSgbRenderBorder(); + } +} + +void gbSgbAttributeBlock() +{ + u8 *fromAddress = &gbSgbPacket[1]; + + u8 nDataSet = *fromAddress++; + if(nDataSet > 12) + nDataSet = 12; + if(nDataSet == 0) + nDataSet = 1; + + while(nDataSet) { + u8 controlCode = (*fromAddress++) & 7; + u8 paletteDesignation = (*fromAddress++) & 0x3f; + u8 startH = (*fromAddress++) & 0x1f; + u8 startV = (*fromAddress++) & 0x1f; + u8 endH = (*fromAddress++) & 0x1f; + u8 endV = (*fromAddress++) & 0x1f; + + u8 * toAddress = gbSgbATF; + + for(u8 y = 0; y < 18; y++) { + for(u8 x = 0; x < 20; x++) { + if(x < startH || y < startV || + x > endH || y > endV) { + // outside + if(controlCode & 0x04) + *toAddress = (paletteDesignation >> 4) & 0x03; + } else if(x > startH && x < endH && + y > startV && y < endV) { + // inside + if(controlCode & 0x01) + *toAddress = paletteDesignation & 0x03; + } else { + // surrounding line + if(controlCode & 0x02) + *toAddress = (paletteDesignation>>2) & 0x03; + else if(controlCode == 0x01) + *toAddress = paletteDesignation & 0x03; + } + toAddress++; + } + } + nDataSet--; + } +} + +void gbSgbSetColumnPalette(u8 col, u8 p) +{ + // if(col < 0) + // col = 0; + if(col > 19) + col = 19; + + p &= 3; + + u8 *toAddress = &gbSgbATF[col]; + + for(u8 y = 0; y < 18; y++) { + *toAddress = p; + toAddress += 20; + } +} + +void gbSgbSetRowPalette(u8 row, u8 p) +{ + // if(row < 0) + // row = 0; + if(row > 17) + row = 17; + + p &= 3; + + u8 *toAddress = &gbSgbATF[row*20]; + + for(u8 x = 0; x < 20; x++) { + *toAddress++ = p; + } +} + +void gbSgbAttributeDivide() +{ + u8 control = gbSgbPacket[1]; + u8 coord = gbSgbPacket[2]; + u8 colorBR = control & 3; + u8 colorAL = (control >> 2) & 3; + u8 colorOL = (control >> 4) & 3; + + if(control & 0x40) { + if(coord > 17) + coord = 17; + + for(u8 i = 0; i < 18; i++) { + if(i < coord) + gbSgbSetRowPalette(i, colorAL); + else if ( i > coord) + gbSgbSetRowPalette(i, colorBR); + else + gbSgbSetRowPalette(i, colorOL); + } + } else { + if(coord > 19) + coord = 19; + + for(u8 i = 0; i < 20; i++) { + if(i < coord) + gbSgbSetColumnPalette(i, colorAL); + else if ( i > coord) + gbSgbSetColumnPalette(i, colorBR); + else + gbSgbSetColumnPalette(i, colorOL); + } + } +} + +void gbSgbAttributeLine() +{ + u8 *fromAddress = &gbSgbPacket[1]; + + u8 nDataSet = *fromAddress++; + + if(nDataSet > 0x6e) + nDataSet = 0x6e; + + while(nDataSet) { + u8 line = *fromAddress++; + u8 num = line & 0x1f; + u8 pal = (line >> 5) & 0x03; + if(line & 0x80) { + if(num > 17) + num = 17; + gbSgbSetRowPalette(num,pal); + } else { + if(num > 19) + num = 19; + gbSgbSetColumnPalette(num,pal); + } + nDataSet--; + } +} + +void gbSgbAttributeCharacter() +{ + u8 startH = gbSgbPacket[1] & 0x1f; + u8 startV = gbSgbPacket[2] & 0x1f; + int nDataSet = READ16LE(((u16 *)&gbSgbPacket[3])); + int style = gbSgbPacket[5] & 1; + if(startH > 19) + startH = 19; + if(startV > 17) + startV = 17; + + u8 s = 6; + u8 *fromAddress = &gbSgbPacket[6]; + u8 v = *fromAddress++; + + if(style) { + while(nDataSet) { + u8 p = (v >> s) & 3; + gbSgbATF[startV * 20 + startH] = p; + startV++; + if(startV == 18) { + startV = 0; + startH++; + if(startH == 20) + break; + } + + if(s) + s -= 2; + else { + s = 6; + v = *fromAddress++; + nDataSet--; + } + } + } else { + while(nDataSet) { + u8 p = (v >> s) & 3; + gbSgbATF[startV * 20 + startH] = p; + startH++; + if(startH == 20) { + startH = 0; + startV++; + if(startV == 18) + break; + } + + if(s) + s -= 2; + else { + s = 6; + v = *fromAddress++; + nDataSet--; + } + } + } +} + +void gbSgbSetATFList() +{ + gbSgbRenderScreenToBuffer(); + + u8 *fromAddress = gbSgbScreenBuffer; + u8 *toAddress = gbSgbATFList; + + for(int i = 0; i < 45; i++) { + for(int j = 0; j < 90; j++) { + u8 v = *fromAddress++; + u8 s = 6; + if(i == 2) + s = 6; + for(int k = 0; k < 4; k++) { + *toAddress++ = (v >> s) & 0x03; + s -= 2; + } + } + } +} + +void gbSgbMaskEnable() +{ + int gbSgbMaskFlag = gbSgbPacket[1] & 3; + + gbSgbMask = gbSgbMaskFlag; + + switch(gbSgbMaskFlag) { + case 1: + break; + case 2: + gbSgbFillScreen(0x0000); + // memset(&gbPalette[0], 0, 128*sizeof(u16)); + break; + case 3: + gbSgbFillScreen(gbPalette[0]); + break; + } + if(!gbSgbMask) { + if(gbBorderOn) + gbSgbRenderBorder(); + } +} + +void gbSgbChrTransfer() +{ + gbSgbRenderScreenToBuffer(); + + int address = (gbSgbPacket[1] & 1) * (128*32); + + if(gbSgbPacket[1] & 1) + gbSgbCGBSupport |= 2; + else + gbSgbCGBSupport |= 1; + + memcpy(&gbSgbBorderChar[address], gbSgbScreenBuffer, 128 * 32); + + if(gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4) { + gbBorderOn = 1; + systemGbBorderOn(); + } + + if(gbBorderOn && !gbSgbMask) + gbSgbRenderBorder(); + + if(gbSgbMode && gbCgbMode && gbSgbCGBSupport == 7) { + gbSgbCGBSupport = 0; + gbSgbMode = 0; + gbSgbMask = 0; + gbSgbRenderBorder(); + gbReset(); + } + + if(gbSgbCGBSupport > 4) + gbSgbCGBSupport = 0; +} + +void gbSgbMultiRequest() +{ + if(gbSgbPacket[1] & 1) { + gbSgbMultiplayer = 1; + if(gbSgbPacket[1] & 2) + gbSgbFourPlayers = 1; + else + gbSgbFourPlayers = 0; + gbSgbNextController = 0x0e; + } else { + gbSgbFourPlayers = 0; + gbSgbMultiplayer = 0; + gbSgbNextController = 0x0f; + } +} + +void gbSgbCommand() +{ + int command = gbSgbPacket[0] >> 3; + // int nPacket = gbSgbPacket[0] & 7; + + switch(command) { + case 0x00: + gbSgbSetPalette(0,1,(u16 *)&gbSgbPacket[1]); + break; + case 0x01: + gbSgbSetPalette(2,3,(u16 *)&gbSgbPacket[1]); + break; + case 0x02: + gbSgbSetPalette(0,3,(u16 *)&gbSgbPacket[1]); + break; + case 0x03: + gbSgbSetPalette(1,2,(u16 *)&gbSgbPacket[1]); + break; + case 0x04: + gbSgbAttributeBlock(); + break; + case 0x05: + gbSgbAttributeLine(); + break; + case 0x06: + gbSgbAttributeDivide(); + break; + case 0x07: + gbSgbAttributeCharacter(); + break; + case 0x0a: + gbSgbSetPalette(); + break; + case 0x0b: + gbSgbScpPalette(); + break; + case 0x11: + gbSgbMultiRequest(); + break; + case 0x13: + gbSgbChrTransfer(); + break; + case 0x14: + gbSgbPicture(); + break; + case 0x15: + gbSgbSetATFList(); + break; + case 0x16: + gbSgbSetATF(gbSgbPacket[1] & 0x3f); + break; + case 0x17: + gbSgbMaskEnable(); + break; + } +} + +void gbSgbResetPacketState() +{ + gbSgbPacketState = GBSGB_NONE; + gbSgbPacketTimeout = 0; +} + +void gbSgbDoBitTransfer(u8 value) +{ + value = value & 0x30; + switch(gbSgbPacketState) { + case GBSGB_NONE: + if(value == 0) { + gbSgbPacketState = GBSGB_RESET; + gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; + } else if (value == 0x30) { + if(gbSgbMultiplayer) { + if((gbSgbReadingController & 7) == 7) { + gbSgbReadingController = 0; + if(gbSgbMultiplayer) { + gbSgbNextController--; + if(gbSgbFourPlayers) { + if(gbSgbNextController == 0x0b) + gbSgbNextController = 0x0f; + } else { + if(gbSgbNextController == 0x0d) + gbSgbNextController = 0x0f; + } + } + } else { + gbSgbReadingController &= 3; + } + } + gbSgbPacketTimeout = 0; + } else { + if(value == 0x10) + gbSgbReadingController |= 0x2; + else if(value == 0x20) + gbSgbReadingController |= 0x01; + gbSgbPacketTimeout = 0; + } + gbSgbPacketTimeout = 0; + break; + case GBSGB_RESET: + if(value == 0x30) { + gbSgbPacketState = GBSGB_PACKET_TRANSMIT; + gbSgbPacketByte = 0; + gbSgbPacketNBits = 0; + gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; + } else if(value == 0x00) { + gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; + gbSgbPacketState = GBSGB_RESET; + } else { + gbSgbPacketState = GBSGB_NONE; + gbSgbPacketTimeout = 0; + } + break; + case GBSGB_PACKET_TRANSMIT: + if(value == 0) { + gbSgbPacketState = GBSGB_RESET; + gbSgbPacketTimeout = 0; + } else if (value == 0x30){ + if(gbSgbPacketNBits == 128) { + gbSgbPacketNBits = 0; + gbSgbPacketByte = 0; + gbSgbPacketNumber++; + gbSgbPacketTimeout = 0; + if(gbSgbPacketNumber == (gbSgbPacket[0] & 7)) { + gbSgbCommand(); + gbSgbPacketNumber = 0; + gbSgbPacketState = GBSGB_NONE; + gbSgbPacketTimeout = 0; + } + } else { + if(gbSgbPacketNBits < 128) { + gbSgbPacket[gbSgbPacketNumber * 16 + gbSgbPacketByte] >>= 1; + gbSgbPacket[gbSgbPacketNumber * 16 + gbSgbPacketByte] |= gbSgbBit; + gbSgbPacketNBits++; + if(!(gbSgbPacketNBits & 7)) { + gbSgbPacketByte++; + } + gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; + } + } + } else { + if(value == 0x20) + gbSgbBit = 0x00; + else + gbSgbBit = 0x80; + gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; + } + gbSgbReadingController = 0; + break; + default: + gbSgbPacketState = GBSGB_NONE; + gbSgbPacketTimeout = 0; + break; + } +} + +variable_desc gbSgbSaveStruct[] = { + { &gbSgbMask, sizeof(int) }, + { &gbSgbPacketState, sizeof(int) }, + { &gbSgbBit, sizeof(int) }, + { &gbSgbPacketNBits, sizeof(int) }, + { &gbSgbPacketByte, sizeof(int) }, + { &gbSgbPacketNumber, sizeof(int) }, + { &gbSgbMultiplayer, sizeof(int) }, + { &gbSgbNextController, sizeof(u8) }, + { &gbSgbReadingController, sizeof(u8) }, + { NULL, 0 } +}; + +variable_desc gbSgbSaveStructV3[] = { + { &gbSgbMask, sizeof(int) }, + { &gbSgbPacketState, sizeof(int) }, + { &gbSgbBit, sizeof(int) }, + { &gbSgbPacketNBits, sizeof(int) }, + { &gbSgbPacketByte, sizeof(int) }, + { &gbSgbPacketNumber, sizeof(int) }, + { &gbSgbMultiplayer, sizeof(int) }, + { &gbSgbNextController, sizeof(u8) }, + { &gbSgbReadingController, sizeof(u8) }, + { &gbSgbFourPlayers, sizeof(int) }, + { NULL, 0 } +}; + +void gbSgbSaveGame(gzFile gzFile) +{ + utilWriteData(gzFile, gbSgbSaveStructV3); + + utilGzWrite(gzFile, gbSgbBorder, 2048); + utilGzWrite(gzFile, gbSgbBorderChar, 32*256); + + utilGzWrite(gzFile, gbSgbPacket, 16*7); + + utilGzWrite(gzFile, gbSgbSCPPalette, 4 * 512 * sizeof(u16)); + utilGzWrite(gzFile, gbSgbATF, 20 * 18); + utilGzWrite(gzFile, gbSgbATFList, 45 * 20 * 18); +} + +void gbSgbReadGame(gzFile gzFile, int version) +{ + if(version >= 3) + utilReadData(gzFile, gbSgbSaveStructV3); + else { + utilReadData(gzFile, gbSgbSaveStruct); + gbSgbFourPlayers = 0; + } + + if(version >= 8) { + utilGzRead(gzFile, gbSgbBorder, 2048); + utilGzRead(gzFile, gbSgbBorderChar, 32*256); + } + + utilGzRead(gzFile, gbSgbPacket, 16*7); + + utilGzRead(gzFile, gbSgbSCPPalette, 4 * 512 * sizeof(u16)); + utilGzRead(gzFile, gbSgbATF, 20 * 18); + utilGzRead(gzFile, gbSgbATFList, 45 * 20 * 18); +} diff --git a/src/dmg/gbSGB.h b/src/dmg/gbSGB.h index 6dcd3b44..95afb2c1 100644 --- a/src/dmg/gbSGB.h +++ b/src/dmg/gbSGB.h @@ -1,39 +1,39 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -void gbSgbInit(); -void gbSgbShutdown(); -void gbSgbCommand(); -void gbSgbResetPacketState(); -void gbSgbReset(); -void gbSgbDoBitTransfer(u8); -void gbSgbSaveGame(gzFile); -void gbSgbReadGame(gzFile, int version); -void gbSgbRenderBorder(); - -extern u8 gbSgbATF[20*18]; -extern int gbSgbMode; -extern int gbSgbMask; -extern int gbSgbMultiplayer; -extern u8 gbSgbNextController; -extern int gbSgbPacketTimeout; -extern u8 gbSgbReadingController; -extern int gbSgbFourPlayers; - - +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +void gbSgbInit(); +void gbSgbShutdown(); +void gbSgbCommand(); +void gbSgbResetPacketState(); +void gbSgbReset(); +void gbSgbDoBitTransfer(u8); +void gbSgbSaveGame(gzFile); +void gbSgbReadGame(gzFile, int version); +void gbSgbRenderBorder(); + +extern u8 gbSgbATF[20*18]; +extern int gbSgbMode; +extern int gbSgbMask; +extern int gbSgbMultiplayer; +extern u8 gbSgbNextController; +extern int gbSgbPacketTimeout; +extern u8 gbSgbReadingController; +extern int gbSgbFourPlayers; + + diff --git a/src/dmg/gbSound.cpp b/src/dmg/gbSound.cpp index 66634243..da1bcc58 100644 --- a/src/dmg/gbSound.cpp +++ b/src/dmg/gbSound.cpp @@ -1,412 +1,412 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005-2006 Forgotten and the VBA development team -// Copyright (C) 2007-2008 VBA-M development team -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include - -#include "../System.h" -#include "../Util.h" -#include "gbGlobals.h" -#include "gbSound.h" - -#include "gb_apu/Gb_Apu.h" -#include "gb_apu/Effects_Buffer.h" - -static Gb_Apu* gb_apu; -static Simple_Effects_Buffer* stereo_buffer; - -extern u16 soundFinalWave[1470]; -extern int soundVolume; - -extern int gbHardware; - -extern void soundResume(); - -extern int soundBufferLen; -extern int soundQuality; -extern bool soundPaused; -extern int soundTicks; -extern int SOUND_CLOCK_TICKS; -extern u32 soundNextPosition; - -extern int soundDebug; - -extern bool soundEcho; -extern bool soundLowPass; -extern bool soundReverse; -extern bool soundOffFlag; - -int const ticks_to_time = 2 * GB_APU_OVERCLOCK; - -static inline blip_time_t blip_time() -{ - return (SOUND_CLOCK_TICKS - soundTicks) * ticks_to_time; -} - -u8 gbSoundRead( u16 address ) -{ - if ( gb_apu && address >= NR10 && address <= 0xFF3F ) - return gb_apu->read_register( blip_time(), address ); - - return gbMemory[address]; -} - -void gbSoundEvent(register u16 address, register int data) -{ - int freq = 0; - - gbMemory[address] = data; - -#ifndef FINAL_VERSION - if(soundDebug) { - // don't translate. debug only - log("Sound event: %08lx %02x\n", address, data); - } -#endif - - if ( gb_apu && address >= NR10 && address <= 0xFF3F ) - gb_apu->write_register( blip_time(), address, data ); -} - -static void end_frame( blip_time_t time ) -{ - gb_apu ->end_frame( time ); - stereo_buffer->end_frame( time ); -} - -static void flush_samples() -{ - // number of samples in output buffer - int const out_buf_size = soundBufferLen / sizeof *soundFinalWave; - - // Keep filling and writing soundFinalWave until it can't be fully filled - while ( stereo_buffer->samples_avail() >= out_buf_size ) - { - stereo_buffer->read_samples( (blip_sample_t*) soundFinalWave, out_buf_size ); - if(systemSoundOn) - { - if(soundPaused) - soundResume(); - - systemWriteDataToSoundBuffer(); - } - } -} - -int const chan_count = 4; - -gb_effects_config_t gb_effects_config; -static gb_effects_config_t gb_effects_config_current; - -static void apply_effects() -{ - gb_effects_config_current = gb_effects_config; - - stereo_buffer->config().enabled = gb_effects_config_current.enabled; - stereo_buffer->config().echo = gb_effects_config_current.echo; - stereo_buffer->config().stereo = gb_effects_config_current.stereo; - stereo_buffer->config().surround = gb_effects_config_current.surround; - stereo_buffer->apply_config(); - - for ( int i = 0; i < chan_count; i++ ) - { - Multi_Buffer::channel_t ch = stereo_buffer->channel( i ); - gb_apu->set_output( ch.center, ch.left, ch.right, i ); - } -} - -void gbSoundTick() -{ - if ( systemSoundOn && gb_apu && stereo_buffer ) - { - // Run sound hardware to present - end_frame( SOUND_CLOCK_TICKS * ticks_to_time ); - - flush_samples(); - - gb_effects_config.enabled = soundEcho; - - // Update effects config if it was changed - if ( memcmp( &gb_effects_config_current, &gb_effects_config, - sizeof gb_effects_config ) ) - apply_effects(); - } -} - -static void reset_apu() -{ - // Use DMG or CGB sound differences based on type of game - gb_apu->reset( gbHardware & 1 ? gb_apu->mode_dmg : gb_apu->mode_cgb ); - - if ( stereo_buffer ) - stereo_buffer->clear(); - - soundTicks = SOUND_CLOCK_TICKS; -} - -static void remake_stereo_buffer() -{ - // Stereo_Buffer - delete stereo_buffer; - stereo_buffer = 0; - - stereo_buffer = new Simple_Effects_Buffer; // TODO: handle out of memory - stereo_buffer->set_sample_rate( 44100 / soundQuality ); // TODO: handle out of memory - stereo_buffer->clock_rate( gb_apu->clock_rate ); - - // APU - static int const chan_types [chan_count] = { - Multi_Buffer::wave_type+1, Multi_Buffer::wave_type+2, - Multi_Buffer::wave_type+3, Multi_Buffer::mixed_type+1 - }; - stereo_buffer->set_channel_count( chan_count, chan_types ); - - if ( !gb_apu ) - { - gb_apu = new Gb_Apu; - reset_apu(); - } - - apply_effects(); -} - -void gbSoundReset() -{ - gb_effects_config.echo = 0.20f; - gb_effects_config.stereo = 0.15f; - gb_effects_config.surround = false; - - SOUND_CLOCK_TICKS = 20000; - - remake_stereo_buffer(); - reset_apu(); - - soundPaused = 1; - soundNextPosition = 0; - - // don't translate -#ifndef FINAL_VERSION - if(soundDebug) { - log("*** Sound Init ***\n"); - } -#endif - gbSoundEvent(0xff10, 0x80); - gbSoundEvent(0xff11, 0xbf); - gbSoundEvent(0xff12, 0xf3); - gbSoundEvent(0xff14, 0xbf); - gbSoundEvent(0xff16, 0x3f); - gbSoundEvent(0xff17, 0x00); - gbSoundEvent(0xff19, 0xbf); - - gbSoundEvent(0xff1a, 0x7f); - gbSoundEvent(0xff1b, 0xff); - gbSoundEvent(0xff1c, 0xbf); - gbSoundEvent(0xff1e, 0xbf); - - gbSoundEvent(0xff20, 0xff); - gbSoundEvent(0xff21, 0x00); - gbSoundEvent(0xff22, 0x00); - gbSoundEvent(0xff23, 0xbf); - gbSoundEvent(0xff24, 0x77); - gbSoundEvent(0xff25, 0xf3); - - if (gbHardware & 0x4) - gbSoundEvent(0xff26, 0xf0); - else - gbSoundEvent(0xff26, 0xf1); - - // don't translate -#ifndef FINAL_VERSION - if(soundDebug) { - log("*** Sound Init Complete ***\n"); - } -#endif - int addr = 0xff30; - - while(addr < 0xff40) { - gbMemory[addr++] = 0x00; - gbMemory[addr++] = 0xff; - } -} - -extern bool soundInit(); -extern void soundShutdown(); - -void gbSoundSetQuality(int quality) -{ - if ( soundQuality != quality ) - { - if ( systemCanChangeSoundQuality() ) - { - if ( !soundOffFlag ) - soundShutdown(); - - soundQuality = quality; - soundNextPosition = 0; - - if ( !soundOffFlag ) - soundInit(); - } - else - { - soundQuality = quality; - soundNextPosition = 0; - } - - remake_stereo_buffer(); - } -} - -static char dummy_buf [735 * 2]; - -#define SKIP( type, name ) { dummy_buf, sizeof (type) } - -// funny expr at end ensures that type matches type of variable -#define LOAD( type, name ) { &name, sizeof (name) + (&name - (type*) &name) } - -static variable_desc gbsound_format [] = -{ - SKIP( int, soundPaused ), - SKIP( int, soundPlay ), - SKIP( int, soundTicks ), - SKIP( int, SOUND_CLOCK_TICKS ), - SKIP( int, soundLevel1 ), - SKIP( int, soundLevel2 ), - SKIP( int, soundBalance ), - SKIP( int, soundMasterOn ), - SKIP( int, soundIndex ), - SKIP( int, soundVIN ), - SKIP( int, soundOn [0] ), - SKIP( int, soundATL [0] ), - SKIP( int, sound1Skip ), - SKIP( int, soundIndex [0] ), - SKIP( int, sound1Continue ), - SKIP( int, soundEnvelopeVolume [0] ), - SKIP( int, soundEnvelopeATL [0] ), - SKIP( int, sound1EnvelopeATLReload ), - SKIP( int, sound1EnvelopeUpDown ), - SKIP( int, sound1SweepATL ), - SKIP( int, sound1SweepATLReload ), - SKIP( int, sound1SweepSteps ), - SKIP( int, sound1SweepUpDown ), - SKIP( int, sound1SweepStep ), - SKIP( int, soundOn [1] ), - SKIP( int, soundATL [1] ), - SKIP( int, sound2Skip ), - SKIP( int, soundIndex [1] ), - SKIP( int, sound2Continue ), - SKIP( int, soundEnvelopeVolume [1] ), - SKIP( int, soundEnvelopeATL [1] ), - SKIP( int, sound2EnvelopeATLReload ), - SKIP( int, sound2EnvelopeUpDown ), - SKIP( int, soundOn [2] ), - SKIP( int, soundATL [2] ), - SKIP( int, sound3Skip ), - SKIP( int, soundIndex [2] ), - SKIP( int, sound3Continue ), - SKIP( int, sound3OutputLevel ), - SKIP( int, soundOn [3] ), - SKIP( int, soundATL [3] ), - SKIP( int, sound4Skip ), - SKIP( int, soundIndex [3] ), - SKIP( int, sound4Clock ), - SKIP( int, sound4ShiftRight ), - SKIP( int, sound4ShiftSkip ), - SKIP( int, sound4ShiftIndex ), - SKIP( int, sound4NSteps ), - SKIP( int, sound4CountDown ), - SKIP( int, sound4Continue ), - SKIP( int, soundEnvelopeVolume [2] ), - SKIP( int, soundEnvelopeATL [2] ), - SKIP( int, sound4EnvelopeATLReload ), - SKIP( int, sound4EnvelopeUpDown ), - SKIP( int, soundEnableFlag ), - { NULL, 0 } -}; - -static variable_desc gbsound_format2 [] = -{ - SKIP( int, sound1ATLreload ), - SKIP( int, freq1low ), - SKIP( int, freq1high ), - SKIP( int, sound2ATLreload ), - SKIP( int, freq2low ), - SKIP( int, freq2high ), - SKIP( int, sound3ATLreload ), - SKIP( int, freq3low ), - SKIP( int, freq3high ), - SKIP( int, sound4ATLreload ), - SKIP( int, freq4 ), - { NULL, 0 } -}; - -static variable_desc gbsound_format3 [] = -{ - SKIP( u8[2*735], soundBuffer ), - SKIP( u8[2*735], soundBuffer ), - SKIP( u16[735], soundFinalWave ), - { NULL, 0 } -}; - -void gbSoundSaveGame(gzFile gzFile) -{ - // TODO: implement -} - -enum { - nr10 = 0, - nr11, nr12, nr13, nr14, - nr20, nr21, nr22, nr23, nr24, - nr30, nr31, nr32, nr33, nr34, - nr40, nr41, nr42, nr43, nr44, - nr50, nr51, nr52 -}; - -void gbSoundReadGame(int version,gzFile gzFile) -{ - return; // TODO: apparently GB save states don't work in the main emulator - - // Load state - utilReadData( gzFile, gbsound_format ); - - if ( version >= 11 ) - utilReadData( gzFile, gbsound_format2 ); - - utilReadData( gzFile, gbsound_format3 ); - - int quality = 1; - if ( version >= 7 ) - quality = utilReadInt( gzFile ); - - gbSoundSetQuality( quality ); - - // Convert to format Gb_Apu uses - reset_apu(); - gb_apu_state_t s; - gb_apu->save_state( &s ); // use fresh values for anything not restored - - // Only some registers are properly preserved - static int const regs_to_copy [] = { - nr10, nr11, nr12, nr21, nr22, nr30, nr32, nr42, nr43, nr50, nr51, nr52, -1 - }; - for ( int i = 0; regs_to_copy [i] >= 0; i++ ) - s.regs [regs_to_copy [i]] = gbMemory [0xFF10 + regs_to_copy [i]]; - - memcpy( &s.regs [0x20], &gbMemory [0xFF30], 0x10 ); // wave - - gb_apu->load_state( s ); -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team +// Copyright (C) 2007-2008 VBA-M development team +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include + +#include "../System.h" +#include "../Util.h" +#include "gbGlobals.h" +#include "gbSound.h" + +#include "gb_apu/Gb_Apu.h" +#include "gb_apu/Effects_Buffer.h" + +static Gb_Apu* gb_apu; +static Simple_Effects_Buffer* stereo_buffer; + +extern u16 soundFinalWave[1470]; +extern int soundVolume; + +extern int gbHardware; + +extern void soundResume(); + +extern int soundBufferLen; +extern int soundQuality; +extern bool soundPaused; +extern int soundTicks; +extern int SOUND_CLOCK_TICKS; +extern u32 soundNextPosition; + +extern int soundDebug; + +extern bool soundEcho; +extern bool soundLowPass; +extern bool soundReverse; +extern bool soundOffFlag; + +int const ticks_to_time = 2 * GB_APU_OVERCLOCK; + +static inline blip_time_t blip_time() +{ + return (SOUND_CLOCK_TICKS - soundTicks) * ticks_to_time; +} + +u8 gbSoundRead( u16 address ) +{ + if ( gb_apu && address >= NR10 && address <= 0xFF3F ) + return gb_apu->read_register( blip_time(), address ); + + return gbMemory[address]; +} + +void gbSoundEvent(register u16 address, register int data) +{ + int freq = 0; + + gbMemory[address] = data; + +#ifndef FINAL_VERSION + if(soundDebug) { + // don't translate. debug only + log("Sound event: %08lx %02x\n", address, data); + } +#endif + + if ( gb_apu && address >= NR10 && address <= 0xFF3F ) + gb_apu->write_register( blip_time(), address, data ); +} + +static void end_frame( blip_time_t time ) +{ + gb_apu ->end_frame( time ); + stereo_buffer->end_frame( time ); +} + +static void flush_samples() +{ + // number of samples in output buffer + int const out_buf_size = soundBufferLen / sizeof *soundFinalWave; + + // Keep filling and writing soundFinalWave until it can't be fully filled + while ( stereo_buffer->samples_avail() >= out_buf_size ) + { + stereo_buffer->read_samples( (blip_sample_t*) soundFinalWave, out_buf_size ); + if(systemSoundOn) + { + if(soundPaused) + soundResume(); + + systemWriteDataToSoundBuffer(); + } + } +} + +int const chan_count = 4; + +gb_effects_config_t gb_effects_config; +static gb_effects_config_t gb_effects_config_current; + +static void apply_effects() +{ + gb_effects_config_current = gb_effects_config; + + stereo_buffer->config().enabled = gb_effects_config_current.enabled; + stereo_buffer->config().echo = gb_effects_config_current.echo; + stereo_buffer->config().stereo = gb_effects_config_current.stereo; + stereo_buffer->config().surround = gb_effects_config_current.surround; + stereo_buffer->apply_config(); + + for ( int i = 0; i < chan_count; i++ ) + { + Multi_Buffer::channel_t ch = stereo_buffer->channel( i ); + gb_apu->set_output( ch.center, ch.left, ch.right, i ); + } +} + +void gbSoundTick() +{ + if ( systemSoundOn && gb_apu && stereo_buffer ) + { + // Run sound hardware to present + end_frame( SOUND_CLOCK_TICKS * ticks_to_time ); + + flush_samples(); + + gb_effects_config.enabled = soundEcho; + + // Update effects config if it was changed + if ( memcmp( &gb_effects_config_current, &gb_effects_config, + sizeof gb_effects_config ) ) + apply_effects(); + } +} + +static void reset_apu() +{ + // Use DMG or CGB sound differences based on type of game + gb_apu->reset( gbHardware & 1 ? gb_apu->mode_dmg : gb_apu->mode_cgb ); + + if ( stereo_buffer ) + stereo_buffer->clear(); + + soundTicks = SOUND_CLOCK_TICKS; +} + +static void remake_stereo_buffer() +{ + // Stereo_Buffer + delete stereo_buffer; + stereo_buffer = 0; + + stereo_buffer = new Simple_Effects_Buffer; // TODO: handle out of memory + stereo_buffer->set_sample_rate( 44100 / soundQuality ); // TODO: handle out of memory + stereo_buffer->clock_rate( gb_apu->clock_rate ); + + // APU + static int const chan_types [chan_count] = { + Multi_Buffer::wave_type+1, Multi_Buffer::wave_type+2, + Multi_Buffer::wave_type+3, Multi_Buffer::mixed_type+1 + }; + stereo_buffer->set_channel_count( chan_count, chan_types ); + + if ( !gb_apu ) + { + gb_apu = new Gb_Apu; + reset_apu(); + } + + apply_effects(); +} + +void gbSoundReset() +{ + gb_effects_config.echo = 0.20f; + gb_effects_config.stereo = 0.15f; + gb_effects_config.surround = false; + + SOUND_CLOCK_TICKS = 20000; + + remake_stereo_buffer(); + reset_apu(); + + soundPaused = 1; + soundNextPosition = 0; + + // don't translate +#ifndef FINAL_VERSION + if(soundDebug) { + log("*** Sound Init ***\n"); + } +#endif + gbSoundEvent(0xff10, 0x80); + gbSoundEvent(0xff11, 0xbf); + gbSoundEvent(0xff12, 0xf3); + gbSoundEvent(0xff14, 0xbf); + gbSoundEvent(0xff16, 0x3f); + gbSoundEvent(0xff17, 0x00); + gbSoundEvent(0xff19, 0xbf); + + gbSoundEvent(0xff1a, 0x7f); + gbSoundEvent(0xff1b, 0xff); + gbSoundEvent(0xff1c, 0xbf); + gbSoundEvent(0xff1e, 0xbf); + + gbSoundEvent(0xff20, 0xff); + gbSoundEvent(0xff21, 0x00); + gbSoundEvent(0xff22, 0x00); + gbSoundEvent(0xff23, 0xbf); + gbSoundEvent(0xff24, 0x77); + gbSoundEvent(0xff25, 0xf3); + + if (gbHardware & 0x4) + gbSoundEvent(0xff26, 0xf0); + else + gbSoundEvent(0xff26, 0xf1); + + // don't translate +#ifndef FINAL_VERSION + if(soundDebug) { + log("*** Sound Init Complete ***\n"); + } +#endif + int addr = 0xff30; + + while(addr < 0xff40) { + gbMemory[addr++] = 0x00; + gbMemory[addr++] = 0xff; + } +} + +extern bool soundInit(); +extern void soundShutdown(); + +void gbSoundSetQuality(int quality) +{ + if ( soundQuality != quality ) + { + if ( systemCanChangeSoundQuality() ) + { + if ( !soundOffFlag ) + soundShutdown(); + + soundQuality = quality; + soundNextPosition = 0; + + if ( !soundOffFlag ) + soundInit(); + } + else + { + soundQuality = quality; + soundNextPosition = 0; + } + + remake_stereo_buffer(); + } +} + +static char dummy_buf [735 * 2]; + +#define SKIP( type, name ) { dummy_buf, sizeof (type) } + +// funny expr at end ensures that type matches type of variable +#define LOAD( type, name ) { &name, sizeof (name) + (&name - (type*) &name) } + +static variable_desc gbsound_format [] = +{ + SKIP( int, soundPaused ), + SKIP( int, soundPlay ), + SKIP( int, soundTicks ), + SKIP( int, SOUND_CLOCK_TICKS ), + SKIP( int, soundLevel1 ), + SKIP( int, soundLevel2 ), + SKIP( int, soundBalance ), + SKIP( int, soundMasterOn ), + SKIP( int, soundIndex ), + SKIP( int, soundVIN ), + SKIP( int, soundOn [0] ), + SKIP( int, soundATL [0] ), + SKIP( int, sound1Skip ), + SKIP( int, soundIndex [0] ), + SKIP( int, sound1Continue ), + SKIP( int, soundEnvelopeVolume [0] ), + SKIP( int, soundEnvelopeATL [0] ), + SKIP( int, sound1EnvelopeATLReload ), + SKIP( int, sound1EnvelopeUpDown ), + SKIP( int, sound1SweepATL ), + SKIP( int, sound1SweepATLReload ), + SKIP( int, sound1SweepSteps ), + SKIP( int, sound1SweepUpDown ), + SKIP( int, sound1SweepStep ), + SKIP( int, soundOn [1] ), + SKIP( int, soundATL [1] ), + SKIP( int, sound2Skip ), + SKIP( int, soundIndex [1] ), + SKIP( int, sound2Continue ), + SKIP( int, soundEnvelopeVolume [1] ), + SKIP( int, soundEnvelopeATL [1] ), + SKIP( int, sound2EnvelopeATLReload ), + SKIP( int, sound2EnvelopeUpDown ), + SKIP( int, soundOn [2] ), + SKIP( int, soundATL [2] ), + SKIP( int, sound3Skip ), + SKIP( int, soundIndex [2] ), + SKIP( int, sound3Continue ), + SKIP( int, sound3OutputLevel ), + SKIP( int, soundOn [3] ), + SKIP( int, soundATL [3] ), + SKIP( int, sound4Skip ), + SKIP( int, soundIndex [3] ), + SKIP( int, sound4Clock ), + SKIP( int, sound4ShiftRight ), + SKIP( int, sound4ShiftSkip ), + SKIP( int, sound4ShiftIndex ), + SKIP( int, sound4NSteps ), + SKIP( int, sound4CountDown ), + SKIP( int, sound4Continue ), + SKIP( int, soundEnvelopeVolume [2] ), + SKIP( int, soundEnvelopeATL [2] ), + SKIP( int, sound4EnvelopeATLReload ), + SKIP( int, sound4EnvelopeUpDown ), + SKIP( int, soundEnableFlag ), + { NULL, 0 } +}; + +static variable_desc gbsound_format2 [] = +{ + SKIP( int, sound1ATLreload ), + SKIP( int, freq1low ), + SKIP( int, freq1high ), + SKIP( int, sound2ATLreload ), + SKIP( int, freq2low ), + SKIP( int, freq2high ), + SKIP( int, sound3ATLreload ), + SKIP( int, freq3low ), + SKIP( int, freq3high ), + SKIP( int, sound4ATLreload ), + SKIP( int, freq4 ), + { NULL, 0 } +}; + +static variable_desc gbsound_format3 [] = +{ + SKIP( u8[2*735], soundBuffer ), + SKIP( u8[2*735], soundBuffer ), + SKIP( u16[735], soundFinalWave ), + { NULL, 0 } +}; + +void gbSoundSaveGame(gzFile gzFile) +{ + // TODO: implement +} + +enum { + nr10 = 0, + nr11, nr12, nr13, nr14, + nr20, nr21, nr22, nr23, nr24, + nr30, nr31, nr32, nr33, nr34, + nr40, nr41, nr42, nr43, nr44, + nr50, nr51, nr52 +}; + +void gbSoundReadGame(int version,gzFile gzFile) +{ + return; // TODO: apparently GB save states don't work in the main emulator + + // Load state + utilReadData( gzFile, gbsound_format ); + + if ( version >= 11 ) + utilReadData( gzFile, gbsound_format2 ); + + utilReadData( gzFile, gbsound_format3 ); + + int quality = 1; + if ( version >= 7 ) + quality = utilReadInt( gzFile ); + + gbSoundSetQuality( quality ); + + // Convert to format Gb_Apu uses + reset_apu(); + gb_apu_state_t s; + gb_apu->save_state( &s ); // use fresh values for anything not restored + + // Only some registers are properly preserved + static int const regs_to_copy [] = { + nr10, nr11, nr12, nr21, nr22, nr30, nr32, nr42, nr43, nr50, nr51, nr52, -1 + }; + for ( int i = 0; regs_to_copy [i] >= 0; i++ ) + s.regs [regs_to_copy [i]] = gbMemory [0xFF10 + regs_to_copy [i]]; + + memcpy( &s.regs [0x20], &gbMemory [0xFF30], 0x10 ); // wave + + gb_apu->load_state( s ); +} diff --git a/src/dmg/gbSound.h b/src/dmg/gbSound.h index 75d5fb0e..2dc8e79a 100644 --- a/src/dmg/gbSound.h +++ b/src/dmg/gbSound.h @@ -1,74 +1,74 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#define NR10 0xff10 -#define NR11 0xff11 -#define NR12 0xff12 -#define NR13 0xff13 -#define NR14 0xff14 -#define NR21 0xff16 -#define NR22 0xff17 -#define NR23 0xff18 -#define NR24 0xff19 -#define NR30 0xff1a -#define NR31 0xff1b -#define NR32 0xff1c -#define NR33 0xff1d -#define NR34 0xff1e -#define NR41 0xff20 -#define NR42 0xff21 -#define NR43 0xff22 -#define NR44 0xff23 -#define NR50 0xff24 -#define NR51 0xff25 -#define NR52 0xff26 - -#define SOUND_EVENT(address,value) \ - gbSoundEvent(address,value) - -extern void gbSoundTick(); -extern void gbSoundPause(); -extern void gbSoundResume(); -extern void gbSoundEnable(int); -extern void gbSoundDisable(int); -extern int gbSoundGetEnable(); -extern void gbSoundReset(); -extern void gbSoundSaveGame(gzFile); -extern void gbSoundReadGame(int,gzFile); -extern void gbSoundEvent(register u16, register int); -extern void gbSoundSetQuality(int); - -extern u8 gbSoundRead(u16 address); - -extern int soundTicks; -extern int soundQuality; -extern int SOUND_CLOCK_TICKS; - -struct gb_effects_config_t -{ - bool enabled; // false = disable all effects - - float echo; // 0.0 = none, 1.0 = lots - float stereo; // 0.0 = channels in center, 1.0 = channels on left/right - bool surround; // true = put some channels in back -}; - -// Can be changed at any time, probably from another thread too. -// Sound will notice changes during next 1/100 second. -extern gb_effects_config_t gb_effects_config; +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#define NR10 0xff10 +#define NR11 0xff11 +#define NR12 0xff12 +#define NR13 0xff13 +#define NR14 0xff14 +#define NR21 0xff16 +#define NR22 0xff17 +#define NR23 0xff18 +#define NR24 0xff19 +#define NR30 0xff1a +#define NR31 0xff1b +#define NR32 0xff1c +#define NR33 0xff1d +#define NR34 0xff1e +#define NR41 0xff20 +#define NR42 0xff21 +#define NR43 0xff22 +#define NR44 0xff23 +#define NR50 0xff24 +#define NR51 0xff25 +#define NR52 0xff26 + +#define SOUND_EVENT(address,value) \ + gbSoundEvent(address,value) + +extern void gbSoundTick(); +extern void gbSoundPause(); +extern void gbSoundResume(); +extern void gbSoundEnable(int); +extern void gbSoundDisable(int); +extern int gbSoundGetEnable(); +extern void gbSoundReset(); +extern void gbSoundSaveGame(gzFile); +extern void gbSoundReadGame(int,gzFile); +extern void gbSoundEvent(register u16, register int); +extern void gbSoundSetQuality(int); + +extern u8 gbSoundRead(u16 address); + +extern int soundTicks; +extern int soundQuality; +extern int SOUND_CLOCK_TICKS; + +struct gb_effects_config_t +{ + bool enabled; // false = disable all effects + + float echo; // 0.0 = none, 1.0 = lots + float stereo; // 0.0 = channels in center, 1.0 = channels on left/right + bool surround; // true = put some channels in back +}; + +// Can be changed at any time, probably from another thread too. +// Sound will notice changes during next 1/100 second. +extern gb_effects_config_t gb_effects_config; diff --git a/src/dmg/gb_apu/Blip_Buffer.cpp b/src/dmg/gb_apu/Blip_Buffer.cpp index ab9faa94..3b2dda93 100644 --- a/src/dmg/gb_apu/Blip_Buffer.cpp +++ b/src/dmg/gb_apu/Blip_Buffer.cpp @@ -1,465 +1,465 @@ -// Blip_Buffer 0.4.1. http://www.slack.net/~ant/ - -#include "Blip_Buffer.h" - -#include -#include -#include -#include -#include - -/* Copyright (C) 2003-2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -// TODO: use scoped for variables in treble_eq() - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - -int const silent_buf_size = 1; // size used for Silent_Blip_Buffer - -Blip_Buffer::Blip_Buffer() -{ - factor_ = LONG_MAX; - buffer_ = 0; - buffer_size_ = 0; - sample_rate_ = 0; - bass_shift_ = 0; - clock_rate_ = 0; - bass_freq_ = 16; - length_ = 0; - - // assumptions code makes about implementation-defined features - #ifndef NDEBUG - // right shift of negative value preserves sign - buf_t_ i = -0x7FFFFFFE; - assert( (i >> 1) == -0x3FFFFFFF ); - - // casting to short truncates to 16 bits and sign-extends - i = 0x18000; - assert( (short) i == -0x8000 ); - #endif - - clear(); -} - -Blip_Buffer::~Blip_Buffer() -{ - if ( buffer_size_ != silent_buf_size ) - free( buffer_ ); -} - -Silent_Blip_Buffer::Silent_Blip_Buffer() -{ - factor_ = 0; - buffer_ = buf; - buffer_size_ = silent_buf_size; - clear(); -} - -void Blip_Buffer::clear( int entire_buffer ) -{ - offset_ = 0; - reader_accum_ = 0; - modified_ = 0; - if ( buffer_ ) - { - long count = (entire_buffer ? buffer_size_ : samples_avail()); - memset( buffer_, 0, (count + blip_buffer_extra_) * sizeof (buf_t_) ); - } -} - -Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec ) -{ - if ( buffer_size_ == silent_buf_size ) - { - assert( 0 ); - return "Internal (tried to resize Silent_Blip_Buffer)"; - } - - // start with maximum length that resampled time can represent - long new_size = (ULONG_MAX >> BLIP_BUFFER_ACCURACY) - blip_buffer_extra_ - 64; - if ( msec != blip_max_length ) - { - long s = (new_rate * (msec + 1) + 999) / 1000; - if ( s < new_size ) - new_size = s; - else - assert( 0 ); // fails if requested buffer length exceeds limit - } - - if ( buffer_size_ != new_size ) - { - void* p = realloc( buffer_, (new_size + blip_buffer_extra_) * sizeof *buffer_ ); - if ( !p ) - return "Out of memory"; - buffer_ = (buf_t_*) p; - } - - buffer_size_ = new_size; - assert( buffer_size_ != silent_buf_size ); // size should never happen to match this - - // update things based on the sample rate - sample_rate_ = new_rate; - length_ = new_size * 1000 / new_rate - 1; - if ( msec ) - assert( length_ == msec ); // ensure length is same as that passed in - - // update these since they depend on sample rate - if ( clock_rate_ ) - clock_rate( clock_rate_ ); - bass_freq( bass_freq_ ); - - clear(); - - return 0; // success -} - -blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const -{ - double ratio = (double) sample_rate_ / rate; - blip_long factor = (blip_long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 ); - assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large - return (blip_resampled_time_t) factor; -} - -void Blip_Buffer::bass_freq( int freq ) -{ - bass_freq_ = freq; - int shift = 31; - if ( freq > 0 ) - { - shift = 13; - long f = (freq << 16) / sample_rate_; - while ( (f >>= 1) && --shift ) { } - } - bass_shift_ = shift; -} - -void Blip_Buffer::end_frame( blip_time_t t ) -{ - offset_ += t * factor_; - assert( samples_avail() <= (long) buffer_size_ ); // fails if time is past end of buffer -} - -long Blip_Buffer::count_samples( blip_time_t t ) const -{ - blip_resampled_time_t last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY; - blip_resampled_time_t first_sample = offset_ >> BLIP_BUFFER_ACCURACY; - return long (last_sample - first_sample); -} - -blip_time_t Blip_Buffer::count_clocks( long count ) const -{ - if ( !factor_ ) - { - assert( 0 ); // sample rate and clock rates must be set first - return 0; - } - - if ( count > buffer_size_ ) - count = buffer_size_; - blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; - return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_); -} - -void Blip_Buffer::remove_samples( long count ) -{ - if ( count ) - { - remove_silence( count ); - - // copy remaining samples to beginning and clear old samples - long remain = samples_avail() + blip_buffer_extra_; - memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ ); - memset( buffer_ + remain, 0, count * sizeof *buffer_ ); - } -} - -// Blip_Synth_ - -Blip_Synth_Fast_::Blip_Synth_Fast_() -{ - buf = 0; - last_amp = 0; - delta_factor = 0; -} - -void Blip_Synth_Fast_::volume_unit( double new_unit ) -{ - delta_factor = int (new_unit * (1L << blip_sample_bits) + 0.5); -} - -#if !BLIP_BUFFER_FAST - -Blip_Synth_::Blip_Synth_( short* p, int w ) : - impulses( p ), - width( w ) -{ - volume_unit_ = 0.0; - kernel_unit = 0; - buf = 0; - last_amp = 0; - delta_factor = 0; -} - -#undef PI -#define PI 3.1415926535897932384626433832795029 - -static void gen_sinc( float* out, int count, double oversample, double treble, double cutoff ) -{ - if ( cutoff >= 0.999 ) - cutoff = 0.999; - - if ( treble < -300.0 ) - treble = -300.0; - if ( treble > 5.0 ) - treble = 5.0; - - double const maxh = 4096.0; - double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) ); - double const pow_a_n = pow( rolloff, maxh - maxh * cutoff ); - double const to_angle = PI / 2 / maxh / oversample; - for ( int i = 0; i < count; i++ ) - { - double angle = ((i - count) * 2 + 1) * to_angle; - double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle ); - double cos_nc_angle = cos( maxh * cutoff * angle ); - double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle ); - double cos_angle = cos( angle ); - - c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle; - double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle); - double b = 2.0 - cos_angle - cos_angle; - double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle; - - out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d - } -} - -void blip_eq_t::generate( float* out, int count ) const -{ - // lower cutoff freq for narrow kernels with their wider transition band - // (8 points->1.49, 16 points->1.15) - double oversample = blip_res * 2.25 / count + 0.85; - double half_rate = sample_rate * 0.5; - if ( cutoff_freq ) - oversample = half_rate / cutoff_freq; - double cutoff = rolloff_freq * oversample / half_rate; - - gen_sinc( out, count, blip_res * oversample, treble, cutoff ); - - // apply (half of) hamming window - double to_fraction = PI / (count - 1); - for ( int i = count; i--; ) - out [i] *= 0.54f - 0.46f * (float) cos( i * to_fraction ); -} - -void Blip_Synth_::adjust_impulse() -{ - // sum pairs for each phase and add error correction to end of first half - int const size = impulses_size(); - for ( int p = blip_res; p-- >= blip_res / 2; ) - { - int p2 = blip_res - 2 - p; - long error = kernel_unit; - for ( int i = 1; i < size; i += blip_res ) - { - error -= impulses [i + p ]; - error -= impulses [i + p2]; - } - if ( p == p2 ) - error /= 2; // phase = 0.5 impulse uses same half for both sides - impulses [size - blip_res + p] += (short) error; - //printf( "error: %ld\n", error ); - } - - //for ( int i = blip_res; i--; printf( "\n" ) ) - // for ( int j = 0; j < width / 2; j++ ) - // printf( "%5ld,", impulses [j * blip_res + i + 1] ); -} - -void Blip_Synth_::treble_eq( blip_eq_t const& eq ) -{ - float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2]; - - int const half_size = blip_res / 2 * (width - 1); - eq.generate( &fimpulse [blip_res], half_size ); - - int i; - - // need mirror slightly past center for calculation - for ( i = blip_res; i--; ) - fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i]; - - // starts at 0 - for ( i = 0; i < blip_res; i++ ) - fimpulse [i] = 0.0f; - - // find rescale factor - double total = 0.0; - for ( i = 0; i < half_size; i++ ) - total += fimpulse [blip_res + i]; - - //double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB - //double const base_unit = 37888.0; // allows treble to +5 dB - double const base_unit = 32768.0; // necessary for blip_unscaled to work - double rescale = base_unit / 2 / total; - kernel_unit = (long) base_unit; - - // integrate, first difference, rescale, convert to int - double sum = 0.0; - double next = 0.0; - int const size = this->impulses_size(); - for ( i = 0; i < size; i++ ) - { - impulses [i] = (short) (int) floor( (next - sum) * rescale + 0.5 ); - sum += fimpulse [i]; - next += fimpulse [i + blip_res]; - } - adjust_impulse(); - - // volume might require rescaling - double vol = volume_unit_; - if ( vol ) - { - volume_unit_ = 0.0; - volume_unit( vol ); - } -} - -void Blip_Synth_::volume_unit( double new_unit ) -{ - if ( new_unit != volume_unit_ ) - { - // use default eq if it hasn't been set yet - if ( !kernel_unit ) - treble_eq( -8.0 ); - - volume_unit_ = new_unit; - double factor = new_unit * (1L << blip_sample_bits) / kernel_unit; - - if ( factor > 0.0 ) - { - int shift = 0; - - // if unit is really small, might need to attenuate kernel - while ( factor < 2.0 ) - { - shift++; - factor *= 2.0; - } - - if ( shift ) - { - kernel_unit >>= shift; - assert( kernel_unit > 0 ); // fails if volume unit is too low - - // keep values positive to avoid round-towards-zero of sign-preserving - // right shift for negative values - long offset = 0x8000 + (1 << (shift - 1)); - long offset2 = 0x8000 >> shift; - for ( int i = impulses_size(); i--; ) - impulses [i] = (short) (int) (((impulses [i] + offset) >> shift) - offset2); - adjust_impulse(); - } - } - delta_factor = (int) floor( factor + 0.5 ); - //printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit ); - } -} -#endif - -long Blip_Buffer::read_samples( blip_sample_t* out_, long max_samples, int stereo ) -{ - long count = samples_avail(); - if ( count > max_samples ) - count = max_samples; - - if ( count ) - { - int const bass = BLIP_READER_BASS( *this ); - BLIP_READER_BEGIN( reader, *this ); - BLIP_READER_ADJ_( reader, count ); - blip_sample_t* BLIP_RESTRICT out = out_ + count; - blip_long offset = (blip_long) -count; - - if ( !stereo ) - { - do - { - blip_long s = BLIP_READER_READ( reader ); - BLIP_READER_NEXT_IDX_( reader, bass, offset ); - BLIP_CLAMP( s, s ); - out [offset] = (blip_sample_t) s; - } - while ( ++offset ); - } - else - { - do - { - blip_long s = BLIP_READER_READ( reader ); - BLIP_READER_NEXT_IDX_( reader, bass, offset ); - BLIP_CLAMP( s, s ); - out [offset * 2] = (blip_sample_t) s; - } - while ( ++offset ); - } - - BLIP_READER_END( reader, *this ); - - remove_samples( count ); - } - return count; -} - -void Blip_Buffer::mix_samples( blip_sample_t const* in, long count ) -{ - if ( buffer_size_ == silent_buf_size ) - { - assert( 0 ); - return; - } - - buf_t_* out = buffer_ + (offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2; - - int const sample_shift = blip_sample_bits - 16; - int prev = 0; - while ( count-- ) - { - blip_long s = (blip_long) *in++ << sample_shift; - *out += s - prev; - prev = s; - ++out; - } - *out -= prev; -} - -blip_ulong const subsample_mask = (1L << BLIP_BUFFER_ACCURACY) - 1; - -void Blip_Buffer::save_state( blip_buffer_state_t* out ) -{ - assert( samples_avail() == 0 ); - out->offset_ = offset_; - out->reader_accum_ = reader_accum_; - memcpy( out->buf, &buffer_ [offset_ >> BLIP_BUFFER_ACCURACY], sizeof out->buf ); -} - -void Blip_Buffer::load_state( blip_buffer_state_t const& in ) -{ - clear( false ); - - offset_ = in.offset_; - reader_accum_ = in.reader_accum_; - memcpy( buffer_, in.buf, sizeof in.buf ); -} +// Blip_Buffer 0.4.1. http://www.slack.net/~ant/ + +#include "Blip_Buffer.h" + +#include +#include +#include +#include +#include + +/* Copyright (C) 2003-2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +// TODO: use scoped for variables in treble_eq() + +#ifdef BLARGG_ENABLE_OPTIMIZER + #include BLARGG_ENABLE_OPTIMIZER +#endif + +int const silent_buf_size = 1; // size used for Silent_Blip_Buffer + +Blip_Buffer::Blip_Buffer() +{ + factor_ = LONG_MAX; + buffer_ = 0; + buffer_size_ = 0; + sample_rate_ = 0; + bass_shift_ = 0; + clock_rate_ = 0; + bass_freq_ = 16; + length_ = 0; + + // assumptions code makes about implementation-defined features + #ifndef NDEBUG + // right shift of negative value preserves sign + buf_t_ i = -0x7FFFFFFE; + assert( (i >> 1) == -0x3FFFFFFF ); + + // casting to short truncates to 16 bits and sign-extends + i = 0x18000; + assert( (short) i == -0x8000 ); + #endif + + clear(); +} + +Blip_Buffer::~Blip_Buffer() +{ + if ( buffer_size_ != silent_buf_size ) + free( buffer_ ); +} + +Silent_Blip_Buffer::Silent_Blip_Buffer() +{ + factor_ = 0; + buffer_ = buf; + buffer_size_ = silent_buf_size; + clear(); +} + +void Blip_Buffer::clear( int entire_buffer ) +{ + offset_ = 0; + reader_accum_ = 0; + modified_ = 0; + if ( buffer_ ) + { + long count = (entire_buffer ? buffer_size_ : samples_avail()); + memset( buffer_, 0, (count + blip_buffer_extra_) * sizeof (buf_t_) ); + } +} + +Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec ) +{ + if ( buffer_size_ == silent_buf_size ) + { + assert( 0 ); + return "Internal (tried to resize Silent_Blip_Buffer)"; + } + + // start with maximum length that resampled time can represent + long new_size = (ULONG_MAX >> BLIP_BUFFER_ACCURACY) - blip_buffer_extra_ - 64; + if ( msec != blip_max_length ) + { + long s = (new_rate * (msec + 1) + 999) / 1000; + if ( s < new_size ) + new_size = s; + else + assert( 0 ); // fails if requested buffer length exceeds limit + } + + if ( buffer_size_ != new_size ) + { + void* p = realloc( buffer_, (new_size + blip_buffer_extra_) * sizeof *buffer_ ); + if ( !p ) + return "Out of memory"; + buffer_ = (buf_t_*) p; + } + + buffer_size_ = new_size; + assert( buffer_size_ != silent_buf_size ); // size should never happen to match this + + // update things based on the sample rate + sample_rate_ = new_rate; + length_ = new_size * 1000 / new_rate - 1; + if ( msec ) + assert( length_ == msec ); // ensure length is same as that passed in + + // update these since they depend on sample rate + if ( clock_rate_ ) + clock_rate( clock_rate_ ); + bass_freq( bass_freq_ ); + + clear(); + + return 0; // success +} + +blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const +{ + double ratio = (double) sample_rate_ / rate; + blip_long factor = (blip_long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 ); + assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large + return (blip_resampled_time_t) factor; +} + +void Blip_Buffer::bass_freq( int freq ) +{ + bass_freq_ = freq; + int shift = 31; + if ( freq > 0 ) + { + shift = 13; + long f = (freq << 16) / sample_rate_; + while ( (f >>= 1) && --shift ) { } + } + bass_shift_ = shift; +} + +void Blip_Buffer::end_frame( blip_time_t t ) +{ + offset_ += t * factor_; + assert( samples_avail() <= (long) buffer_size_ ); // fails if time is past end of buffer +} + +long Blip_Buffer::count_samples( blip_time_t t ) const +{ + blip_resampled_time_t last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY; + blip_resampled_time_t first_sample = offset_ >> BLIP_BUFFER_ACCURACY; + return long (last_sample - first_sample); +} + +blip_time_t Blip_Buffer::count_clocks( long count ) const +{ + if ( !factor_ ) + { + assert( 0 ); // sample rate and clock rates must be set first + return 0; + } + + if ( count > buffer_size_ ) + count = buffer_size_; + blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; + return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_); +} + +void Blip_Buffer::remove_samples( long count ) +{ + if ( count ) + { + remove_silence( count ); + + // copy remaining samples to beginning and clear old samples + long remain = samples_avail() + blip_buffer_extra_; + memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ ); + memset( buffer_ + remain, 0, count * sizeof *buffer_ ); + } +} + +// Blip_Synth_ + +Blip_Synth_Fast_::Blip_Synth_Fast_() +{ + buf = 0; + last_amp = 0; + delta_factor = 0; +} + +void Blip_Synth_Fast_::volume_unit( double new_unit ) +{ + delta_factor = int (new_unit * (1L << blip_sample_bits) + 0.5); +} + +#if !BLIP_BUFFER_FAST + +Blip_Synth_::Blip_Synth_( short* p, int w ) : + impulses( p ), + width( w ) +{ + volume_unit_ = 0.0; + kernel_unit = 0; + buf = 0; + last_amp = 0; + delta_factor = 0; +} + +#undef PI +#define PI 3.1415926535897932384626433832795029 + +static void gen_sinc( float* out, int count, double oversample, double treble, double cutoff ) +{ + if ( cutoff >= 0.999 ) + cutoff = 0.999; + + if ( treble < -300.0 ) + treble = -300.0; + if ( treble > 5.0 ) + treble = 5.0; + + double const maxh = 4096.0; + double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) ); + double const pow_a_n = pow( rolloff, maxh - maxh * cutoff ); + double const to_angle = PI / 2 / maxh / oversample; + for ( int i = 0; i < count; i++ ) + { + double angle = ((i - count) * 2 + 1) * to_angle; + double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle ); + double cos_nc_angle = cos( maxh * cutoff * angle ); + double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle ); + double cos_angle = cos( angle ); + + c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle; + double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle); + double b = 2.0 - cos_angle - cos_angle; + double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle; + + out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d + } +} + +void blip_eq_t::generate( float* out, int count ) const +{ + // lower cutoff freq for narrow kernels with their wider transition band + // (8 points->1.49, 16 points->1.15) + double oversample = blip_res * 2.25 / count + 0.85; + double half_rate = sample_rate * 0.5; + if ( cutoff_freq ) + oversample = half_rate / cutoff_freq; + double cutoff = rolloff_freq * oversample / half_rate; + + gen_sinc( out, count, blip_res * oversample, treble, cutoff ); + + // apply (half of) hamming window + double to_fraction = PI / (count - 1); + for ( int i = count; i--; ) + out [i] *= 0.54f - 0.46f * (float) cos( i * to_fraction ); +} + +void Blip_Synth_::adjust_impulse() +{ + // sum pairs for each phase and add error correction to end of first half + int const size = impulses_size(); + for ( int p = blip_res; p-- >= blip_res / 2; ) + { + int p2 = blip_res - 2 - p; + long error = kernel_unit; + for ( int i = 1; i < size; i += blip_res ) + { + error -= impulses [i + p ]; + error -= impulses [i + p2]; + } + if ( p == p2 ) + error /= 2; // phase = 0.5 impulse uses same half for both sides + impulses [size - blip_res + p] += (short) error; + //printf( "error: %ld\n", error ); + } + + //for ( int i = blip_res; i--; printf( "\n" ) ) + // for ( int j = 0; j < width / 2; j++ ) + // printf( "%5ld,", impulses [j * blip_res + i + 1] ); +} + +void Blip_Synth_::treble_eq( blip_eq_t const& eq ) +{ + float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2]; + + int const half_size = blip_res / 2 * (width - 1); + eq.generate( &fimpulse [blip_res], half_size ); + + int i; + + // need mirror slightly past center for calculation + for ( i = blip_res; i--; ) + fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i]; + + // starts at 0 + for ( i = 0; i < blip_res; i++ ) + fimpulse [i] = 0.0f; + + // find rescale factor + double total = 0.0; + for ( i = 0; i < half_size; i++ ) + total += fimpulse [blip_res + i]; + + //double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB + //double const base_unit = 37888.0; // allows treble to +5 dB + double const base_unit = 32768.0; // necessary for blip_unscaled to work + double rescale = base_unit / 2 / total; + kernel_unit = (long) base_unit; + + // integrate, first difference, rescale, convert to int + double sum = 0.0; + double next = 0.0; + int const size = this->impulses_size(); + for ( i = 0; i < size; i++ ) + { + impulses [i] = (short) (int) floor( (next - sum) * rescale + 0.5 ); + sum += fimpulse [i]; + next += fimpulse [i + blip_res]; + } + adjust_impulse(); + + // volume might require rescaling + double vol = volume_unit_; + if ( vol ) + { + volume_unit_ = 0.0; + volume_unit( vol ); + } +} + +void Blip_Synth_::volume_unit( double new_unit ) +{ + if ( new_unit != volume_unit_ ) + { + // use default eq if it hasn't been set yet + if ( !kernel_unit ) + treble_eq( -8.0 ); + + volume_unit_ = new_unit; + double factor = new_unit * (1L << blip_sample_bits) / kernel_unit; + + if ( factor > 0.0 ) + { + int shift = 0; + + // if unit is really small, might need to attenuate kernel + while ( factor < 2.0 ) + { + shift++; + factor *= 2.0; + } + + if ( shift ) + { + kernel_unit >>= shift; + assert( kernel_unit > 0 ); // fails if volume unit is too low + + // keep values positive to avoid round-towards-zero of sign-preserving + // right shift for negative values + long offset = 0x8000 + (1 << (shift - 1)); + long offset2 = 0x8000 >> shift; + for ( int i = impulses_size(); i--; ) + impulses [i] = (short) (int) (((impulses [i] + offset) >> shift) - offset2); + adjust_impulse(); + } + } + delta_factor = (int) floor( factor + 0.5 ); + //printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit ); + } +} +#endif + +long Blip_Buffer::read_samples( blip_sample_t* out_, long max_samples, int stereo ) +{ + long count = samples_avail(); + if ( count > max_samples ) + count = max_samples; + + if ( count ) + { + int const bass = BLIP_READER_BASS( *this ); + BLIP_READER_BEGIN( reader, *this ); + BLIP_READER_ADJ_( reader, count ); + blip_sample_t* BLIP_RESTRICT out = out_ + count; + blip_long offset = (blip_long) -count; + + if ( !stereo ) + { + do + { + blip_long s = BLIP_READER_READ( reader ); + BLIP_READER_NEXT_IDX_( reader, bass, offset ); + BLIP_CLAMP( s, s ); + out [offset] = (blip_sample_t) s; + } + while ( ++offset ); + } + else + { + do + { + blip_long s = BLIP_READER_READ( reader ); + BLIP_READER_NEXT_IDX_( reader, bass, offset ); + BLIP_CLAMP( s, s ); + out [offset * 2] = (blip_sample_t) s; + } + while ( ++offset ); + } + + BLIP_READER_END( reader, *this ); + + remove_samples( count ); + } + return count; +} + +void Blip_Buffer::mix_samples( blip_sample_t const* in, long count ) +{ + if ( buffer_size_ == silent_buf_size ) + { + assert( 0 ); + return; + } + + buf_t_* out = buffer_ + (offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2; + + int const sample_shift = blip_sample_bits - 16; + int prev = 0; + while ( count-- ) + { + blip_long s = (blip_long) *in++ << sample_shift; + *out += s - prev; + prev = s; + ++out; + } + *out -= prev; +} + +blip_ulong const subsample_mask = (1L << BLIP_BUFFER_ACCURACY) - 1; + +void Blip_Buffer::save_state( blip_buffer_state_t* out ) +{ + assert( samples_avail() == 0 ); + out->offset_ = offset_; + out->reader_accum_ = reader_accum_; + memcpy( out->buf, &buffer_ [offset_ >> BLIP_BUFFER_ACCURACY], sizeof out->buf ); +} + +void Blip_Buffer::load_state( blip_buffer_state_t const& in ) +{ + clear( false ); + + offset_ = in.offset_; + reader_accum_ = in.reader_accum_; + memcpy( buffer_, in.buf, sizeof in.buf ); +} diff --git a/src/dmg/gb_apu/Blip_Buffer.h b/src/dmg/gb_apu/Blip_Buffer.h index 831dcd67..850f0957 100644 --- a/src/dmg/gb_apu/Blip_Buffer.h +++ b/src/dmg/gb_apu/Blip_Buffer.h @@ -1,556 +1,556 @@ -// Band-limited sound synthesis buffer - -// Blip_Buffer 0.4.1 -#ifndef BLIP_BUFFER_H -#define BLIP_BUFFER_H - - // internal - #include - #if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF - typedef long blip_long; - typedef unsigned long blip_ulong; - #else - typedef int blip_long; - typedef unsigned blip_ulong; - #endif - -// Time unit at source clock rate -typedef blip_long blip_time_t; - -// Output samples are 16-bit signed, with a range of -32768 to 32767 -typedef short blip_sample_t; -enum { blip_sample_max = 32767 }; - -struct blip_buffer_state_t; - -class Blip_Buffer { -public: - typedef const char* blargg_err_t; - - // Sets output sample rate and buffer length in milliseconds (1/1000 sec, defaults - // to 1/4 second) and clears buffer. If there isn't enough memory, leaves buffer - // untouched and returns "Out of memory", otherwise returns NULL. - blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 ); - - // Sets number of source time units per second - void clock_rate( long clocks_per_sec ); - - // Ends current time frame of specified duration and makes its samples available - // (along with any still-unread samples) for reading with read_samples(). Begins - // a new time frame at the end of the current frame. - void end_frame( blip_time_t time ); - - // Reads at most 'max_samples' out of buffer into 'dest', removing them from from - // the buffer. Returns number of samples actually read and removed. If stereo is - // true, increments 'dest' one extra time after writing each sample, to allow - // easy interleving of two channels into a stereo output buffer. - long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 ); - -// Additional features - - // Removes all available samples and clear buffer to silence. If 'entire_buffer' is - // false, just clears out any samples waiting rather than the entire buffer. - void clear( int entire_buffer = 1 ); - - // Number of samples available for reading with read_samples() - long samples_avail() const; - - // Removes 'count' samples from those waiting to be read - void remove_samples( long count ); - - // Sets frequency high-pass filter frequency, where higher values reduce bass more - void bass_freq( int frequency ); - - // Current output sample rate - long sample_rate() const; - - // Length of buffer in milliseconds - int length() const; - - // Number of source time units per second - long clock_rate() const; - -// Experimental features - - // Saves state, including high-pass filter and tails of last deltas. - // All samples must have been read from buffer before calling this. - void save_state( blip_buffer_state_t* out ); - - // Loads state. State must have been saved from Blip_Buffer with same - // settings during same run of program. States can NOT be stored on disk. - // Clears buffer before loading state. - void load_state( blip_buffer_state_t const& in ); - - // Number of samples delay from synthesis to samples read out - int output_latency() const; - - // Counts number of clocks needed until 'count' samples will be available. - // If buffer can't even hold 'count' samples, returns number of clocks until - // buffer becomes full. - blip_time_t count_clocks( long count ) const; - - // Number of raw samples that can be mixed within frame of specified duration. - long count_samples( blip_time_t duration ) const; - - // Mixes in 'count' samples from 'buf_in' - void mix_samples( blip_sample_t const* buf_in, long count ); - - - // Signals that sound has been added to buffer. Could be done automatically in - // Blip_Synth, but that would affect performance more, as you can arrange that - // this is called only once per time frame rather than for every delta. - void set_modified() { modified_ = this; } - - // not documented yet - blip_ulong unsettled() const; - Blip_Buffer* clear_modified() { Blip_Buffer* b = modified_; modified_ = 0; return b; } - void remove_silence( long count ); - typedef blip_ulong blip_resampled_time_t; - blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; } - blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; } - blip_resampled_time_t clock_rate_factor( long clock_rate ) const; -public: - Blip_Buffer(); - ~Blip_Buffer(); - - // Deprecated - typedef blip_resampled_time_t resampled_time_t; - blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); } - blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); } -private: - // noncopyable - Blip_Buffer( const Blip_Buffer& ); - Blip_Buffer& operator = ( const Blip_Buffer& ); -public: - typedef blip_long buf_t_; - blip_ulong factor_; - blip_resampled_time_t offset_; - buf_t_* buffer_; - blip_long buffer_size_; - blip_long reader_accum_; - int bass_shift_; -private: - long sample_rate_; - long clock_rate_; - int bass_freq_; - int length_; - Blip_Buffer* modified_; // non-zero = true (more optimal than using bool, heh) - friend class Blip_Reader; -}; - -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -// Number of bits in resample ratio fraction. Higher values give a more accurate ratio -// but reduce maximum buffer size. -#ifndef BLIP_BUFFER_ACCURACY - #define BLIP_BUFFER_ACCURACY 16 -#endif - -// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in -// noticeable broadband noise when synthesizing high frequency square waves. -// Affects size of Blip_Synth objects since they store the waveform directly. -#ifndef BLIP_PHASE_BITS - #if BLIP_BUFFER_FAST - #define BLIP_PHASE_BITS 8 - #else - #define BLIP_PHASE_BITS 6 - #endif -#endif - - // Internal - typedef blip_ulong blip_resampled_time_t; - int const blip_widest_impulse_ = 16; - int const blip_buffer_extra_ = blip_widest_impulse_ + 2; - int const blip_res = 1 << BLIP_PHASE_BITS; - class blip_eq_t; - - class Blip_Synth_Fast_ { - public: - Blip_Buffer* buf; - int last_amp; - int delta_factor; - - void volume_unit( double ); - Blip_Synth_Fast_(); - void treble_eq( blip_eq_t const& ) { } - }; - - class Blip_Synth_ { - public: - Blip_Buffer* buf; - int last_amp; - int delta_factor; - - void volume_unit( double ); - Blip_Synth_( short* impulses, int width ); - void treble_eq( blip_eq_t const& ); - private: - double volume_unit_; - short* const impulses; - int const width; - blip_long kernel_unit; - int impulses_size() const { return blip_res / 2 * width + 1; } - void adjust_impulse(); - }; - -// Quality level, better = slower. In general, use blip_good_quality. -const int blip_med_quality = 8; -const int blip_good_quality = 12; -const int blip_high_quality = 16; - -// Range specifies the greatest expected change in amplitude. Calculate it -// by finding the difference between the maximum and minimum expected -// amplitudes (max - min). -template -class Blip_Synth { -public: - // Sets overall volume of waveform - void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); } - - // Configures low-pass filter (see blip_buffer.txt) - void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); } - - // Gets/sets Blip_Buffer used for output - Blip_Buffer* output() const { return impl.buf; } - void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; } - - // Updates amplitude of waveform at given time. Using this requires a separate - // Blip_Synth for each waveform. - void update( blip_time_t time, int amplitude ); - -// Low-level interface - - // Adds an amplitude transition of specified delta, optionally into specified buffer - // rather than the one set with output(). Delta can be positive or negative. - // The actual change in amplitude is delta * (volume / range) - void offset( blip_time_t, int delta, Blip_Buffer* ) const; - void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); } - - // Works directly in terms of fractional output samples. Contact author for more info. - void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const; - - // Same as offset(), except code is inlined for higher performance - void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const { - offset_resampled( t * buf->factor_ + buf->offset_, delta, buf ); - } - void offset_inline( blip_time_t t, int delta ) const { - offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf ); - } - -private: -#if BLIP_BUFFER_FAST - Blip_Synth_Fast_ impl; -#else - Blip_Synth_ impl; - typedef short imp_t; - imp_t impulses [blip_res * (quality / 2) + 1]; -public: - Blip_Synth() : impl( impulses, quality ) { } -#endif -}; - -// Low-pass equalization parameters -class blip_eq_t { -public: - // Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce - // treble, small positive values (0 to 5.0) increase treble. - blip_eq_t( double treble_db = 0 ); - - // See blip_buffer.txt - blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 ); - -private: - double treble; - long rolloff_freq; - long sample_rate; - long cutoff_freq; - void generate( float* out, int count ) const; - friend class Blip_Synth_; -}; - -int const blip_sample_bits = 30; - -// Dummy Blip_Buffer to direct sound output to, for easy muting without -// having to stop sound code. -class Silent_Blip_Buffer : public Blip_Buffer { - buf_t_ buf [blip_buffer_extra_ + 1]; -public: - // The following cannot be used (an assertion will fail if attempted): - blargg_err_t set_sample_rate( long samples_per_sec, int msec_length ); - blip_time_t count_clocks( long count ) const; - void mix_samples( blip_sample_t const* buf, long count ); - - Silent_Blip_Buffer(); -}; - - #if __GNUC__ >= 3 || _MSC_VER >= 1100 - #define BLIP_RESTRICT __restrict - #else - #define BLIP_RESTRICT - #endif - -// Optimized reading from Blip_Buffer, for use in custom sample output - -// Begins reading from buffer. Name should be unique to the current block. -#define BLIP_READER_BEGIN( name, blip_buffer ) \ - const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\ - blip_long name##_reader_accum = (blip_buffer).reader_accum_ - -// Gets value to pass to BLIP_READER_NEXT() -#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_) - -// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal -// code at the cost of having no bass control -int const blip_reader_default_bass = 9; - -// Current sample -#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16)) - -// Current raw sample in full internal resolution -#define BLIP_READER_READ_RAW( name ) (name##_reader_accum) - -// Advances to next sample -#define BLIP_READER_NEXT( name, bass ) \ - (void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass))) - -// Ends reading samples from buffer. The number of samples read must now be removed -// using Blip_Buffer::remove_samples(). -#define BLIP_READER_END( name, blip_buffer ) \ - (void) ((blip_buffer).reader_accum_ = name##_reader_accum) - - -// experimental -#define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset) - -blip_long const blip_reader_idx_factor = sizeof (Blip_Buffer::buf_t_); - -#define BLIP_READER_NEXT_IDX_( name, bass, idx ) {\ - name##_reader_accum -= name##_reader_accum >> (bass);\ - name##_reader_accum += name##_reader_buf [(idx)];\ -} - -#define BLIP_READER_NEXT_RAW_IDX_( name, bass, idx ) {\ - name##_reader_accum -= name##_reader_accum >> (bass);\ - name##_reader_accum +=\ - *(Blip_Buffer::buf_t_ const*) ((char const*) name##_reader_buf + (idx));\ -} - -// Compatibility with older version -const long blip_unscaled = 65535; -const int blip_low_quality = blip_med_quality; -const int blip_best_quality = blip_high_quality; - -// Deprecated; use BLIP_READER macros as follows: -// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf ); -// int bass = r.begin( buf ) -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf ); -// r.read() -> BLIP_READER_READ( r ) -// r.read_raw() -> BLIP_READER_READ_RAW( r ) -// r.next( bass ) -> BLIP_READER_NEXT( r, bass ) -// r.next() -> BLIP_READER_NEXT( r, blip_reader_default_bass ) -// r.end( buf ) -> BLIP_READER_END( r, buf ) -class Blip_Reader { -public: - int begin( Blip_Buffer& ); - blip_long read() const { return accum >> (blip_sample_bits - 16); } - blip_long read_raw() const { return accum; } - void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); } - void end( Blip_Buffer& b ) { b.reader_accum_ = accum; } -private: - const Blip_Buffer::buf_t_* buf; - blip_long accum; -}; - -#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ - defined (__x86_64__) || defined (__ia64__) || defined (__i386__) - #define BLIP_CLAMP_( in ) in < -0x8000 || 0x7FFF < in -#else - #define BLIP_CLAMP_( in ) (blip_sample_t) in != in -#endif - -// Clamp sample to blip_sample_t range -#define BLIP_CLAMP( sample, out )\ - { if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 24) ^ 0x7FFF; } - -struct blip_buffer_state_t -{ - blip_resampled_time_t offset_; - blip_long reader_accum_; - blip_long buf [blip_buffer_extra_]; -}; - -// End of public interface - -#ifndef assert - #include -#endif - -template -inline void Blip_Synth::offset_resampled( blip_resampled_time_t time, - int delta, Blip_Buffer* blip_buf ) const -{ - // If this assertion fails, it means that an attempt was made to add a delta - // at a negative time or past the end of the buffer. - assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ ); - - delta *= impl.delta_factor; - blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY); - int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1)); - -#if BLIP_BUFFER_FAST - blip_long left = buf [0] + delta; - - // Kind of crappy, but doing shift after multiply results in overflow. - // Alternate way of delaying multiply by delta_factor results in worse - // sub-sample resolution. - blip_long right = (delta >> BLIP_PHASE_BITS) * phase; - left -= right; - right += buf [1]; - - buf [0] = left; - buf [1] = right; -#else - - int const fwd = (blip_widest_impulse_ - quality) / 2; - int const rev = fwd + quality - 2; - int const mid = quality / 2 - 1; - - imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase; - - #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ - defined (__x86_64__) || defined (__ia64__) || defined (__i386__) - - // this straight forward version gave in better code on GCC for x86 - - #define ADD_IMP( out, in ) \ - buf [out] += (blip_long) imp [blip_res * (in)] * delta - - #define BLIP_FWD( i ) {\ - ADD_IMP( fwd + i, i );\ - ADD_IMP( fwd + 1 + i, i + 1 );\ - } - #define BLIP_REV( r ) {\ - ADD_IMP( rev - r, r + 1 );\ - ADD_IMP( rev + 1 - r, r );\ - } - - BLIP_FWD( 0 ) - if ( quality > 8 ) BLIP_FWD( 2 ) - if ( quality > 12 ) BLIP_FWD( 4 ) - { - ADD_IMP( fwd + mid - 1, mid - 1 ); - ADD_IMP( fwd + mid , mid ); - imp = impulses + phase; - } - if ( quality > 12 ) BLIP_REV( 6 ) - if ( quality > 8 ) BLIP_REV( 4 ) - BLIP_REV( 2 ) - - ADD_IMP( rev , 1 ); - ADD_IMP( rev + 1, 0 ); - - #undef ADD_IMP - - #else - - // for RISC processors, help compiler by reading ahead of writes - - #define BLIP_FWD( i ) {\ - blip_long t0 = i0 * delta + buf [fwd + i];\ - blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\ - i0 = imp [blip_res * (i + 2)];\ - buf [fwd + i] = t0;\ - buf [fwd + 1 + i] = t1;\ - } - #define BLIP_REV( r ) {\ - blip_long t0 = i0 * delta + buf [rev - r];\ - blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\ - i0 = imp [blip_res * (r - 1)];\ - buf [rev - r] = t0;\ - buf [rev + 1 - r] = t1;\ - } - - blip_long i0 = *imp; - BLIP_FWD( 0 ) - if ( quality > 8 ) BLIP_FWD( 2 ) - if ( quality > 12 ) BLIP_FWD( 4 ) - { - blip_long t0 = i0 * delta + buf [fwd + mid - 1]; - blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid ]; - imp = impulses + phase; - i0 = imp [blip_res * mid]; - buf [fwd + mid - 1] = t0; - buf [fwd + mid ] = t1; - } - if ( quality > 12 ) BLIP_REV( 6 ) - if ( quality > 8 ) BLIP_REV( 4 ) - BLIP_REV( 2 ) - - blip_long t0 = i0 * delta + buf [rev ]; - blip_long t1 = *imp * delta + buf [rev + 1]; - buf [rev ] = t0; - buf [rev + 1] = t1; - #endif - -#endif -} - -#undef BLIP_FWD -#undef BLIP_REV - -template -#if BLIP_BUFFER_FAST - inline -#endif -void Blip_Synth::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const -{ - offset_resampled( t * buf->factor_ + buf->offset_, delta, buf ); -} - -template -#if BLIP_BUFFER_FAST - inline -#endif -void Blip_Synth::update( blip_time_t t, int amp ) -{ - int delta = amp - impl.last_amp; - impl.last_amp = amp; - offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf ); -} - -inline blip_eq_t::blip_eq_t( double t ) : - treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { } -inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) : - treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { } - -inline int Blip_Buffer::length() const { return length_; } -inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); } -inline long Blip_Buffer::sample_rate() const { return sample_rate_; } -inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; } -inline long Blip_Buffer::clock_rate() const { return clock_rate_; } -inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); } - -inline int Blip_Reader::begin( Blip_Buffer& blip_buf ) -{ - buf = blip_buf.buffer_; - accum = blip_buf.reader_accum_; - return blip_buf.bass_shift_; -} - -inline void Blip_Buffer::remove_silence( long count ) -{ - // fails if you try to remove more samples than available - assert( count <= samples_avail() ); - offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; -} - -inline blip_ulong Blip_Buffer::unsettled() const -{ - return reader_accum_ >> (blip_sample_bits - 16); -} - -int const blip_max_length = 0; -int const blip_default_length = 250; // 1/4 second - -#endif +// Band-limited sound synthesis buffer + +// Blip_Buffer 0.4.1 +#ifndef BLIP_BUFFER_H +#define BLIP_BUFFER_H + + // internal + #include + #if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF + typedef long blip_long; + typedef unsigned long blip_ulong; + #else + typedef int blip_long; + typedef unsigned blip_ulong; + #endif + +// Time unit at source clock rate +typedef blip_long blip_time_t; + +// Output samples are 16-bit signed, with a range of -32768 to 32767 +typedef short blip_sample_t; +enum { blip_sample_max = 32767 }; + +struct blip_buffer_state_t; + +class Blip_Buffer { +public: + typedef const char* blargg_err_t; + + // Sets output sample rate and buffer length in milliseconds (1/1000 sec, defaults + // to 1/4 second) and clears buffer. If there isn't enough memory, leaves buffer + // untouched and returns "Out of memory", otherwise returns NULL. + blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 ); + + // Sets number of source time units per second + void clock_rate( long clocks_per_sec ); + + // Ends current time frame of specified duration and makes its samples available + // (along with any still-unread samples) for reading with read_samples(). Begins + // a new time frame at the end of the current frame. + void end_frame( blip_time_t time ); + + // Reads at most 'max_samples' out of buffer into 'dest', removing them from from + // the buffer. Returns number of samples actually read and removed. If stereo is + // true, increments 'dest' one extra time after writing each sample, to allow + // easy interleving of two channels into a stereo output buffer. + long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 ); + +// Additional features + + // Removes all available samples and clear buffer to silence. If 'entire_buffer' is + // false, just clears out any samples waiting rather than the entire buffer. + void clear( int entire_buffer = 1 ); + + // Number of samples available for reading with read_samples() + long samples_avail() const; + + // Removes 'count' samples from those waiting to be read + void remove_samples( long count ); + + // Sets frequency high-pass filter frequency, where higher values reduce bass more + void bass_freq( int frequency ); + + // Current output sample rate + long sample_rate() const; + + // Length of buffer in milliseconds + int length() const; + + // Number of source time units per second + long clock_rate() const; + +// Experimental features + + // Saves state, including high-pass filter and tails of last deltas. + // All samples must have been read from buffer before calling this. + void save_state( blip_buffer_state_t* out ); + + // Loads state. State must have been saved from Blip_Buffer with same + // settings during same run of program. States can NOT be stored on disk. + // Clears buffer before loading state. + void load_state( blip_buffer_state_t const& in ); + + // Number of samples delay from synthesis to samples read out + int output_latency() const; + + // Counts number of clocks needed until 'count' samples will be available. + // If buffer can't even hold 'count' samples, returns number of clocks until + // buffer becomes full. + blip_time_t count_clocks( long count ) const; + + // Number of raw samples that can be mixed within frame of specified duration. + long count_samples( blip_time_t duration ) const; + + // Mixes in 'count' samples from 'buf_in' + void mix_samples( blip_sample_t const* buf_in, long count ); + + + // Signals that sound has been added to buffer. Could be done automatically in + // Blip_Synth, but that would affect performance more, as you can arrange that + // this is called only once per time frame rather than for every delta. + void set_modified() { modified_ = this; } + + // not documented yet + blip_ulong unsettled() const; + Blip_Buffer* clear_modified() { Blip_Buffer* b = modified_; modified_ = 0; return b; } + void remove_silence( long count ); + typedef blip_ulong blip_resampled_time_t; + blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; } + blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; } + blip_resampled_time_t clock_rate_factor( long clock_rate ) const; +public: + Blip_Buffer(); + ~Blip_Buffer(); + + // Deprecated + typedef blip_resampled_time_t resampled_time_t; + blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); } + blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); } +private: + // noncopyable + Blip_Buffer( const Blip_Buffer& ); + Blip_Buffer& operator = ( const Blip_Buffer& ); +public: + typedef blip_long buf_t_; + blip_ulong factor_; + blip_resampled_time_t offset_; + buf_t_* buffer_; + blip_long buffer_size_; + blip_long reader_accum_; + int bass_shift_; +private: + long sample_rate_; + long clock_rate_; + int bass_freq_; + int length_; + Blip_Buffer* modified_; // non-zero = true (more optimal than using bool, heh) + friend class Blip_Reader; +}; + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +// Number of bits in resample ratio fraction. Higher values give a more accurate ratio +// but reduce maximum buffer size. +#ifndef BLIP_BUFFER_ACCURACY + #define BLIP_BUFFER_ACCURACY 16 +#endif + +// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in +// noticeable broadband noise when synthesizing high frequency square waves. +// Affects size of Blip_Synth objects since they store the waveform directly. +#ifndef BLIP_PHASE_BITS + #if BLIP_BUFFER_FAST + #define BLIP_PHASE_BITS 8 + #else + #define BLIP_PHASE_BITS 6 + #endif +#endif + + // Internal + typedef blip_ulong blip_resampled_time_t; + int const blip_widest_impulse_ = 16; + int const blip_buffer_extra_ = blip_widest_impulse_ + 2; + int const blip_res = 1 << BLIP_PHASE_BITS; + class blip_eq_t; + + class Blip_Synth_Fast_ { + public: + Blip_Buffer* buf; + int last_amp; + int delta_factor; + + void volume_unit( double ); + Blip_Synth_Fast_(); + void treble_eq( blip_eq_t const& ) { } + }; + + class Blip_Synth_ { + public: + Blip_Buffer* buf; + int last_amp; + int delta_factor; + + void volume_unit( double ); + Blip_Synth_( short* impulses, int width ); + void treble_eq( blip_eq_t const& ); + private: + double volume_unit_; + short* const impulses; + int const width; + blip_long kernel_unit; + int impulses_size() const { return blip_res / 2 * width + 1; } + void adjust_impulse(); + }; + +// Quality level, better = slower. In general, use blip_good_quality. +const int blip_med_quality = 8; +const int blip_good_quality = 12; +const int blip_high_quality = 16; + +// Range specifies the greatest expected change in amplitude. Calculate it +// by finding the difference between the maximum and minimum expected +// amplitudes (max - min). +template +class Blip_Synth { +public: + // Sets overall volume of waveform + void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); } + + // Configures low-pass filter (see blip_buffer.txt) + void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); } + + // Gets/sets Blip_Buffer used for output + Blip_Buffer* output() const { return impl.buf; } + void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; } + + // Updates amplitude of waveform at given time. Using this requires a separate + // Blip_Synth for each waveform. + void update( blip_time_t time, int amplitude ); + +// Low-level interface + + // Adds an amplitude transition of specified delta, optionally into specified buffer + // rather than the one set with output(). Delta can be positive or negative. + // The actual change in amplitude is delta * (volume / range) + void offset( blip_time_t, int delta, Blip_Buffer* ) const; + void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); } + + // Works directly in terms of fractional output samples. Contact author for more info. + void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const; + + // Same as offset(), except code is inlined for higher performance + void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const { + offset_resampled( t * buf->factor_ + buf->offset_, delta, buf ); + } + void offset_inline( blip_time_t t, int delta ) const { + offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf ); + } + +private: +#if BLIP_BUFFER_FAST + Blip_Synth_Fast_ impl; +#else + Blip_Synth_ impl; + typedef short imp_t; + imp_t impulses [blip_res * (quality / 2) + 1]; +public: + Blip_Synth() : impl( impulses, quality ) { } +#endif +}; + +// Low-pass equalization parameters +class blip_eq_t { +public: + // Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce + // treble, small positive values (0 to 5.0) increase treble. + blip_eq_t( double treble_db = 0 ); + + // See blip_buffer.txt + blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 ); + +private: + double treble; + long rolloff_freq; + long sample_rate; + long cutoff_freq; + void generate( float* out, int count ) const; + friend class Blip_Synth_; +}; + +int const blip_sample_bits = 30; + +// Dummy Blip_Buffer to direct sound output to, for easy muting without +// having to stop sound code. +class Silent_Blip_Buffer : public Blip_Buffer { + buf_t_ buf [blip_buffer_extra_ + 1]; +public: + // The following cannot be used (an assertion will fail if attempted): + blargg_err_t set_sample_rate( long samples_per_sec, int msec_length ); + blip_time_t count_clocks( long count ) const; + void mix_samples( blip_sample_t const* buf, long count ); + + Silent_Blip_Buffer(); +}; + + #if __GNUC__ >= 3 || _MSC_VER >= 1100 + #define BLIP_RESTRICT __restrict + #else + #define BLIP_RESTRICT + #endif + +// Optimized reading from Blip_Buffer, for use in custom sample output + +// Begins reading from buffer. Name should be unique to the current block. +#define BLIP_READER_BEGIN( name, blip_buffer ) \ + const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\ + blip_long name##_reader_accum = (blip_buffer).reader_accum_ + +// Gets value to pass to BLIP_READER_NEXT() +#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_) + +// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal +// code at the cost of having no bass control +int const blip_reader_default_bass = 9; + +// Current sample +#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16)) + +// Current raw sample in full internal resolution +#define BLIP_READER_READ_RAW( name ) (name##_reader_accum) + +// Advances to next sample +#define BLIP_READER_NEXT( name, bass ) \ + (void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass))) + +// Ends reading samples from buffer. The number of samples read must now be removed +// using Blip_Buffer::remove_samples(). +#define BLIP_READER_END( name, blip_buffer ) \ + (void) ((blip_buffer).reader_accum_ = name##_reader_accum) + + +// experimental +#define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset) + +blip_long const blip_reader_idx_factor = sizeof (Blip_Buffer::buf_t_); + +#define BLIP_READER_NEXT_IDX_( name, bass, idx ) {\ + name##_reader_accum -= name##_reader_accum >> (bass);\ + name##_reader_accum += name##_reader_buf [(idx)];\ +} + +#define BLIP_READER_NEXT_RAW_IDX_( name, bass, idx ) {\ + name##_reader_accum -= name##_reader_accum >> (bass);\ + name##_reader_accum +=\ + *(Blip_Buffer::buf_t_ const*) ((char const*) name##_reader_buf + (idx));\ +} + +// Compatibility with older version +const long blip_unscaled = 65535; +const int blip_low_quality = blip_med_quality; +const int blip_best_quality = blip_high_quality; + +// Deprecated; use BLIP_READER macros as follows: +// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf ); +// int bass = r.begin( buf ) -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf ); +// r.read() -> BLIP_READER_READ( r ) +// r.read_raw() -> BLIP_READER_READ_RAW( r ) +// r.next( bass ) -> BLIP_READER_NEXT( r, bass ) +// r.next() -> BLIP_READER_NEXT( r, blip_reader_default_bass ) +// r.end( buf ) -> BLIP_READER_END( r, buf ) +class Blip_Reader { +public: + int begin( Blip_Buffer& ); + blip_long read() const { return accum >> (blip_sample_bits - 16); } + blip_long read_raw() const { return accum; } + void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); } + void end( Blip_Buffer& b ) { b.reader_accum_ = accum; } +private: + const Blip_Buffer::buf_t_* buf; + blip_long accum; +}; + +#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ + defined (__x86_64__) || defined (__ia64__) || defined (__i386__) + #define BLIP_CLAMP_( in ) in < -0x8000 || 0x7FFF < in +#else + #define BLIP_CLAMP_( in ) (blip_sample_t) in != in +#endif + +// Clamp sample to blip_sample_t range +#define BLIP_CLAMP( sample, out )\ + { if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 24) ^ 0x7FFF; } + +struct blip_buffer_state_t +{ + blip_resampled_time_t offset_; + blip_long reader_accum_; + blip_long buf [blip_buffer_extra_]; +}; + +// End of public interface + +#ifndef assert + #include +#endif + +template +inline void Blip_Synth::offset_resampled( blip_resampled_time_t time, + int delta, Blip_Buffer* blip_buf ) const +{ + // If this assertion fails, it means that an attempt was made to add a delta + // at a negative time or past the end of the buffer. + assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ ); + + delta *= impl.delta_factor; + blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY); + int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1)); + +#if BLIP_BUFFER_FAST + blip_long left = buf [0] + delta; + + // Kind of crappy, but doing shift after multiply results in overflow. + // Alternate way of delaying multiply by delta_factor results in worse + // sub-sample resolution. + blip_long right = (delta >> BLIP_PHASE_BITS) * phase; + left -= right; + right += buf [1]; + + buf [0] = left; + buf [1] = right; +#else + + int const fwd = (blip_widest_impulse_ - quality) / 2; + int const rev = fwd + quality - 2; + int const mid = quality / 2 - 1; + + imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase; + + #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ + defined (__x86_64__) || defined (__ia64__) || defined (__i386__) + + // this straight forward version gave in better code on GCC for x86 + + #define ADD_IMP( out, in ) \ + buf [out] += (blip_long) imp [blip_res * (in)] * delta + + #define BLIP_FWD( i ) {\ + ADD_IMP( fwd + i, i );\ + ADD_IMP( fwd + 1 + i, i + 1 );\ + } + #define BLIP_REV( r ) {\ + ADD_IMP( rev - r, r + 1 );\ + ADD_IMP( rev + 1 - r, r );\ + } + + BLIP_FWD( 0 ) + if ( quality > 8 ) BLIP_FWD( 2 ) + if ( quality > 12 ) BLIP_FWD( 4 ) + { + ADD_IMP( fwd + mid - 1, mid - 1 ); + ADD_IMP( fwd + mid , mid ); + imp = impulses + phase; + } + if ( quality > 12 ) BLIP_REV( 6 ) + if ( quality > 8 ) BLIP_REV( 4 ) + BLIP_REV( 2 ) + + ADD_IMP( rev , 1 ); + ADD_IMP( rev + 1, 0 ); + + #undef ADD_IMP + + #else + + // for RISC processors, help compiler by reading ahead of writes + + #define BLIP_FWD( i ) {\ + blip_long t0 = i0 * delta + buf [fwd + i];\ + blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\ + i0 = imp [blip_res * (i + 2)];\ + buf [fwd + i] = t0;\ + buf [fwd + 1 + i] = t1;\ + } + #define BLIP_REV( r ) {\ + blip_long t0 = i0 * delta + buf [rev - r];\ + blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\ + i0 = imp [blip_res * (r - 1)];\ + buf [rev - r] = t0;\ + buf [rev + 1 - r] = t1;\ + } + + blip_long i0 = *imp; + BLIP_FWD( 0 ) + if ( quality > 8 ) BLIP_FWD( 2 ) + if ( quality > 12 ) BLIP_FWD( 4 ) + { + blip_long t0 = i0 * delta + buf [fwd + mid - 1]; + blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid ]; + imp = impulses + phase; + i0 = imp [blip_res * mid]; + buf [fwd + mid - 1] = t0; + buf [fwd + mid ] = t1; + } + if ( quality > 12 ) BLIP_REV( 6 ) + if ( quality > 8 ) BLIP_REV( 4 ) + BLIP_REV( 2 ) + + blip_long t0 = i0 * delta + buf [rev ]; + blip_long t1 = *imp * delta + buf [rev + 1]; + buf [rev ] = t0; + buf [rev + 1] = t1; + #endif + +#endif +} + +#undef BLIP_FWD +#undef BLIP_REV + +template +#if BLIP_BUFFER_FAST + inline +#endif +void Blip_Synth::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const +{ + offset_resampled( t * buf->factor_ + buf->offset_, delta, buf ); +} + +template +#if BLIP_BUFFER_FAST + inline +#endif +void Blip_Synth::update( blip_time_t t, int amp ) +{ + int delta = amp - impl.last_amp; + impl.last_amp = amp; + offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf ); +} + +inline blip_eq_t::blip_eq_t( double t ) : + treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { } +inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) : + treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { } + +inline int Blip_Buffer::length() const { return length_; } +inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); } +inline long Blip_Buffer::sample_rate() const { return sample_rate_; } +inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; } +inline long Blip_Buffer::clock_rate() const { return clock_rate_; } +inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); } + +inline int Blip_Reader::begin( Blip_Buffer& blip_buf ) +{ + buf = blip_buf.buffer_; + accum = blip_buf.reader_accum_; + return blip_buf.bass_shift_; +} + +inline void Blip_Buffer::remove_silence( long count ) +{ + // fails if you try to remove more samples than available + assert( count <= samples_avail() ); + offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; +} + +inline blip_ulong Blip_Buffer::unsettled() const +{ + return reader_accum_ >> (blip_sample_bits - 16); +} + +int const blip_max_length = 0; +int const blip_default_length = 250; // 1/4 second + +#endif diff --git a/src/dmg/gb_apu/Effects_Buffer.cpp b/src/dmg/gb_apu/Effects_Buffer.cpp index deff3f0e..c418bad5 100644 --- a/src/dmg/gb_apu/Effects_Buffer.cpp +++ b/src/dmg/gb_apu/Effects_Buffer.cpp @@ -1,638 +1,638 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Effects_Buffer.h" - -#include - -/* Copyright (C) 2006-2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -int const fixed_shift = 12; -#define TO_FIXED( f ) fixed_t ((f) * ((fixed_t) 1 << fixed_shift)) -#define FROM_FIXED( f ) ((f) >> fixed_shift) - -int const max_read = 2560; // determines minimum delay - -Effects_Buffer::Effects_Buffer( int max_bufs, long echo_size_ ) : Multi_Buffer( stereo ) -{ - echo_size = max( max_read * (long) stereo, echo_size_ & ~1 ); - clock_rate_ = 0; - bass_freq_ = 90; - bufs = 0; - bufs_size = 0; - bufs_max = max( max_bufs, (int) extra_chans ); - no_echo = true; - no_effects = true; - - // defaults - config_.enabled = false; - config_.delay [0] = 120; - config_.delay [1] = 122; - config_.feedback = 0.2f; - config_.treble = 0.4f; - - static float const sep = 0.8f; - config_.side_chans [0].pan = -sep; - config_.side_chans [1].pan = +sep; - config_.side_chans [0].vol = 1.0f; - config_.side_chans [1].vol = 1.0f; - - memset( &s, 0, sizeof s ); - clear(); -} - -Effects_Buffer::~Effects_Buffer() -{ - delete_bufs(); -} - -// avoid using new [] -blargg_err_t Effects_Buffer::new_bufs( int size ) -{ - bufs = (buf_t*) malloc( size * sizeof *bufs ); - CHECK_ALLOC( bufs ); - for ( int i = 0; i < size; i++ ) - new (bufs + i) buf_t; - bufs_size = size; - return 0; -} - -void Effects_Buffer::delete_bufs() -{ - if ( bufs ) - { - for ( int i = bufs_size; --i >= 0; ) - bufs [i].~buf_t(); - free( bufs ); - bufs = 0; - } - bufs_size = 0; -} - -blargg_err_t Effects_Buffer::set_sample_rate( long rate, int msec ) -{ - // extra to allow farther past-the-end pointers - mixer.samples_read = 0; - RETURN_ERR( echo.resize( echo_size + stereo ) ); - return Multi_Buffer::set_sample_rate( rate, msec ); -} - -void Effects_Buffer::clock_rate( long rate ) -{ - clock_rate_ = rate; - for ( int i = bufs_size; --i >= 0; ) - bufs [i].clock_rate( clock_rate_ ); -} - -void Effects_Buffer::bass_freq( int freq ) -{ - bass_freq_ = freq; - for ( int i = bufs_size; --i >= 0; ) - bufs [i].bass_freq( bass_freq_ ); -} - -blargg_err_t Effects_Buffer::set_channel_count( int count, int const* types ) -{ - RETURN_ERR( Multi_Buffer::set_channel_count( count, types ) ); - - delete_bufs(); - - mixer.samples_read = 0; - - RETURN_ERR( chans.resize( count + extra_chans ) ); - - RETURN_ERR( new_bufs( min( bufs_max, count + extra_chans ) ) ); - - for ( int i = bufs_size; --i >= 0; ) - RETURN_ERR( bufs [i].set_sample_rate( sample_rate(), length() ) ); - - for ( int i = chans.size(); --i >= 0; ) - { - chan_t& ch = chans [i]; - ch.cfg.vol = 1.0f; - ch.cfg.pan = 0.0f; - ch.cfg.surround = false; - ch.cfg.echo = false; - } - // side channels with echo - chans [2].cfg.echo = true; - chans [3].cfg.echo = true; - - clock_rate( clock_rate_ ); - bass_freq( bass_freq_ ); - apply_config(); - clear(); - - return 0; -} - -void Effects_Buffer::clear_echo() -{ - if ( echo.size() ) - memset( echo.begin(), 0, echo.size() * sizeof echo [0] ); -} - -void Effects_Buffer::clear() -{ - echo_pos = 0; - s.low_pass [0] = 0; - s.low_pass [1] = 0; - mixer.samples_read = 0; - - for ( int i = bufs_size; --i >= 0; ) - bufs [i].clear(); - clear_echo(); -} - -Effects_Buffer::channel_t Effects_Buffer::channel( int i ) -{ - i += extra_chans; - require( extra_chans <= i && i < (int) chans.size() ); - return chans [i].channel; -} - - -// Configuration - -// 3 wave positions with/without surround, 2 multi (one with same config as wave) -int const simple_bufs = 3 * 2 + 2 - 1; - -Simple_Effects_Buffer::Simple_Effects_Buffer() : - Effects_Buffer( extra_chans + simple_bufs, 18 * 1024L ) -{ - config_.echo = 0.20f; - config_.stereo = 0.20f; - config_.surround = true; - config_.enabled = false; -} - -void Simple_Effects_Buffer::apply_config() -{ - Effects_Buffer::config_t& c = Effects_Buffer::config(); - - c.enabled = config_.enabled; - if ( c.enabled ) - { - c.delay [0] = 120; - c.delay [1] = 122; - c.feedback = config_.echo * 0.7f; - c.treble = 0.6f - 0.3f * config_.echo; - - float sep = config_.stereo + 0.80f; - if ( sep > 1.0f ) - sep = 1.0f; - - c.side_chans [0].pan = -sep; - c.side_chans [1].pan = +sep; - - for ( int i = channel_count(); --i >= 0; ) - { - chan_config_t& ch = Effects_Buffer::chan_config( i ); - - ch.pan = 0.0f; - ch.surround = config_.surround; - ch.echo = false; - - int const type = (channel_types() ? channel_types() [i] : 0); - if ( !(type & noise_type) ) - { - int index = (type & type_index_mask) % 6 - 3; - if ( index < 0 ) - { - index += 3; - ch.surround = false; - ch.echo = true; - } - if ( index >= 1 ) - { - ch.pan = config_.stereo; - if ( index == 1 ) - ch.pan = -ch.pan; - } - } - else if ( type & 1 ) - { - ch.surround = false; - } - } - } - - Effects_Buffer::apply_config(); -} - -int Effects_Buffer::min_delay() const -{ - require( sample_rate() ); - return max_read * 1000L / sample_rate(); -} - -int Effects_Buffer::max_delay() const -{ - require( sample_rate() ); - return (echo_size / stereo - max_read) * 1000L / sample_rate(); -} - -void Effects_Buffer::apply_config() -{ - int i; - - if ( !bufs_size ) - return; - - s.treble = TO_FIXED( config_.treble ); - - bool echo_dirty = false; - - fixed_t old_feedback = s.feedback; - s.feedback = TO_FIXED( config_.feedback ); - if ( !old_feedback && s.feedback ) - echo_dirty = true; - - // delays - for ( i = stereo; --i >= 0; ) - { - long delay = config_.delay [i] * sample_rate() / 1000 * stereo; - delay = max( delay, long (max_read * stereo) ); - delay = min( delay, long (echo_size - max_read * stereo) ); - if ( s.delay [i] != delay ) - { - s.delay [i] = delay; - echo_dirty = true; - } - } - - // side channels - for ( i = 2; --i >= 0; ) - { - chans [i+2].cfg.vol = chans [i].cfg.vol = config_.side_chans [i].vol * 0.5f; - chans [i+2].cfg.pan = chans [i].cfg.pan = config_.side_chans [i].pan; - } - - // convert volumes - for ( i = chans.size(); --i >= 0; ) - { - chan_t& ch = chans [i]; - ch.vol [0] = TO_FIXED( ch.cfg.vol - ch.cfg.vol * ch.cfg.pan ); - ch.vol [1] = TO_FIXED( ch.cfg.vol + ch.cfg.vol * ch.cfg.pan ); - if ( ch.cfg.surround ) - ch.vol [0] = -ch.vol [0]; - } - - assign_buffers(); - - // set side channels - for ( i = chans.size(); --i >= 0; ) - { - chan_t& ch = chans [i]; - ch.channel.left = chans [ch.cfg.echo*2 ].channel.center; - ch.channel.right = chans [ch.cfg.echo*2+1].channel.center; - } - - bool old_echo = !no_echo && !no_effects; - - // determine whether effects and echo are needed at all - no_effects = true; - no_echo = true; - for ( i = chans.size(); --i >= extra_chans; ) - { - chan_t& ch = chans [i]; - if ( ch.cfg.echo && s.feedback ) - no_echo = false; - - if ( ch.vol [0] != TO_FIXED( 1 ) || ch.vol [1] != TO_FIXED( 1 ) ) - no_effects = false; - } - if ( !no_echo ) - no_effects = false; - - if ( chans [0].vol [0] != TO_FIXED( 1 ) || - chans [0].vol [1] != TO_FIXED( 0 ) || - chans [1].vol [0] != TO_FIXED( 0 ) || - chans [1].vol [1] != TO_FIXED( 1 ) ) - no_effects = false; - - if ( !config_.enabled ) - no_effects = true; - - if ( no_effects ) - { - for ( i = chans.size(); --i >= 0; ) - { - chan_t& ch = chans [i]; - ch.channel.center = &bufs [2]; - ch.channel.left = &bufs [0]; - ch.channel.right = &bufs [1]; - } - } - - mixer.bufs [0] = &bufs [0]; - mixer.bufs [1] = &bufs [1]; - mixer.bufs [2] = &bufs [2]; - - if ( echo_dirty || (!old_echo && (!no_echo && !no_effects)) ) - clear_echo(); - - channels_changed(); -} - -void Effects_Buffer::assign_buffers() -{ - // assign channels to buffers - int buf_count = 0; - for ( int i = 0; i < (int) chans.size(); i++ ) - { - // put second two side channels at end to give priority to main channels - // in case closest matching is necessary - int x = i; - if ( i > 1 ) - x += 2; - if ( x >= (int) chans.size() ) - x -= (chans.size() - 2); - chan_t& ch = chans [x]; - - int b = 0; - for ( ; b < buf_count; b++ ) - { - if ( ch.vol [0] == bufs [b].vol [0] && - ch.vol [1] == bufs [b].vol [1] && - (ch.cfg.echo == bufs [b].echo || !s.feedback) ) - break; - } - - if ( b >= buf_count ) - { - if ( buf_count < bufs_max ) - { - bufs [b].vol [0] = ch.vol [0]; - bufs [b].vol [1] = ch.vol [1]; - bufs [b].echo = ch.cfg.echo; - buf_count++; - } - else - { - // TODO: this is a mess, needs refinement - dprintf( "Effects_Buffer ran out of buffers; using closest match\n" ); - b = 0; - fixed_t best_dist = TO_FIXED( 8 ); - for ( int h = buf_count; --h >= 0; ) - { - #define CALC_LEVELS( vols, sum, diff, surround ) \ - fixed_t sum, diff;\ - bool surround = false;\ - {\ - fixed_t vol_0 = vols [0];\ - if ( vol_0 < 0 ) vol_0 = -vol_0, surround = true;\ - fixed_t vol_1 = vols [1];\ - if ( vol_1 < 0 ) vol_1 = -vol_1, surround = true;\ - sum = vol_0 + vol_1;\ - diff = vol_0 - vol_1;\ - } - CALC_LEVELS( ch.vol, ch_sum, ch_diff, ch_surround ); - CALC_LEVELS( bufs [h].vol, buf_sum, buf_diff, buf_surround ); - - fixed_t dist = abs( ch_sum - buf_sum ) + abs( ch_diff - buf_diff ); - - if ( ch_surround != buf_surround ) - dist += TO_FIXED( 1 ) / 2; - - if ( s.feedback && ch.cfg.echo != bufs [h].echo ) - dist += TO_FIXED( 1 ) / 2; - - if ( best_dist > dist ) - { - best_dist = dist; - b = h; - } - } - } - } - - //dprintf( "ch %d->buf %d\n", x, b ); - ch.channel.center = &bufs [b]; - } -} - - -// Mixing - -void Effects_Buffer::end_frame( blip_time_t time ) -{ - for ( int i = bufs_size; --i >= 0; ) - bufs [i].end_frame( time ); -} - -long Effects_Buffer::read_samples( blip_sample_t* out, long out_size ) -{ - out_size = min( out_size, samples_avail() ); - - int pair_count = int (out_size >> 1); - require( pair_count * stereo == out_size ); // must read an even number of samples - if ( pair_count ) - { - if ( no_effects ) - { - mixer.read_pairs( out, pair_count ); - } - else - { - int pairs_remain = pair_count; - do - { - // mix at most max_read pairs at a time - int count = max_read; - if ( count > pairs_remain ) - count = pairs_remain; - - if ( no_echo ) - { - // optimization: clear echo here to keep mix_effects() a leaf function - echo_pos = 0; - memset( echo.begin(), 0, count * stereo * sizeof echo [0] ); - } - mix_effects( out, count ); - - blargg_long new_echo_pos = echo_pos + count * stereo; - if ( new_echo_pos >= echo_size ) - new_echo_pos -= echo_size; - echo_pos = new_echo_pos; - assert( echo_pos < echo_size ); - - out += count * stereo; - mixer.samples_read += count; - pairs_remain -= count; - } - while ( pairs_remain ); - } - - if ( samples_avail() <= 0 || immediate_removal() ) - { - for ( int i = bufs_size; --i >= 0; ) - { - buf_t& b = bufs [i]; - // TODO: might miss non-silence settling since it checks END of last read - if ( b.non_silent() ) - b.remove_samples( mixer.samples_read ); - else - b.remove_silence( mixer.samples_read ); - } - mixer.samples_read = 0; - } - } - return out_size; -} - -void Effects_Buffer::mix_effects( blip_sample_t* out_, int pair_count ) -{ - typedef fixed_t stereo_fixed_t [stereo]; - - // add channels with echo, do echo, add channels without echo, then convert to 16-bit and output - int echo_phase = 1; - do - { - // mix any modified buffers - { - buf_t* buf = bufs; - int bufs_remain = bufs_size; - do - { - if ( buf->non_silent() && ( buf->echo == (bool)echo_phase ) ) - { - stereo_fixed_t* BLIP_RESTRICT out = (stereo_fixed_t*) &echo [echo_pos]; - int const bass = BLIP_READER_BASS( *buf ); - BLIP_READER_BEGIN( in, *buf ); - BLIP_READER_ADJ_( in, mixer.samples_read ); - fixed_t const vol_0 = buf->vol [0]; - fixed_t const vol_1 = buf->vol [1]; - - int count = unsigned (echo_size - echo_pos) / stereo; - int remain = pair_count; - if ( count > remain ) - count = remain; - do - { - remain -= count; - BLIP_READER_ADJ_( in, count ); - - out += count; - int offset = -count; - do - { - fixed_t s = BLIP_READER_READ( in ); - BLIP_READER_NEXT_IDX_( in, bass, offset ); - - out [offset] [0] += s * vol_0; - out [offset] [1] += s * vol_1; - } - while ( ++offset ); - - out = (stereo_fixed_t*) echo.begin(); - count = remain; - } - while ( remain ); - - BLIP_READER_END( in, *buf ); - } - buf++; - } - while ( --bufs_remain ); - } - - // add echo - if ( echo_phase && !no_echo ) - { - fixed_t const feedback = s.feedback; - fixed_t const treble = s.treble; - - int i = 1; - do - { - fixed_t low_pass = s.low_pass [i]; - - fixed_t* echo_end = &echo [echo_size + i]; - fixed_t const* BLIP_RESTRICT in_pos = &echo [echo_pos + i]; - blargg_long out_offset = echo_pos + i + s.delay [i]; - if ( out_offset >= echo_size ) - out_offset -= echo_size; - assert( out_offset < echo_size ); - fixed_t* BLIP_RESTRICT out_pos = &echo [out_offset]; - - // break into up to three chunks to avoid having to handle wrap-around - // in middle of core loop - int remain = pair_count; - do - { - fixed_t const* pos = in_pos; - if ( pos < out_pos ) - pos = out_pos; - int count = blargg_ulong ((char*) echo_end - (char const*) pos) / - unsigned (stereo * sizeof (fixed_t)); - if ( count > remain ) - count = remain; - remain -= count; - - in_pos += count * stereo; - out_pos += count * stereo; - int offset = -count; - do - { - low_pass += FROM_FIXED( in_pos [offset * stereo] - low_pass ) * treble; - out_pos [offset * stereo] = FROM_FIXED( low_pass ) * feedback; - } - while ( ++offset ); - - if ( in_pos >= echo_end ) in_pos -= echo_size; - if ( out_pos >= echo_end ) out_pos -= echo_size; - } - while ( remain ); - - s.low_pass [i] = low_pass; - } - while ( --i >= 0 ); - } - } - while ( --echo_phase >= 0 ); - - // clamp to 16 bits - { - stereo_fixed_t const* BLIP_RESTRICT in = (stereo_fixed_t*) &echo [echo_pos]; - typedef blip_sample_t stereo_blip_sample_t [stereo]; - stereo_blip_sample_t* BLIP_RESTRICT out = (stereo_blip_sample_t*) out_; - int count = unsigned (echo_size - echo_pos) / (unsigned) stereo; - int remain = pair_count; - if ( count > remain ) - count = remain; - do - { - remain -= count; - in += count; - out += count; - int offset = -count; - do - { - fixed_t in_0 = FROM_FIXED( in [offset] [0] ); - fixed_t in_1 = FROM_FIXED( in [offset] [1] ); - - BLIP_CLAMP( in_0, in_0 ); - out [offset] [0] = (blip_sample_t) in_0; - - BLIP_CLAMP( in_1, in_1 ); - out [offset] [1] = (blip_sample_t) in_1; - } - while ( ++offset ); - - in = (stereo_fixed_t*) echo.begin(); - count = remain; - } - while ( remain ); - } -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Effects_Buffer.h" + +#include + +/* Copyright (C) 2006-2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +int const fixed_shift = 12; +#define TO_FIXED( f ) fixed_t ((f) * ((fixed_t) 1 << fixed_shift)) +#define FROM_FIXED( f ) ((f) >> fixed_shift) + +int const max_read = 2560; // determines minimum delay + +Effects_Buffer::Effects_Buffer( int max_bufs, long echo_size_ ) : Multi_Buffer( stereo ) +{ + echo_size = max( max_read * (long) stereo, echo_size_ & ~1 ); + clock_rate_ = 0; + bass_freq_ = 90; + bufs = 0; + bufs_size = 0; + bufs_max = max( max_bufs, (int) extra_chans ); + no_echo = true; + no_effects = true; + + // defaults + config_.enabled = false; + config_.delay [0] = 120; + config_.delay [1] = 122; + config_.feedback = 0.2f; + config_.treble = 0.4f; + + static float const sep = 0.8f; + config_.side_chans [0].pan = -sep; + config_.side_chans [1].pan = +sep; + config_.side_chans [0].vol = 1.0f; + config_.side_chans [1].vol = 1.0f; + + memset( &s, 0, sizeof s ); + clear(); +} + +Effects_Buffer::~Effects_Buffer() +{ + delete_bufs(); +} + +// avoid using new [] +blargg_err_t Effects_Buffer::new_bufs( int size ) +{ + bufs = (buf_t*) malloc( size * sizeof *bufs ); + CHECK_ALLOC( bufs ); + for ( int i = 0; i < size; i++ ) + new (bufs + i) buf_t; + bufs_size = size; + return 0; +} + +void Effects_Buffer::delete_bufs() +{ + if ( bufs ) + { + for ( int i = bufs_size; --i >= 0; ) + bufs [i].~buf_t(); + free( bufs ); + bufs = 0; + } + bufs_size = 0; +} + +blargg_err_t Effects_Buffer::set_sample_rate( long rate, int msec ) +{ + // extra to allow farther past-the-end pointers + mixer.samples_read = 0; + RETURN_ERR( echo.resize( echo_size + stereo ) ); + return Multi_Buffer::set_sample_rate( rate, msec ); +} + +void Effects_Buffer::clock_rate( long rate ) +{ + clock_rate_ = rate; + for ( int i = bufs_size; --i >= 0; ) + bufs [i].clock_rate( clock_rate_ ); +} + +void Effects_Buffer::bass_freq( int freq ) +{ + bass_freq_ = freq; + for ( int i = bufs_size; --i >= 0; ) + bufs [i].bass_freq( bass_freq_ ); +} + +blargg_err_t Effects_Buffer::set_channel_count( int count, int const* types ) +{ + RETURN_ERR( Multi_Buffer::set_channel_count( count, types ) ); + + delete_bufs(); + + mixer.samples_read = 0; + + RETURN_ERR( chans.resize( count + extra_chans ) ); + + RETURN_ERR( new_bufs( min( bufs_max, count + extra_chans ) ) ); + + for ( int i = bufs_size; --i >= 0; ) + RETURN_ERR( bufs [i].set_sample_rate( sample_rate(), length() ) ); + + for ( int i = chans.size(); --i >= 0; ) + { + chan_t& ch = chans [i]; + ch.cfg.vol = 1.0f; + ch.cfg.pan = 0.0f; + ch.cfg.surround = false; + ch.cfg.echo = false; + } + // side channels with echo + chans [2].cfg.echo = true; + chans [3].cfg.echo = true; + + clock_rate( clock_rate_ ); + bass_freq( bass_freq_ ); + apply_config(); + clear(); + + return 0; +} + +void Effects_Buffer::clear_echo() +{ + if ( echo.size() ) + memset( echo.begin(), 0, echo.size() * sizeof echo [0] ); +} + +void Effects_Buffer::clear() +{ + echo_pos = 0; + s.low_pass [0] = 0; + s.low_pass [1] = 0; + mixer.samples_read = 0; + + for ( int i = bufs_size; --i >= 0; ) + bufs [i].clear(); + clear_echo(); +} + +Effects_Buffer::channel_t Effects_Buffer::channel( int i ) +{ + i += extra_chans; + require( extra_chans <= i && i < (int) chans.size() ); + return chans [i].channel; +} + + +// Configuration + +// 3 wave positions with/without surround, 2 multi (one with same config as wave) +int const simple_bufs = 3 * 2 + 2 - 1; + +Simple_Effects_Buffer::Simple_Effects_Buffer() : + Effects_Buffer( extra_chans + simple_bufs, 18 * 1024L ) +{ + config_.echo = 0.20f; + config_.stereo = 0.20f; + config_.surround = true; + config_.enabled = false; +} + +void Simple_Effects_Buffer::apply_config() +{ + Effects_Buffer::config_t& c = Effects_Buffer::config(); + + c.enabled = config_.enabled; + if ( c.enabled ) + { + c.delay [0] = 120; + c.delay [1] = 122; + c.feedback = config_.echo * 0.7f; + c.treble = 0.6f - 0.3f * config_.echo; + + float sep = config_.stereo + 0.80f; + if ( sep > 1.0f ) + sep = 1.0f; + + c.side_chans [0].pan = -sep; + c.side_chans [1].pan = +sep; + + for ( int i = channel_count(); --i >= 0; ) + { + chan_config_t& ch = Effects_Buffer::chan_config( i ); + + ch.pan = 0.0f; + ch.surround = config_.surround; + ch.echo = false; + + int const type = (channel_types() ? channel_types() [i] : 0); + if ( !(type & noise_type) ) + { + int index = (type & type_index_mask) % 6 - 3; + if ( index < 0 ) + { + index += 3; + ch.surround = false; + ch.echo = true; + } + if ( index >= 1 ) + { + ch.pan = config_.stereo; + if ( index == 1 ) + ch.pan = -ch.pan; + } + } + else if ( type & 1 ) + { + ch.surround = false; + } + } + } + + Effects_Buffer::apply_config(); +} + +int Effects_Buffer::min_delay() const +{ + require( sample_rate() ); + return max_read * 1000L / sample_rate(); +} + +int Effects_Buffer::max_delay() const +{ + require( sample_rate() ); + return (echo_size / stereo - max_read) * 1000L / sample_rate(); +} + +void Effects_Buffer::apply_config() +{ + int i; + + if ( !bufs_size ) + return; + + s.treble = TO_FIXED( config_.treble ); + + bool echo_dirty = false; + + fixed_t old_feedback = s.feedback; + s.feedback = TO_FIXED( config_.feedback ); + if ( !old_feedback && s.feedback ) + echo_dirty = true; + + // delays + for ( i = stereo; --i >= 0; ) + { + long delay = config_.delay [i] * sample_rate() / 1000 * stereo; + delay = max( delay, long (max_read * stereo) ); + delay = min( delay, long (echo_size - max_read * stereo) ); + if ( s.delay [i] != delay ) + { + s.delay [i] = delay; + echo_dirty = true; + } + } + + // side channels + for ( i = 2; --i >= 0; ) + { + chans [i+2].cfg.vol = chans [i].cfg.vol = config_.side_chans [i].vol * 0.5f; + chans [i+2].cfg.pan = chans [i].cfg.pan = config_.side_chans [i].pan; + } + + // convert volumes + for ( i = chans.size(); --i >= 0; ) + { + chan_t& ch = chans [i]; + ch.vol [0] = TO_FIXED( ch.cfg.vol - ch.cfg.vol * ch.cfg.pan ); + ch.vol [1] = TO_FIXED( ch.cfg.vol + ch.cfg.vol * ch.cfg.pan ); + if ( ch.cfg.surround ) + ch.vol [0] = -ch.vol [0]; + } + + assign_buffers(); + + // set side channels + for ( i = chans.size(); --i >= 0; ) + { + chan_t& ch = chans [i]; + ch.channel.left = chans [ch.cfg.echo*2 ].channel.center; + ch.channel.right = chans [ch.cfg.echo*2+1].channel.center; + } + + bool old_echo = !no_echo && !no_effects; + + // determine whether effects and echo are needed at all + no_effects = true; + no_echo = true; + for ( i = chans.size(); --i >= extra_chans; ) + { + chan_t& ch = chans [i]; + if ( ch.cfg.echo && s.feedback ) + no_echo = false; + + if ( ch.vol [0] != TO_FIXED( 1 ) || ch.vol [1] != TO_FIXED( 1 ) ) + no_effects = false; + } + if ( !no_echo ) + no_effects = false; + + if ( chans [0].vol [0] != TO_FIXED( 1 ) || + chans [0].vol [1] != TO_FIXED( 0 ) || + chans [1].vol [0] != TO_FIXED( 0 ) || + chans [1].vol [1] != TO_FIXED( 1 ) ) + no_effects = false; + + if ( !config_.enabled ) + no_effects = true; + + if ( no_effects ) + { + for ( i = chans.size(); --i >= 0; ) + { + chan_t& ch = chans [i]; + ch.channel.center = &bufs [2]; + ch.channel.left = &bufs [0]; + ch.channel.right = &bufs [1]; + } + } + + mixer.bufs [0] = &bufs [0]; + mixer.bufs [1] = &bufs [1]; + mixer.bufs [2] = &bufs [2]; + + if ( echo_dirty || (!old_echo && (!no_echo && !no_effects)) ) + clear_echo(); + + channels_changed(); +} + +void Effects_Buffer::assign_buffers() +{ + // assign channels to buffers + int buf_count = 0; + for ( int i = 0; i < (int) chans.size(); i++ ) + { + // put second two side channels at end to give priority to main channels + // in case closest matching is necessary + int x = i; + if ( i > 1 ) + x += 2; + if ( x >= (int) chans.size() ) + x -= (chans.size() - 2); + chan_t& ch = chans [x]; + + int b = 0; + for ( ; b < buf_count; b++ ) + { + if ( ch.vol [0] == bufs [b].vol [0] && + ch.vol [1] == bufs [b].vol [1] && + (ch.cfg.echo == bufs [b].echo || !s.feedback) ) + break; + } + + if ( b >= buf_count ) + { + if ( buf_count < bufs_max ) + { + bufs [b].vol [0] = ch.vol [0]; + bufs [b].vol [1] = ch.vol [1]; + bufs [b].echo = ch.cfg.echo; + buf_count++; + } + else + { + // TODO: this is a mess, needs refinement + dprintf( "Effects_Buffer ran out of buffers; using closest match\n" ); + b = 0; + fixed_t best_dist = TO_FIXED( 8 ); + for ( int h = buf_count; --h >= 0; ) + { + #define CALC_LEVELS( vols, sum, diff, surround ) \ + fixed_t sum, diff;\ + bool surround = false;\ + {\ + fixed_t vol_0 = vols [0];\ + if ( vol_0 < 0 ) vol_0 = -vol_0, surround = true;\ + fixed_t vol_1 = vols [1];\ + if ( vol_1 < 0 ) vol_1 = -vol_1, surround = true;\ + sum = vol_0 + vol_1;\ + diff = vol_0 - vol_1;\ + } + CALC_LEVELS( ch.vol, ch_sum, ch_diff, ch_surround ); + CALC_LEVELS( bufs [h].vol, buf_sum, buf_diff, buf_surround ); + + fixed_t dist = abs( ch_sum - buf_sum ) + abs( ch_diff - buf_diff ); + + if ( ch_surround != buf_surround ) + dist += TO_FIXED( 1 ) / 2; + + if ( s.feedback && ch.cfg.echo != bufs [h].echo ) + dist += TO_FIXED( 1 ) / 2; + + if ( best_dist > dist ) + { + best_dist = dist; + b = h; + } + } + } + } + + //dprintf( "ch %d->buf %d\n", x, b ); + ch.channel.center = &bufs [b]; + } +} + + +// Mixing + +void Effects_Buffer::end_frame( blip_time_t time ) +{ + for ( int i = bufs_size; --i >= 0; ) + bufs [i].end_frame( time ); +} + +long Effects_Buffer::read_samples( blip_sample_t* out, long out_size ) +{ + out_size = min( out_size, samples_avail() ); + + int pair_count = int (out_size >> 1); + require( pair_count * stereo == out_size ); // must read an even number of samples + if ( pair_count ) + { + if ( no_effects ) + { + mixer.read_pairs( out, pair_count ); + } + else + { + int pairs_remain = pair_count; + do + { + // mix at most max_read pairs at a time + int count = max_read; + if ( count > pairs_remain ) + count = pairs_remain; + + if ( no_echo ) + { + // optimization: clear echo here to keep mix_effects() a leaf function + echo_pos = 0; + memset( echo.begin(), 0, count * stereo * sizeof echo [0] ); + } + mix_effects( out, count ); + + blargg_long new_echo_pos = echo_pos + count * stereo; + if ( new_echo_pos >= echo_size ) + new_echo_pos -= echo_size; + echo_pos = new_echo_pos; + assert( echo_pos < echo_size ); + + out += count * stereo; + mixer.samples_read += count; + pairs_remain -= count; + } + while ( pairs_remain ); + } + + if ( samples_avail() <= 0 || immediate_removal() ) + { + for ( int i = bufs_size; --i >= 0; ) + { + buf_t& b = bufs [i]; + // TODO: might miss non-silence settling since it checks END of last read + if ( b.non_silent() ) + b.remove_samples( mixer.samples_read ); + else + b.remove_silence( mixer.samples_read ); + } + mixer.samples_read = 0; + } + } + return out_size; +} + +void Effects_Buffer::mix_effects( blip_sample_t* out_, int pair_count ) +{ + typedef fixed_t stereo_fixed_t [stereo]; + + // add channels with echo, do echo, add channels without echo, then convert to 16-bit and output + int echo_phase = 1; + do + { + // mix any modified buffers + { + buf_t* buf = bufs; + int bufs_remain = bufs_size; + do + { + if ( buf->non_silent() && ( buf->echo == (bool)echo_phase ) ) + { + stereo_fixed_t* BLIP_RESTRICT out = (stereo_fixed_t*) &echo [echo_pos]; + int const bass = BLIP_READER_BASS( *buf ); + BLIP_READER_BEGIN( in, *buf ); + BLIP_READER_ADJ_( in, mixer.samples_read ); + fixed_t const vol_0 = buf->vol [0]; + fixed_t const vol_1 = buf->vol [1]; + + int count = unsigned (echo_size - echo_pos) / stereo; + int remain = pair_count; + if ( count > remain ) + count = remain; + do + { + remain -= count; + BLIP_READER_ADJ_( in, count ); + + out += count; + int offset = -count; + do + { + fixed_t s = BLIP_READER_READ( in ); + BLIP_READER_NEXT_IDX_( in, bass, offset ); + + out [offset] [0] += s * vol_0; + out [offset] [1] += s * vol_1; + } + while ( ++offset ); + + out = (stereo_fixed_t*) echo.begin(); + count = remain; + } + while ( remain ); + + BLIP_READER_END( in, *buf ); + } + buf++; + } + while ( --bufs_remain ); + } + + // add echo + if ( echo_phase && !no_echo ) + { + fixed_t const feedback = s.feedback; + fixed_t const treble = s.treble; + + int i = 1; + do + { + fixed_t low_pass = s.low_pass [i]; + + fixed_t* echo_end = &echo [echo_size + i]; + fixed_t const* BLIP_RESTRICT in_pos = &echo [echo_pos + i]; + blargg_long out_offset = echo_pos + i + s.delay [i]; + if ( out_offset >= echo_size ) + out_offset -= echo_size; + assert( out_offset < echo_size ); + fixed_t* BLIP_RESTRICT out_pos = &echo [out_offset]; + + // break into up to three chunks to avoid having to handle wrap-around + // in middle of core loop + int remain = pair_count; + do + { + fixed_t const* pos = in_pos; + if ( pos < out_pos ) + pos = out_pos; + int count = blargg_ulong ((char*) echo_end - (char const*) pos) / + unsigned (stereo * sizeof (fixed_t)); + if ( count > remain ) + count = remain; + remain -= count; + + in_pos += count * stereo; + out_pos += count * stereo; + int offset = -count; + do + { + low_pass += FROM_FIXED( in_pos [offset * stereo] - low_pass ) * treble; + out_pos [offset * stereo] = FROM_FIXED( low_pass ) * feedback; + } + while ( ++offset ); + + if ( in_pos >= echo_end ) in_pos -= echo_size; + if ( out_pos >= echo_end ) out_pos -= echo_size; + } + while ( remain ); + + s.low_pass [i] = low_pass; + } + while ( --i >= 0 ); + } + } + while ( --echo_phase >= 0 ); + + // clamp to 16 bits + { + stereo_fixed_t const* BLIP_RESTRICT in = (stereo_fixed_t*) &echo [echo_pos]; + typedef blip_sample_t stereo_blip_sample_t [stereo]; + stereo_blip_sample_t* BLIP_RESTRICT out = (stereo_blip_sample_t*) out_; + int count = unsigned (echo_size - echo_pos) / (unsigned) stereo; + int remain = pair_count; + if ( count > remain ) + count = remain; + do + { + remain -= count; + in += count; + out += count; + int offset = -count; + do + { + fixed_t in_0 = FROM_FIXED( in [offset] [0] ); + fixed_t in_1 = FROM_FIXED( in [offset] [1] ); + + BLIP_CLAMP( in_0, in_0 ); + out [offset] [0] = (blip_sample_t) in_0; + + BLIP_CLAMP( in_1, in_1 ); + out [offset] [1] = (blip_sample_t) in_1; + } + while ( ++offset ); + + in = (stereo_fixed_t*) echo.begin(); + count = remain; + } + while ( remain ); + } +} diff --git a/src/dmg/gb_apu/Effects_Buffer.h b/src/dmg/gb_apu/Effects_Buffer.h index 5d800bb3..790325d9 100644 --- a/src/dmg/gb_apu/Effects_Buffer.h +++ b/src/dmg/gb_apu/Effects_Buffer.h @@ -1,143 +1,143 @@ -// Multi-channel effects buffer with echo and individual panning for each channel - -// Game_Music_Emu $vers -#ifndef EFFECTS_BUFFER_H -#define EFFECTS_BUFFER_H - -#include "Multi_Buffer.h" - -// See Simple_Effects_Buffer (below) for a simpler interface - -class Effects_Buffer : public Multi_Buffer { -public: - // To reduce memory usage, fewer buffers can be used (with a best-fit - // approach if there are too few), and maximum echo delay can be reduced - Effects_Buffer( int max_bufs = 32, long echo_size = 24 * 1024L ); - - struct pan_vol_t - { - float vol; // 0.0 = silent, 0.5 = half volume, 1.0 = normal - float pan; // -1.0 = left, 0.0 = center, +1.0 = right - }; - - // Global configuration - struct config_t - { - bool enabled; // false = disable all effects - - // Current sound is echoed at adjustable left/right delay, - // with reduced treble and volume (feedback). - float treble; // 1.0 = full treble, 0.1 = very little, 0.0 = silent - int delay [2]; // left, right delays (msec) - float feedback; // 0.0 = no echo, 0.5 = each echo half previous, 1.0 = cacophony - pan_vol_t side_chans [2]; // left and right side channel volume and pan - }; - config_t& config() { return config_; } - - // Limits of delay (msec) - int min_delay() const; - int max_delay() const; - - // Per-channel configuration. Two or more channels with matching parameters are - // optimized to internally use the same buffer. - struct chan_config_t : pan_vol_t - { - // (inherited from pan_vol_t) - //float vol; // these only affect center channel - //float pan; - bool surround; // if true, negates left volume to put sound in back - bool echo; // false = channel doesn't have any echo - }; - chan_config_t& chan_config( int i ) { return chans [i + extra_chans].cfg; } - - // Apply any changes made to config() and chan_config() - virtual void apply_config(); - -public: - ~Effects_Buffer(); - blargg_err_t set_sample_rate( long samples_per_sec, int msec = blip_default_length ); - blargg_err_t set_channel_count( int, int const* = 0 ); - void clock_rate( long ); - void bass_freq( int ); - void clear(); - channel_t channel( int ); - void end_frame( blip_time_t ); - long read_samples( blip_sample_t*, long ); - long samples_avail() const { return (bufs [0].samples_avail() - mixer.samples_read) * 2; } - enum { stereo = 2 }; - typedef blargg_long fixed_t; -protected: - enum { extra_chans = stereo * stereo }; -private: - config_t config_; - long clock_rate_; - int bass_freq_; - - blargg_long echo_size; - - struct chan_t - { - fixed_t vol [stereo]; - chan_config_t cfg; - channel_t channel; - }; - blargg_vector chans; - - struct buf_t : Tracked_Blip_Buffer - { - fixed_t vol [stereo]; - bool echo; - - void* operator new ( size_t, void* p ) { return p; } - void operator delete ( void* ) { } - - ~buf_t() { } - }; - buf_t* bufs; - int bufs_size; - int bufs_max; // bufs_size <= bufs_max, to limit memory usage - Stereo_Mixer mixer; - - struct { - long delay [stereo]; - fixed_t treble; - fixed_t feedback; - fixed_t low_pass [stereo]; - } s; - - blargg_vector echo; - blargg_long echo_pos; - - bool no_effects; - bool no_echo; - - void assign_buffers(); - void clear_echo(); - void mix_effects( blip_sample_t* out, int pair_count ); - blargg_err_t new_bufs( int size ); - void delete_bufs(); -}; - -// Simpler interface and lower memory usage -class Simple_Effects_Buffer : public Effects_Buffer { -public: - struct config_t - { - bool enabled; // false = disable all effects - float echo; // 0.0 = none, 1.0 = lots - float stereo; // 0.0 = channels in center, 1.0 = channels on left/right - bool surround; // true = put some channels in back - }; - config_t& config() { return config_; } - - // Apply any changes made to config() - void apply_config(); - -public: - Simple_Effects_Buffer(); -private: - config_t config_; - void chan_config(); // hide -}; - -#endif +// Multi-channel effects buffer with echo and individual panning for each channel + +// Game_Music_Emu $vers +#ifndef EFFECTS_BUFFER_H +#define EFFECTS_BUFFER_H + +#include "Multi_Buffer.h" + +// See Simple_Effects_Buffer (below) for a simpler interface + +class Effects_Buffer : public Multi_Buffer { +public: + // To reduce memory usage, fewer buffers can be used (with a best-fit + // approach if there are too few), and maximum echo delay can be reduced + Effects_Buffer( int max_bufs = 32, long echo_size = 24 * 1024L ); + + struct pan_vol_t + { + float vol; // 0.0 = silent, 0.5 = half volume, 1.0 = normal + float pan; // -1.0 = left, 0.0 = center, +1.0 = right + }; + + // Global configuration + struct config_t + { + bool enabled; // false = disable all effects + + // Current sound is echoed at adjustable left/right delay, + // with reduced treble and volume (feedback). + float treble; // 1.0 = full treble, 0.1 = very little, 0.0 = silent + int delay [2]; // left, right delays (msec) + float feedback; // 0.0 = no echo, 0.5 = each echo half previous, 1.0 = cacophony + pan_vol_t side_chans [2]; // left and right side channel volume and pan + }; + config_t& config() { return config_; } + + // Limits of delay (msec) + int min_delay() const; + int max_delay() const; + + // Per-channel configuration. Two or more channels with matching parameters are + // optimized to internally use the same buffer. + struct chan_config_t : pan_vol_t + { + // (inherited from pan_vol_t) + //float vol; // these only affect center channel + //float pan; + bool surround; // if true, negates left volume to put sound in back + bool echo; // false = channel doesn't have any echo + }; + chan_config_t& chan_config( int i ) { return chans [i + extra_chans].cfg; } + + // Apply any changes made to config() and chan_config() + virtual void apply_config(); + +public: + ~Effects_Buffer(); + blargg_err_t set_sample_rate( long samples_per_sec, int msec = blip_default_length ); + blargg_err_t set_channel_count( int, int const* = 0 ); + void clock_rate( long ); + void bass_freq( int ); + void clear(); + channel_t channel( int ); + void end_frame( blip_time_t ); + long read_samples( blip_sample_t*, long ); + long samples_avail() const { return (bufs [0].samples_avail() - mixer.samples_read) * 2; } + enum { stereo = 2 }; + typedef blargg_long fixed_t; +protected: + enum { extra_chans = stereo * stereo }; +private: + config_t config_; + long clock_rate_; + int bass_freq_; + + blargg_long echo_size; + + struct chan_t + { + fixed_t vol [stereo]; + chan_config_t cfg; + channel_t channel; + }; + blargg_vector chans; + + struct buf_t : Tracked_Blip_Buffer + { + fixed_t vol [stereo]; + bool echo; + + void* operator new ( size_t, void* p ) { return p; } + void operator delete ( void* ) { } + + ~buf_t() { } + }; + buf_t* bufs; + int bufs_size; + int bufs_max; // bufs_size <= bufs_max, to limit memory usage + Stereo_Mixer mixer; + + struct { + long delay [stereo]; + fixed_t treble; + fixed_t feedback; + fixed_t low_pass [stereo]; + } s; + + blargg_vector echo; + blargg_long echo_pos; + + bool no_effects; + bool no_echo; + + void assign_buffers(); + void clear_echo(); + void mix_effects( blip_sample_t* out, int pair_count ); + blargg_err_t new_bufs( int size ); + void delete_bufs(); +}; + +// Simpler interface and lower memory usage +class Simple_Effects_Buffer : public Effects_Buffer { +public: + struct config_t + { + bool enabled; // false = disable all effects + float echo; // 0.0 = none, 1.0 = lots + float stereo; // 0.0 = channels in center, 1.0 = channels on left/right + bool surround; // true = put some channels in back + }; + config_t& config() { return config_; } + + // Apply any changes made to config() + void apply_config(); + +public: + Simple_Effects_Buffer(); +private: + config_t config_; + void chan_config(); // hide +}; + +#endif diff --git a/src/dmg/gb_apu/Gb_Apu.cpp b/src/dmg/gb_apu/Gb_Apu.cpp index f86b29fb..14004d59 100644 --- a/src/dmg/gb_apu/Gb_Apu.cpp +++ b/src/dmg/gb_apu/Gb_Apu.cpp @@ -1,394 +1,394 @@ -// Gb_Snd_Emu 0.2.0. http://www.slack.net/~ant/ - -#include "Gb_Apu.h" - -/* Copyright (C) 2003-2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -unsigned const vol_reg = 0xFF24; -unsigned const stereo_reg = 0xFF25; -unsigned const status_reg = 0xFF26; -unsigned const wave_ram = 0xFF30; - -int const power_mask = 0x80; - -void Gb_Apu::treble_eq( blip_eq_t const& eq ) -{ - good_synth.treble_eq( eq ); - med_synth .treble_eq( eq ); -} - -inline int Gb_Apu::calc_output( int osc ) const -{ - int bits = regs [stereo_reg - start_addr] >> osc; - return (bits >> 3 & 2) | (bits & 1); -} - -void Gb_Apu::set_output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right, int osc ) -{ - // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL) - require( !center || (center && !left && !right) || (center && left && right) ); - require( (unsigned) osc <= osc_count ); // fails if you pass invalid osc index - - if ( !center || !left || !right ) - { - left = center; - right = center; - } - - int i = (unsigned) osc % osc_count; - do - { - Gb_Osc& o = *oscs [i]; - o.outputs [1] = right; - o.outputs [2] = left; - o.outputs [3] = center; - o.output = o.outputs [calc_output( i )]; - } - while ( ++i < osc ); -} - -void Gb_Apu::synth_volume( int iv ) -{ - double v = volume_ * 0.60 / osc_count / 15 /*steps*/ / 8 /*master vol range*/ * iv; - good_synth.volume( v ); - med_synth .volume( v ); -} - -void Gb_Apu::apply_volume() -{ - // TODO: Doesn't handle differing left and right volumes (panning). - // Not worth the complexity. - int data = regs [vol_reg - start_addr]; - int left = data >> 4 & 7; - int right = data & 7; - //if ( data & 0x88 ) dprintf( "Vin: %02X\n", data & 0x88 ); - //if ( left != right ) dprintf( "l: %d r: %d\n", left, right ); - synth_volume( max( left, right ) + 1 ); -} - -void Gb_Apu::volume( double v ) -{ - if ( volume_ != v ) - { - volume_ = v; - apply_volume(); - } -} - -void Gb_Apu::reset_regs() -{ - for ( int i = 0; i < 0x20; i++ ) - regs [i] = 0; - - square1.reset(); - square2.reset(); - wave .reset(); - noise .reset(); - - apply_volume(); -} - -void Gb_Apu::reset_lengths() -{ - square1.length_ctr = 64; - square2.length_ctr = 64; - wave .length_ctr = 256; - noise .length_ctr = 64; -} - -void Gb_Apu::reduce_clicks( bool reduce ) -{ - reduce_clicks_ = reduce; - - // Click reduction makes DAC off generate same output as volume 0 - int dac_off_amp = 0; - if ( reduce && wave.mode != mode_agb ) // AGB already eliminates clicks - dac_off_amp = -Gb_Osc::dac_bias; - - for ( int i = 0; i < osc_count; i++ ) - oscs [i]->dac_off_amp = dac_off_amp; - - // AGB always eliminates clicks on wave channel using same method - if ( wave.mode == mode_agb ) - wave.dac_off_amp = -Gb_Osc::dac_bias; -} - -void Gb_Apu::reset( mode_t mode, bool agb_wave ) -{ - // Hardware mode - if ( agb_wave ) - mode = mode_agb; // using AGB wave features implies AGB hardware - wave.agb_mask = agb_wave ? 0xFF : 0; - for ( int i = 0; i < osc_count; i++ ) - oscs [i]->mode = mode; - reduce_clicks( reduce_clicks_ ); - - // Reset state - frame_time = 0; - last_time = 0; - frame_phase = 0; - - reset_regs(); - reset_lengths(); - - // Load initial wave RAM - static byte const initial_wave [2] [16] = { - {0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C,0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA}, - {0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF}, - }; - for ( int b = 2; --b >= 0; ) - { - // Init both banks (does nothing if not in AGB mode) - // TODO: verify that this works - write_register( 0, 0xFF1A, b * 0x40 ); - for ( unsigned i = 0; i < sizeof initial_wave [0]; i++ ) - write_register( 0, i + wave_ram, initial_wave [(mode != mode_dmg)] [i] ); - } -} - -void Gb_Apu::set_tempo( double t ) -{ - frame_period = 4194304 / 512; // 512 Hz - if ( t != 1.0 ) - frame_period = blip_time_t (frame_period / t); -} - -Gb_Apu::Gb_Apu() -{ - wave.wave_ram = ®s [wave_ram - start_addr]; - - oscs [0] = &square1; - oscs [1] = &square2; - oscs [2] = &wave; - oscs [3] = &noise; - - for ( int i = osc_count; --i >= 0; ) - { - Gb_Osc& o = *oscs [i]; - o.regs = ®s [i * 5]; - o.output = 0; - o.outputs [0] = 0; - o.outputs [1] = 0; - o.outputs [2] = 0; - o.outputs [3] = 0; - o.good_synth = &good_synth; - o.med_synth = &med_synth; - } - - reduce_clicks_ = false; - set_tempo( 1.0 ); - volume_ = 1.0; - reset(); -} - -void Gb_Apu::run_until_( blip_time_t end_time ) -{ - while ( true ) - { - // run oscillators - blip_time_t time = end_time; - if ( time > frame_time ) - time = frame_time; - - square1.run( last_time, time ); - square2.run( last_time, time ); - wave .run( last_time, time ); - noise .run( last_time, time ); - last_time = time; - - if ( time == end_time ) - break; - - // run frame sequencer - frame_time += frame_period * Gb_Osc::clk_mul; - switch ( frame_phase++ ) - { - case 2: - case 6: - // 128 Hz - square1.clock_sweep(); - case 0: - case 4: - // 256 Hz - square1.clock_length(); - square2.clock_length(); - wave .clock_length(); - noise .clock_length(); - break; - - case 7: - // 64 Hz - frame_phase = 0; - square1.clock_envelope(); - square2.clock_envelope(); - noise .clock_envelope(); - } - } -} - -inline void Gb_Apu::run_until( blip_time_t time ) -{ - require( time >= last_time ); // end_time must not be before previous time - if ( time > last_time ) - run_until_( time ); -} - -void Gb_Apu::end_frame( blip_time_t end_time ) -{ - if ( end_time > last_time ) - run_until( end_time ); - - frame_time -= end_time; - assert( frame_time >= 0 ); - - last_time -= end_time; - assert( last_time >= 0 ); -} - -void Gb_Apu::silence_osc( Gb_Osc& o ) -{ - int delta = -o.last_amp; - if ( delta ) - { - o.last_amp = 0; - if ( o.output ) - { - o.output->set_modified(); - med_synth.offset( last_time, delta, o.output ); - } - } -} - -void Gb_Apu::apply_stereo() -{ - for ( int i = osc_count; --i >= 0; ) - { - Gb_Osc& o = *oscs [i]; - Blip_Buffer* out = o.outputs [calc_output( i )]; - if ( o.output != out ) - { - silence_osc( o ); - o.output = out; - } - } -} - -void Gb_Apu::write_register( blip_time_t time, unsigned addr, int data ) -{ - require( (unsigned) data < 0x100 ); - - int reg = addr - start_addr; - if ( (unsigned) reg >= register_count ) - { - require( false ); - return; - } - - if ( addr < status_reg && !(regs [status_reg - start_addr] & power_mask) ) - { - // Power is off - - // length counters can only be written in DMG mode - if ( wave.mode != mode_dmg || (reg != 1 && reg != 5+1 && reg != 10+1 && reg != 15+1) ) - return; - - if ( reg < 10 ) - data &= 0x3F; // clear square duty - } - - run_until( time ); - - if ( addr >= wave_ram ) - { - wave.write( addr, data ); - } - else - { - int old_data = regs [reg]; - regs [reg] = data; - - if ( addr < vol_reg ) - { - // Oscillator - write_osc( reg / 5, reg, old_data, data ); - } - else if ( addr == vol_reg && data != old_data ) - { - // Master volume - for ( int i = osc_count; --i >= 0; ) - silence_osc( *oscs [i] ); - - apply_volume(); - } - else if ( addr == stereo_reg ) - { - // Stereo panning - apply_stereo(); - } - else if ( addr == status_reg && (data ^ old_data) & power_mask ) - { - // Power control - frame_phase = 0; - for ( int i = osc_count; --i >= 0; ) - silence_osc( *oscs [i] ); - - reset_regs(); - if ( wave.mode != mode_dmg ) - reset_lengths(); - - regs [status_reg - start_addr] = data; - } - } -} - -int Gb_Apu::read_register( blip_time_t time, unsigned addr ) -{ - run_until( time ); - - int reg = addr - start_addr; - if ( (unsigned) reg >= register_count ) - { - require( false ); - return 0; - } - - if ( addr >= wave_ram ) - return wave.read( addr ); - - // Value read back has some bits always set - static byte const masks [] = { - 0x80,0x3F,0x00,0xFF,0xBF, - 0xFF,0x3F,0x00,0xFF,0xBF, - 0x7F,0xFF,0x9F,0xFF,0xBF, - 0xFF,0xFF,0x00,0x00,0xBF, - 0x00,0x00,0x70, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF - }; - int mask = masks [reg]; - if ( wave.agb_mask && (reg == 10 || reg == 12) ) - mask = 0x1F; // extra implemented bits in wave regs on AGB - int data = regs [reg] | mask; - - // Status register - if ( addr == status_reg ) - { - data &= 0xF0; - data |= (int) square1.enabled << 0; - data |= (int) square2.enabled << 1; - data |= (int) wave .enabled << 2; - data |= (int) noise .enabled << 3; - } - - return data; -} +// Gb_Snd_Emu 0.2.0. http://www.slack.net/~ant/ + +#include "Gb_Apu.h" + +/* Copyright (C) 2003-2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +unsigned const vol_reg = 0xFF24; +unsigned const stereo_reg = 0xFF25; +unsigned const status_reg = 0xFF26; +unsigned const wave_ram = 0xFF30; + +int const power_mask = 0x80; + +void Gb_Apu::treble_eq( blip_eq_t const& eq ) +{ + good_synth.treble_eq( eq ); + med_synth .treble_eq( eq ); +} + +inline int Gb_Apu::calc_output( int osc ) const +{ + int bits = regs [stereo_reg - start_addr] >> osc; + return (bits >> 3 & 2) | (bits & 1); +} + +void Gb_Apu::set_output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right, int osc ) +{ + // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL) + require( !center || (center && !left && !right) || (center && left && right) ); + require( (unsigned) osc <= osc_count ); // fails if you pass invalid osc index + + if ( !center || !left || !right ) + { + left = center; + right = center; + } + + int i = (unsigned) osc % osc_count; + do + { + Gb_Osc& o = *oscs [i]; + o.outputs [1] = right; + o.outputs [2] = left; + o.outputs [3] = center; + o.output = o.outputs [calc_output( i )]; + } + while ( ++i < osc ); +} + +void Gb_Apu::synth_volume( int iv ) +{ + double v = volume_ * 0.60 / osc_count / 15 /*steps*/ / 8 /*master vol range*/ * iv; + good_synth.volume( v ); + med_synth .volume( v ); +} + +void Gb_Apu::apply_volume() +{ + // TODO: Doesn't handle differing left and right volumes (panning). + // Not worth the complexity. + int data = regs [vol_reg - start_addr]; + int left = data >> 4 & 7; + int right = data & 7; + //if ( data & 0x88 ) dprintf( "Vin: %02X\n", data & 0x88 ); + //if ( left != right ) dprintf( "l: %d r: %d\n", left, right ); + synth_volume( max( left, right ) + 1 ); +} + +void Gb_Apu::volume( double v ) +{ + if ( volume_ != v ) + { + volume_ = v; + apply_volume(); + } +} + +void Gb_Apu::reset_regs() +{ + for ( int i = 0; i < 0x20; i++ ) + regs [i] = 0; + + square1.reset(); + square2.reset(); + wave .reset(); + noise .reset(); + + apply_volume(); +} + +void Gb_Apu::reset_lengths() +{ + square1.length_ctr = 64; + square2.length_ctr = 64; + wave .length_ctr = 256; + noise .length_ctr = 64; +} + +void Gb_Apu::reduce_clicks( bool reduce ) +{ + reduce_clicks_ = reduce; + + // Click reduction makes DAC off generate same output as volume 0 + int dac_off_amp = 0; + if ( reduce && wave.mode != mode_agb ) // AGB already eliminates clicks + dac_off_amp = -Gb_Osc::dac_bias; + + for ( int i = 0; i < osc_count; i++ ) + oscs [i]->dac_off_amp = dac_off_amp; + + // AGB always eliminates clicks on wave channel using same method + if ( wave.mode == mode_agb ) + wave.dac_off_amp = -Gb_Osc::dac_bias; +} + +void Gb_Apu::reset( mode_t mode, bool agb_wave ) +{ + // Hardware mode + if ( agb_wave ) + mode = mode_agb; // using AGB wave features implies AGB hardware + wave.agb_mask = agb_wave ? 0xFF : 0; + for ( int i = 0; i < osc_count; i++ ) + oscs [i]->mode = mode; + reduce_clicks( reduce_clicks_ ); + + // Reset state + frame_time = 0; + last_time = 0; + frame_phase = 0; + + reset_regs(); + reset_lengths(); + + // Load initial wave RAM + static byte const initial_wave [2] [16] = { + {0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C,0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA}, + {0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF}, + }; + for ( int b = 2; --b >= 0; ) + { + // Init both banks (does nothing if not in AGB mode) + // TODO: verify that this works + write_register( 0, 0xFF1A, b * 0x40 ); + for ( unsigned i = 0; i < sizeof initial_wave [0]; i++ ) + write_register( 0, i + wave_ram, initial_wave [(mode != mode_dmg)] [i] ); + } +} + +void Gb_Apu::set_tempo( double t ) +{ + frame_period = 4194304 / 512; // 512 Hz + if ( t != 1.0 ) + frame_period = blip_time_t (frame_period / t); +} + +Gb_Apu::Gb_Apu() +{ + wave.wave_ram = ®s [wave_ram - start_addr]; + + oscs [0] = &square1; + oscs [1] = &square2; + oscs [2] = &wave; + oscs [3] = &noise; + + for ( int i = osc_count; --i >= 0; ) + { + Gb_Osc& o = *oscs [i]; + o.regs = ®s [i * 5]; + o.output = 0; + o.outputs [0] = 0; + o.outputs [1] = 0; + o.outputs [2] = 0; + o.outputs [3] = 0; + o.good_synth = &good_synth; + o.med_synth = &med_synth; + } + + reduce_clicks_ = false; + set_tempo( 1.0 ); + volume_ = 1.0; + reset(); +} + +void Gb_Apu::run_until_( blip_time_t end_time ) +{ + while ( true ) + { + // run oscillators + blip_time_t time = end_time; + if ( time > frame_time ) + time = frame_time; + + square1.run( last_time, time ); + square2.run( last_time, time ); + wave .run( last_time, time ); + noise .run( last_time, time ); + last_time = time; + + if ( time == end_time ) + break; + + // run frame sequencer + frame_time += frame_period * Gb_Osc::clk_mul; + switch ( frame_phase++ ) + { + case 2: + case 6: + // 128 Hz + square1.clock_sweep(); + case 0: + case 4: + // 256 Hz + square1.clock_length(); + square2.clock_length(); + wave .clock_length(); + noise .clock_length(); + break; + + case 7: + // 64 Hz + frame_phase = 0; + square1.clock_envelope(); + square2.clock_envelope(); + noise .clock_envelope(); + } + } +} + +inline void Gb_Apu::run_until( blip_time_t time ) +{ + require( time >= last_time ); // end_time must not be before previous time + if ( time > last_time ) + run_until_( time ); +} + +void Gb_Apu::end_frame( blip_time_t end_time ) +{ + if ( end_time > last_time ) + run_until( end_time ); + + frame_time -= end_time; + assert( frame_time >= 0 ); + + last_time -= end_time; + assert( last_time >= 0 ); +} + +void Gb_Apu::silence_osc( Gb_Osc& o ) +{ + int delta = -o.last_amp; + if ( delta ) + { + o.last_amp = 0; + if ( o.output ) + { + o.output->set_modified(); + med_synth.offset( last_time, delta, o.output ); + } + } +} + +void Gb_Apu::apply_stereo() +{ + for ( int i = osc_count; --i >= 0; ) + { + Gb_Osc& o = *oscs [i]; + Blip_Buffer* out = o.outputs [calc_output( i )]; + if ( o.output != out ) + { + silence_osc( o ); + o.output = out; + } + } +} + +void Gb_Apu::write_register( blip_time_t time, unsigned addr, int data ) +{ + require( (unsigned) data < 0x100 ); + + int reg = addr - start_addr; + if ( (unsigned) reg >= register_count ) + { + require( false ); + return; + } + + if ( addr < status_reg && !(regs [status_reg - start_addr] & power_mask) ) + { + // Power is off + + // length counters can only be written in DMG mode + if ( wave.mode != mode_dmg || (reg != 1 && reg != 5+1 && reg != 10+1 && reg != 15+1) ) + return; + + if ( reg < 10 ) + data &= 0x3F; // clear square duty + } + + run_until( time ); + + if ( addr >= wave_ram ) + { + wave.write( addr, data ); + } + else + { + int old_data = regs [reg]; + regs [reg] = data; + + if ( addr < vol_reg ) + { + // Oscillator + write_osc( reg / 5, reg, old_data, data ); + } + else if ( addr == vol_reg && data != old_data ) + { + // Master volume + for ( int i = osc_count; --i >= 0; ) + silence_osc( *oscs [i] ); + + apply_volume(); + } + else if ( addr == stereo_reg ) + { + // Stereo panning + apply_stereo(); + } + else if ( addr == status_reg && (data ^ old_data) & power_mask ) + { + // Power control + frame_phase = 0; + for ( int i = osc_count; --i >= 0; ) + silence_osc( *oscs [i] ); + + reset_regs(); + if ( wave.mode != mode_dmg ) + reset_lengths(); + + regs [status_reg - start_addr] = data; + } + } +} + +int Gb_Apu::read_register( blip_time_t time, unsigned addr ) +{ + run_until( time ); + + int reg = addr - start_addr; + if ( (unsigned) reg >= register_count ) + { + require( false ); + return 0; + } + + if ( addr >= wave_ram ) + return wave.read( addr ); + + // Value read back has some bits always set + static byte const masks [] = { + 0x80,0x3F,0x00,0xFF,0xBF, + 0xFF,0x3F,0x00,0xFF,0xBF, + 0x7F,0xFF,0x9F,0xFF,0xBF, + 0xFF,0xFF,0x00,0x00,0xBF, + 0x00,0x00,0x70, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF + }; + int mask = masks [reg]; + if ( wave.agb_mask && (reg == 10 || reg == 12) ) + mask = 0x1F; // extra implemented bits in wave regs on AGB + int data = regs [reg] | mask; + + // Status register + if ( addr == status_reg ) + { + data &= 0xF0; + data |= (int) square1.enabled << 0; + data |= (int) square2.enabled << 1; + data |= (int) wave .enabled << 2; + data |= (int) noise .enabled << 3; + } + + return data; +} diff --git a/src/dmg/gb_apu/Gb_Apu.h b/src/dmg/gb_apu/Gb_Apu.h index 4db1c3b5..3f132096 100644 --- a/src/dmg/gb_apu/Gb_Apu.h +++ b/src/dmg/gb_apu/Gb_Apu.h @@ -1,182 +1,182 @@ -// Nintendo Game Boy sound hardware emulator with save state support - -// Gb_Snd_Emu 0.2.0 -#ifndef GB_APU_H -#define GB_APU_H - -#include "Gb_Oscs.h" - -struct gb_apu_state_t; - -class Gb_Apu { -public: -// Basics - - // Clock rate that sound hardware runs at. - enum { clock_rate = 4194304 * GB_APU_OVERCLOCK }; - - // Sets buffer(s) to generate sound into. If left and right are NULL, output is mono. - // If all are NULL, no output is generated but other emulation still runs. - // If chan is specified, only that channel's output is changed, otherwise all are. - enum { osc_count = 4 }; // 0: Square 1, 1: Square 2, 2: Wave, 3: Noise - void set_output( Blip_Buffer* center, Blip_Buffer* left = NULL, Blip_Buffer* right = NULL, - int chan = osc_count ); - - // Resets hardware to initial power on state BEFORE boot ROM runs. Mode selects - // sound hardware. Additional AGB wave features are enabled separately. - enum mode_t { - mode_dmg, // Game Boy monochrome - mode_cgb, // Game Boy Color - mode_agb // Game Boy Advance - }; - void reset( mode_t mode = mode_cgb, bool agb_wave = false ); - - // Reads and writes must be within the start_addr to end_addr range, inclusive. - // Addresses outside this range are not mapped to the sound hardware. - enum { start_addr = 0xFF10 }; - enum { end_addr = 0xFF3F }; - enum { register_count = end_addr - start_addr + 1 }; - - // Times are specified as the number of clocks since the beginning of the - // current time frame. - - // Emulates CPU write of data to addr at specified time. - void write_register( blip_time_t time, unsigned addr, int data ); - - // Emulates CPU read from addr at specified time. - int read_register( blip_time_t time, unsigned addr ); - - // Emulates sound hardware up to specified time, ends current time frame, then - // starts a new frame at time 0. - void end_frame( blip_time_t frame_length ); - -// Sound adjustments - - // Sets overall volume, where 1.0 is normal. - void volume( double ); - - // If true, reduces clicking by disabling DAC biasing. Note that this reduces - // emulation accuracy, since the clicks are authentic. - void reduce_clicks( bool reduce = true ); - - // Sets treble equalization. - void treble_eq( blip_eq_t const& ); - - // Treble and bass values for various hardware. - enum { - speaker_treble = -47, // speaker on system - speaker_bass = 2000, - dmg_treble = 0, // headphones on each system - dmg_bass = 30, - cgb_treble = 0, - cgb_bass = 300, // CGB has much less bass - agb_treble = 0, - agb_bass = 30 - }; - - // Sets frame sequencer rate, where 1.0 is normal. Meant for adjusting the - // tempo in a game music player. - void set_tempo( double ); - -// Save states - - // Saves full emulation state to state_out. Data format is portable and - // includes some extra space to avoid expansion in case more state needs - // to be stored in the future. - void save_state( gb_apu_state_t* state_out ); - - // Loads state. You should call reset() BEFORE this. - blargg_err_t load_state( gb_apu_state_t const& in ); - -public: - Gb_Apu(); - - // Use set_output() in place of these - BLARGG_DEPRECATED void output ( Blip_Buffer* c ) { set_output( c, c, c ); } - BLARGG_DEPRECATED void output ( Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) { set_output( c, l, r ); } - BLARGG_DEPRECATED void osc_output( int i, Blip_Buffer* c ) { set_output( c, c, c, i ); } - BLARGG_DEPRECATED void osc_output( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) { set_output( c, l, r, i ); } - -private: - // noncopyable - Gb_Apu( const Gb_Apu& ); - Gb_Apu& operator = ( const Gb_Apu& ); - - Gb_Osc* oscs [osc_count]; - blip_time_t last_time; // time sound emulator has been run to - blip_time_t frame_period; // clocks between each frame sequencer step - double volume_; - bool reduce_clicks_; - - Gb_Sweep_Square square1; - Gb_Square square2; - Gb_Wave wave; - Gb_Noise noise; - blip_time_t frame_time; // time of next frame sequencer action - int frame_phase; // phase of next frame sequencer step - enum { regs_size = register_count + 0x10 }; - BOOST::uint8_t regs [regs_size];// last values written to registers - - // large objects after everything else - Gb_Osc::Good_Synth good_synth; - Gb_Osc::Med_Synth med_synth; - - void reset_lengths(); - void reset_regs(); - int calc_output( int osc ) const; - void apply_stereo(); - void apply_volume(); - void synth_volume( int ); - void run_until_( blip_time_t ); - void run_until( blip_time_t ); - void silence_osc( Gb_Osc& ); - void write_osc( int index, int reg, int old_data, int data ); - const char* save_load( gb_apu_state_t*, bool save ); - void save_load2( gb_apu_state_t*, bool save ); - friend class Gb_Apu_Tester; -}; - -// Format of save state. Should be stable across versions of the library, -// with earlier versions properly opening later save states. Includes some -// room for expansion so the state size shouldn't increase. -struct gb_apu_state_t -{ -#if GB_APU_CUSTOM_STATE - // Values stored as plain int so your code can read/write them easily. - // Structure can NOT be written to disk, since format is not portable. - typedef int val_t; -#else - // Values written in portable little-endian format, allowing structure - // to be written directly to disk. - typedef unsigned char val_t [4]; -#endif - - enum { format0 = 0x50414247 }; - - val_t format; // format of all following data - val_t version; // later versions just add fields to end - - unsigned char regs [0x40]; - val_t frame_time; - val_t frame_phase; - - val_t sweep_freq; - val_t sweep_delay; - val_t sweep_enabled; - val_t sweep_neg; - val_t noise_divider; - val_t wave_buf; - - val_t delay [4]; - val_t length_ctr [4]; - val_t phase [4]; - val_t enabled [4]; - - val_t env_delay [3]; - val_t env_volume [3]; - val_t env_enabled [3]; - - val_t unused [13]; // for future expansion -}; - -#endif +// Nintendo Game Boy sound hardware emulator with save state support + +// Gb_Snd_Emu 0.2.0 +#ifndef GB_APU_H +#define GB_APU_H + +#include "Gb_Oscs.h" + +struct gb_apu_state_t; + +class Gb_Apu { +public: +// Basics + + // Clock rate that sound hardware runs at. + enum { clock_rate = 4194304 * GB_APU_OVERCLOCK }; + + // Sets buffer(s) to generate sound into. If left and right are NULL, output is mono. + // If all are NULL, no output is generated but other emulation still runs. + // If chan is specified, only that channel's output is changed, otherwise all are. + enum { osc_count = 4 }; // 0: Square 1, 1: Square 2, 2: Wave, 3: Noise + void set_output( Blip_Buffer* center, Blip_Buffer* left = NULL, Blip_Buffer* right = NULL, + int chan = osc_count ); + + // Resets hardware to initial power on state BEFORE boot ROM runs. Mode selects + // sound hardware. Additional AGB wave features are enabled separately. + enum mode_t { + mode_dmg, // Game Boy monochrome + mode_cgb, // Game Boy Color + mode_agb // Game Boy Advance + }; + void reset( mode_t mode = mode_cgb, bool agb_wave = false ); + + // Reads and writes must be within the start_addr to end_addr range, inclusive. + // Addresses outside this range are not mapped to the sound hardware. + enum { start_addr = 0xFF10 }; + enum { end_addr = 0xFF3F }; + enum { register_count = end_addr - start_addr + 1 }; + + // Times are specified as the number of clocks since the beginning of the + // current time frame. + + // Emulates CPU write of data to addr at specified time. + void write_register( blip_time_t time, unsigned addr, int data ); + + // Emulates CPU read from addr at specified time. + int read_register( blip_time_t time, unsigned addr ); + + // Emulates sound hardware up to specified time, ends current time frame, then + // starts a new frame at time 0. + void end_frame( blip_time_t frame_length ); + +// Sound adjustments + + // Sets overall volume, where 1.0 is normal. + void volume( double ); + + // If true, reduces clicking by disabling DAC biasing. Note that this reduces + // emulation accuracy, since the clicks are authentic. + void reduce_clicks( bool reduce = true ); + + // Sets treble equalization. + void treble_eq( blip_eq_t const& ); + + // Treble and bass values for various hardware. + enum { + speaker_treble = -47, // speaker on system + speaker_bass = 2000, + dmg_treble = 0, // headphones on each system + dmg_bass = 30, + cgb_treble = 0, + cgb_bass = 300, // CGB has much less bass + agb_treble = 0, + agb_bass = 30 + }; + + // Sets frame sequencer rate, where 1.0 is normal. Meant for adjusting the + // tempo in a game music player. + void set_tempo( double ); + +// Save states + + // Saves full emulation state to state_out. Data format is portable and + // includes some extra space to avoid expansion in case more state needs + // to be stored in the future. + void save_state( gb_apu_state_t* state_out ); + + // Loads state. You should call reset() BEFORE this. + blargg_err_t load_state( gb_apu_state_t const& in ); + +public: + Gb_Apu(); + + // Use set_output() in place of these + BLARGG_DEPRECATED void output ( Blip_Buffer* c ) { set_output( c, c, c ); } + BLARGG_DEPRECATED void output ( Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) { set_output( c, l, r ); } + BLARGG_DEPRECATED void osc_output( int i, Blip_Buffer* c ) { set_output( c, c, c, i ); } + BLARGG_DEPRECATED void osc_output( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) { set_output( c, l, r, i ); } + +private: + // noncopyable + Gb_Apu( const Gb_Apu& ); + Gb_Apu& operator = ( const Gb_Apu& ); + + Gb_Osc* oscs [osc_count]; + blip_time_t last_time; // time sound emulator has been run to + blip_time_t frame_period; // clocks between each frame sequencer step + double volume_; + bool reduce_clicks_; + + Gb_Sweep_Square square1; + Gb_Square square2; + Gb_Wave wave; + Gb_Noise noise; + blip_time_t frame_time; // time of next frame sequencer action + int frame_phase; // phase of next frame sequencer step + enum { regs_size = register_count + 0x10 }; + BOOST::uint8_t regs [regs_size];// last values written to registers + + // large objects after everything else + Gb_Osc::Good_Synth good_synth; + Gb_Osc::Med_Synth med_synth; + + void reset_lengths(); + void reset_regs(); + int calc_output( int osc ) const; + void apply_stereo(); + void apply_volume(); + void synth_volume( int ); + void run_until_( blip_time_t ); + void run_until( blip_time_t ); + void silence_osc( Gb_Osc& ); + void write_osc( int index, int reg, int old_data, int data ); + const char* save_load( gb_apu_state_t*, bool save ); + void save_load2( gb_apu_state_t*, bool save ); + friend class Gb_Apu_Tester; +}; + +// Format of save state. Should be stable across versions of the library, +// with earlier versions properly opening later save states. Includes some +// room for expansion so the state size shouldn't increase. +struct gb_apu_state_t +{ +#if GB_APU_CUSTOM_STATE + // Values stored as plain int so your code can read/write them easily. + // Structure can NOT be written to disk, since format is not portable. + typedef int val_t; +#else + // Values written in portable little-endian format, allowing structure + // to be written directly to disk. + typedef unsigned char val_t [4]; +#endif + + enum { format0 = 0x50414247 }; + + val_t format; // format of all following data + val_t version; // later versions just add fields to end + + unsigned char regs [0x40]; + val_t frame_time; + val_t frame_phase; + + val_t sweep_freq; + val_t sweep_delay; + val_t sweep_enabled; + val_t sweep_neg; + val_t noise_divider; + val_t wave_buf; + + val_t delay [4]; + val_t length_ctr [4]; + val_t phase [4]; + val_t enabled [4]; + + val_t env_delay [3]; + val_t env_volume [3]; + val_t env_enabled [3]; + + val_t unused [13]; // for future expansion +}; + +#endif diff --git a/src/dmg/gb_apu/Gb_Apu_State.cpp b/src/dmg/gb_apu/Gb_Apu_State.cpp index 7dedcc37..f726ccbd 100644 --- a/src/dmg/gb_apu/Gb_Apu_State.cpp +++ b/src/dmg/gb_apu/Gb_Apu_State.cpp @@ -1,118 +1,118 @@ -// Gb_Snd_Emu $vers. http://www.slack.net/~ant/ - -#include "Gb_Apu.h" - -#include - -/* Copyright (C) 2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -#if GB_APU_CUSTOM_STATE - #define REFLECT( x, y ) (save ? (io->y) = (x) : (x) = (io->y) ) -#else - #define REFLECT( x, y ) (save ? set_val( io->y, x ) : (void) ((x) = get_val( io->y ))) - - static blargg_ulong get_val( byte const* p ) - { - return p [3] * 0x1000000 + p [2] * 0x10000 + p [1] * 0x100 + p [0]; - } - - static void set_val( byte* p, blargg_ulong n ) - { - p [0] = (byte) (n ); - p [1] = (byte) (n >> 8); - p [2] = (byte) (n >> 16); - p [3] = (byte) (n >> 24); - } -#endif - -inline const char* Gb_Apu::save_load( gb_apu_state_t* io, bool save ) -{ - #if !GB_APU_CUSTOM_STATE - assert( sizeof (gb_apu_state_t) == 256 ); - #endif - - int format = io->format0; - REFLECT( format, format ); - if ( format != io->format0 ) - return "Unsupported sound save state format"; - - int version = 0; - REFLECT( version, version ); - - // Registers and wave RAM - assert( regs_size == sizeof io->regs ); - if ( save ) - memcpy( io->regs, regs, sizeof io->regs ); - else - memcpy( regs, io->regs, sizeof regs ); - - // Frame sequencer - REFLECT( frame_time, frame_time ); - REFLECT( frame_phase, frame_phase ); - - REFLECT( square1.sweep_freq, sweep_freq ); - REFLECT( square1.sweep_delay, sweep_delay ); - REFLECT( square1.sweep_enabled, sweep_enabled ); - REFLECT( square1.sweep_neg, sweep_neg ); - - REFLECT( noise.divider, noise_divider ); - REFLECT( wave.sample_buf, wave_buf ); - - return 0; -} - -// second function to avoid inline limits of some compilers -inline void Gb_Apu::save_load2( gb_apu_state_t* io, bool save ) -{ - for ( int i = osc_count; --i >= 0; ) - { - Gb_Osc& osc = *oscs [i]; - REFLECT( osc.delay, delay [i] ); - REFLECT( osc.length_ctr, length_ctr [i] ); - REFLECT( osc.phase, phase [i] ); - REFLECT( osc.enabled, enabled [i] ); - - if ( i != 2 ) - { - int j = min( i, 2 ); - Gb_Env& env = STATIC_CAST(Gb_Env&,osc); - REFLECT( env.env_delay, env_delay [j] ); - REFLECT( env.volume, env_volume [j] ); - REFLECT( env.env_enabled, env_enabled [j] ); - } - } -} - -void Gb_Apu::save_state( gb_apu_state_t* out ) -{ - (void) save_load( out, true ); - save_load2( out, true ); - - #if !GB_APU_CUSTOM_STATE - memset( out->unused, 0, sizeof out->unused ); - #endif -} - -blargg_err_t Gb_Apu::load_state( gb_apu_state_t const& in ) -{ - RETURN_ERR( save_load( CONST_CAST(gb_apu_state_t*,&in), false ) ); - save_load2( CONST_CAST(gb_apu_state_t*,&in), false ); - - apply_stereo(); - synth_volume( 0 ); // suppress output for the moment - run_until_( last_time ); // get last_amp updated - apply_volume(); // now use correct volume - - return 0; -} +// Gb_Snd_Emu $vers. http://www.slack.net/~ant/ + +#include "Gb_Apu.h" + +#include + +/* Copyright (C) 2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +#if GB_APU_CUSTOM_STATE + #define REFLECT( x, y ) (save ? (io->y) = (x) : (x) = (io->y) ) +#else + #define REFLECT( x, y ) (save ? set_val( io->y, x ) : (void) ((x) = get_val( io->y ))) + + static blargg_ulong get_val( byte const* p ) + { + return p [3] * 0x1000000 + p [2] * 0x10000 + p [1] * 0x100 + p [0]; + } + + static void set_val( byte* p, blargg_ulong n ) + { + p [0] = (byte) (n ); + p [1] = (byte) (n >> 8); + p [2] = (byte) (n >> 16); + p [3] = (byte) (n >> 24); + } +#endif + +inline const char* Gb_Apu::save_load( gb_apu_state_t* io, bool save ) +{ + #if !GB_APU_CUSTOM_STATE + assert( sizeof (gb_apu_state_t) == 256 ); + #endif + + int format = io->format0; + REFLECT( format, format ); + if ( format != io->format0 ) + return "Unsupported sound save state format"; + + int version = 0; + REFLECT( version, version ); + + // Registers and wave RAM + assert( regs_size == sizeof io->regs ); + if ( save ) + memcpy( io->regs, regs, sizeof io->regs ); + else + memcpy( regs, io->regs, sizeof regs ); + + // Frame sequencer + REFLECT( frame_time, frame_time ); + REFLECT( frame_phase, frame_phase ); + + REFLECT( square1.sweep_freq, sweep_freq ); + REFLECT( square1.sweep_delay, sweep_delay ); + REFLECT( square1.sweep_enabled, sweep_enabled ); + REFLECT( square1.sweep_neg, sweep_neg ); + + REFLECT( noise.divider, noise_divider ); + REFLECT( wave.sample_buf, wave_buf ); + + return 0; +} + +// second function to avoid inline limits of some compilers +inline void Gb_Apu::save_load2( gb_apu_state_t* io, bool save ) +{ + for ( int i = osc_count; --i >= 0; ) + { + Gb_Osc& osc = *oscs [i]; + REFLECT( osc.delay, delay [i] ); + REFLECT( osc.length_ctr, length_ctr [i] ); + REFLECT( osc.phase, phase [i] ); + REFLECT( osc.enabled, enabled [i] ); + + if ( i != 2 ) + { + int j = min( i, 2 ); + Gb_Env& env = STATIC_CAST(Gb_Env&,osc); + REFLECT( env.env_delay, env_delay [j] ); + REFLECT( env.volume, env_volume [j] ); + REFLECT( env.env_enabled, env_enabled [j] ); + } + } +} + +void Gb_Apu::save_state( gb_apu_state_t* out ) +{ + (void) save_load( out, true ); + save_load2( out, true ); + + #if !GB_APU_CUSTOM_STATE + memset( out->unused, 0, sizeof out->unused ); + #endif +} + +blargg_err_t Gb_Apu::load_state( gb_apu_state_t const& in ) +{ + RETURN_ERR( save_load( CONST_CAST(gb_apu_state_t*,&in), false ) ); + save_load2( CONST_CAST(gb_apu_state_t*,&in), false ); + + apply_stereo(); + synth_volume( 0 ); // suppress output for the moment + run_until_( last_time ); // get last_amp updated + apply_volume(); // now use correct volume + + return 0; +} diff --git a/src/dmg/gb_apu/Gb_Oscs.cpp b/src/dmg/gb_apu/Gb_Oscs.cpp index b77cbad2..644f6ddd 100644 --- a/src/dmg/gb_apu/Gb_Oscs.cpp +++ b/src/dmg/gb_apu/Gb_Oscs.cpp @@ -1,665 +1,665 @@ -// Gb_Snd_Emu 0.2.0. http://www.slack.net/~ant/ - -#include "Gb_Apu.h" - -/* Copyright (C) 2003-2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -bool const cgb_02 = false; // enables bug in early CGB units that causes problems in some games -bool const cgb_05 = false; // enables CGB-05 zombie behavior - -int const trigger_mask = 0x80; -int const length_enabled = 0x40; - -void Gb_Osc::reset() -{ - output = 0; - last_amp = 0; - delay = 0; - phase = 0; - enabled = false; -} - -inline void Gb_Osc::update_amp( blip_time_t time, int new_amp ) -{ - output->set_modified(); - int delta = new_amp - last_amp; - if ( delta ) - { - last_amp = new_amp; - med_synth->offset( time, delta, output ); - } -} - -// Units - -void Gb_Osc::clock_length() -{ - if ( (regs [4] & length_enabled) && length_ctr ) - { - if ( --length_ctr <= 0 ) - enabled = false; - } -} - -inline int Gb_Env::reload_env_timer() -{ - int raw = regs [2] & 7; - env_delay = (raw ? raw : 8); - return raw; -} - -void Gb_Env::clock_envelope() -{ - if ( env_enabled && --env_delay <= 0 && reload_env_timer() ) - { - int v = volume + (regs [2] & 0x08 ? +1 : -1); - if ( 0 <= v && v <= 15 ) - volume = v; - else - env_enabled = false; - } -} - -inline void Gb_Sweep_Square::reload_sweep_timer() -{ - sweep_delay = (regs [0] & period_mask) >> 4; - if ( !sweep_delay ) - sweep_delay = 8; -} - -void Gb_Sweep_Square::calc_sweep( bool update ) -{ - int const shift = regs [0] & shift_mask; - int const delta = sweep_freq >> shift; - sweep_neg = (regs [0] & 0x08) != 0; - int const freq = sweep_freq + (sweep_neg ? -delta : delta); - - if ( freq > 0x7FF ) - { - enabled = false; - } - else if ( shift && update ) - { - sweep_freq = freq; - - regs [3] = freq & 0xFF; - regs [4] = (regs [4] & ~0x07) | (freq >> 8 & 0x07); - } -} - -void Gb_Sweep_Square::clock_sweep() -{ - if ( --sweep_delay <= 0 ) - { - reload_sweep_timer(); - if ( sweep_enabled && (regs [0] & period_mask) ) - { - calc_sweep( true ); - calc_sweep( false ); - } - } -} - -int Gb_Wave::access( unsigned addr ) const -{ - if ( enabled ) - { - addr = phase & (bank_size - 1); - if ( mode == Gb_Apu::mode_dmg ) - { - addr++; - if ( delay > clk_mul ) - return -1; // can only access within narrow time window while playing - } - addr >>= 1; - } - return addr & 0x0F; -} - -// write_register - -int Gb_Osc::write_trig( int frame_phase, int max_len, int old_data ) -{ - int data = regs [4]; - - if ( (frame_phase & 1) && !(old_data & length_enabled) && length_ctr ) - { - if ( (data & length_enabled) || cgb_02 ) - length_ctr--; - } - - if ( data & trigger_mask ) - { - enabled = true; - if ( !length_ctr ) - { - length_ctr = max_len; - if ( (frame_phase & 1) && (data & length_enabled) ) - length_ctr--; - } - } - - if ( !length_ctr ) - enabled = false; - - return data & trigger_mask; -} - -inline void Gb_Env::zombie_volume( int old, int data ) -{ - int v = volume; - if ( mode == Gb_Apu::mode_agb || cgb_05 ) - { - // CGB-05 behavior, very close to AGB behavior as well - if ( (old ^ data) & 8 ) - { - if ( !(old & 8) ) - { - v++; - if ( old & 7 ) - v++; - } - - v = 16 - v; - } - else if ( (old & 0x0F) == 8 ) - { - v++; - } - } - else - { - // CGB-04&02 behavior, very close to MGB behavior as well - if ( !(old & 7) && env_enabled ) - v++; - else if ( !(old & 8) ) - v += 2; - - if ( (old ^ data) & 8 ) - v = 16 - v; - } - volume = v & 0x0F; -} - -bool Gb_Env::write_register( int frame_phase, int reg, int old, int data ) -{ - int const max_len = 64; - - switch ( reg ) - { - case 1: - length_ctr = max_len - (data & (max_len - 1)); - break; - - case 2: - if ( !dac_enabled() ) - enabled = false; - - zombie_volume( old, data ); - - if ( (data & 7) && env_delay == 8 ) - { - env_delay = 1; - clock_envelope(); // TODO: really happens at next length clock - } - break; - - case 4: - if ( write_trig( frame_phase, max_len, old ) ) - { - volume = regs [2] >> 4; - reload_env_timer(); - env_enabled = true; - if ( frame_phase == 7 ) - env_delay++; - if ( !dac_enabled() ) - enabled = false; - return true; - } - } - return false; -} - -bool Gb_Square::write_register( int frame_phase, int reg, int old_data, int data ) -{ - bool result = Gb_Env::write_register( frame_phase, reg, old_data, data ); - if ( result ) - delay = (delay & (4 * clk_mul - 1)) + period(); - return result; -} - -inline void Gb_Noise::write_register( int frame_phase, int reg, int old_data, int data ) -{ - if ( Gb_Env::write_register( frame_phase, reg, old_data, data ) ) - { - phase = 0x7FFF; - delay += 8 * clk_mul; - } -} - -inline void Gb_Sweep_Square::write_register( int frame_phase, int reg, int old_data, int data ) -{ - if ( reg == 0 && sweep_enabled && sweep_neg && !(data & 0x08) ) - enabled = false; // sweep negate disabled after used - - if ( Gb_Square::write_register( frame_phase, reg, old_data, data ) ) - { - sweep_freq = frequency(); - sweep_neg = false; - reload_sweep_timer(); - sweep_enabled = (regs [0] & (period_mask | shift_mask)) != 0; - if ( regs [0] & shift_mask ) - calc_sweep( false ); - } -} - -void Gb_Wave::corrupt_wave() -{ - int pos = ((phase + 1) & (bank_size - 1)) >> 1; - if ( pos < 4 ) - wave_ram [0] = wave_ram [pos]; - else - for ( int i = 4; --i >= 0; ) - wave_ram [i] = wave_ram [(pos & ~3) + i]; -} - -inline void Gb_Wave::write_register( int frame_phase, int reg, int old_data, int data ) -{ - int const max_len = 256; - - switch ( reg ) - { - case 0: - if ( !dac_enabled() ) - enabled = false; - break; - - case 1: - length_ctr = max_len - data; - break; - - case 4: - bool was_enabled = enabled; - if ( write_trig( frame_phase, max_len, old_data ) ) - { - if ( !dac_enabled() ) - enabled = false; - else if ( mode == Gb_Apu::mode_dmg && was_enabled && - (unsigned) (delay - 2 * clk_mul) < 2 * clk_mul ) - corrupt_wave(); - - phase = 0; - delay = period() + 6 * clk_mul; - } - } -} - -void Gb_Apu::write_osc( int index, int reg, int old_data, int data ) -{ - reg -= index * 5; - switch ( index ) - { - case 0: square1.write_register( frame_phase, reg, old_data, data ); break; - case 1: square2.write_register( frame_phase, reg, old_data, data ); break; - case 2: wave .write_register( frame_phase, reg, old_data, data ); break; - case 3: noise .write_register( frame_phase, reg, old_data, data ); break; - } -} - -// Synthesis - -void Gb_Square::run( blip_time_t time, blip_time_t end_time ) -{ - // Calc duty and phase - static byte const duty_offsets [4] = { 1, 1, 3, 7 }; - static byte const duties [4] = { 1, 2, 4, 6 }; - int const duty_code = regs [1] >> 6; - int duty_offset = duty_offsets [duty_code]; - int duty = duties [duty_code]; - if ( mode == Gb_Apu::mode_agb ) - { - // AGB uses inverted duty - duty_offset -= duty; - duty = 8 - duty; - } - int ph = (this->phase + duty_offset) & 7; - - // Determine what will be generated - int vol = 0; - Blip_Buffer* const out = this->output; - if ( out ) - { - int amp = dac_off_amp; - if ( dac_enabled() ) - { - if ( enabled ) - vol = this->volume; - - amp = -dac_bias; - if ( mode == Gb_Apu::mode_agb ) - amp = -(vol >> 1); - - // Play inaudible frequencies as constant amplitude - if ( frequency() >= 0x7FA && delay < 32 * clk_mul ) - { - amp += (vol * duty) >> 3; - vol = 0; - } - - if ( ph < duty ) - { - amp += vol; - vol = -vol; - } - } - update_amp( time, amp ); - } - - // Generate wave - time += delay; - if ( time < end_time ) - { - int const per = this->period(); - if ( !vol ) - { - // Maintain phase when not playing - int count = (end_time - time + per - 1) / per; - ph += count; // will be masked below - time += (blip_time_t) count * per; - } - else - { - // Output amplitude transitions - int delta = vol; - do - { - ph = (ph + 1) & 7; - if ( ph == 0 || ph == duty ) - { - good_synth->offset_inline( time, delta, out ); - delta = -delta; - } - time += per; - } - while ( time < end_time ); - - if ( delta != vol ) - last_amp -= delta; - } - this->phase = (ph - duty_offset) & 7; - } - delay = time - end_time; -} - -// Quickly runs LFSR for a large number of clocks. For use when noise is generating -// no sound. -static unsigned run_lfsr( unsigned s, unsigned mask, int count ) -{ - bool const optimized = true; // set to false to use only unoptimized loop in middle - - // optimization used in several places: - // ((s & (1 << b)) << n) ^ ((s & (1 << b)) << (n + 1)) = (s & (1 << b)) * (3 << n) - - if ( mask == 0x4000 && optimized ) - { - if ( count >= 32767 ) - count %= 32767; - - // Convert from Fibonacci to Galois configuration, - // shifted left 1 bit - s ^= (s & 1) * 0x8000; - - // Each iteration is equivalent to clocking LFSR 255 times - while ( (count -= 255) > 0 ) - s ^= ((s & 0xE) << 12) ^ ((s & 0xE) << 11) ^ (s >> 3); - count += 255; - - // Each iteration is equivalent to clocking LFSR 15 times - // (interesting similarity to single clocking below) - while ( (count -= 15) > 0 ) - s ^= ((s & 2) * (3 << 13)) ^ (s >> 1); - count += 15; - - // Remaining singles - while ( --count >= 0 ) - s = ((s & 2) * (3 << 13)) ^ (s >> 1); - - // Convert back to Fibonacci configuration - s &= 0x7FFF; - } - else if ( count < 8 || !optimized ) - { - // won't fully replace upper 8 bits, so have to do the unoptimized way - while ( --count >= 0 ) - s = (s >> 1 | mask) ^ (mask & -((s - 1) & 2)); - } - else - { - if ( count > 127 ) - { - count %= 127; - if ( !count ) - count = 127; // must run at least once - } - - // Need to keep one extra bit of history - s = s << 1 & 0xFF; - - // Convert from Fibonacci to Galois configuration, - // shifted left 2 bits - s ^= (s & 2) * 0x80; - - // Each iteration is equivalent to clocking LFSR 7 times - // (interesting similarity to single clocking below) - while ( (count -= 7) > 0 ) - s ^= ((s & 4) * (3 << 5)) ^ (s >> 1); - count += 7; - - // Remaining singles - while ( --count >= 0 ) - s = ((s & 4) * (3 << 5)) ^ (s >> 1); - - // Convert back to Fibonacci configuration and - // repeat last 8 bits above significant 7 - s = (s << 7 & 0x7F80) | (s >> 1 & 0x7F); - } - - return s; -} - -void Gb_Noise::run( blip_time_t time, blip_time_t end_time ) -{ - // Determine what will be generated - int vol = 0; - Blip_Buffer* const out = this->output; - if ( out ) - { - int amp = dac_off_amp; - if ( dac_enabled() ) - { - if ( enabled ) - vol = this->volume; - - amp = -dac_bias; - if ( mode == Gb_Apu::mode_agb ) - amp = -(vol >> 1); - - if ( !(phase & 1) ) - { - amp += vol; - vol = -vol; - } - } - - // AGB negates final output - if ( mode == Gb_Apu::mode_agb ) - { - vol = -vol; - amp = -amp; - } - - update_amp( time, amp ); - } - - // Run timer and calculate time of next LFSR clock - static byte const period1s [8] = { 1, 2, 4, 6, 8, 10, 12, 14 }; - int const period1 = period1s [regs [3] & 7] * clk_mul; - { - int extra = (end_time - time) - delay; - int const per2 = this->period2(); - time += delay + ((divider ^ (per2 >> 1)) & (per2 - 1)) * period1; - - int count = (extra < 0 ? 0 : (extra + period1 - 1) / period1); - divider = (divider - count) & period2_mask; - delay = count * period1 - extra; - } - - // Generate wave - if ( time < end_time ) - { - unsigned const mask = this->lfsr_mask(); - unsigned bits = this->phase; - - int per = period2( period1 * 8 ); - if ( period2_index() >= 0xE ) - { - time = end_time; - } - else if ( !vol ) - { - // Maintain phase when not playing - int count = (end_time - time + per - 1) / per; - time += (blip_time_t) count * per; - bits = run_lfsr( bits, ~mask, count ); - } - else - { - // Output amplitude transitions - int delta = -vol; - do - { - unsigned changed = bits + 1; - bits = bits >> 1 & mask; - if ( changed & 2 ) - { - bits |= ~mask; - delta = -delta; - med_synth->offset_inline( time, delta, out ); - } - time += per; - } - while ( time < end_time ); - - if ( delta == vol ) - last_amp += delta; - } - this->phase = bits; - } -} - -void Gb_Wave::run( blip_time_t time, blip_time_t end_time ) -{ - // Calc volume - static byte const volumes [8] = { 0, 4, 2, 1, 3, 3, 3, 3 }; - int const volume_shift = 2; - int const volume_idx = regs [2] >> 5 & (agb_mask | 3); // 2 bits on DMG/CGB, 3 on AGB - int const volume_mul = volumes [volume_idx]; - - // Determine what will be generated - int playing = false; - Blip_Buffer* const out = this->output; - if ( out ) - { - int amp = dac_off_amp; - if ( dac_enabled() ) - { - // Play inaudible frequencies as constant amplitude - amp = 8 << 4; // really depends on average of all samples in wave - - // if delay is larger, constant amplitude won't start yet - if ( frequency() <= 0x7FB || delay > 15 * clk_mul ) - { - if ( volume_mul ) - playing = (int) enabled; - - amp = (sample_buf << (phase << 2 & 4) & 0xF0) * playing; - } - - amp = ((amp * volume_mul) >> (volume_shift + 4)) - dac_bias; - } - update_amp( time, amp ); - } - - // Generate wave - time += delay; - if ( time < end_time ) - { - byte const* wave = this->wave_ram; - - // wave size and bank - int const size20_mask = 0x20; - int const flags = regs [0] & agb_mask; - int const wave_mask = (flags & size20_mask) | 0x1F; - int swap_banks = 0; - if ( flags & bank40_mask ) - { - swap_banks = flags & size20_mask; - wave += bank_size/2 - (swap_banks >> 1); - } - - int ph = this->phase ^ swap_banks; - ph = (ph + 1) & wave_mask; // pre-advance - - int const per = this->period(); - if ( !playing ) - { - // Maintain phase when not playing - int count = (end_time - time + per - 1) / per; - ph += count; // will be masked below - time += (blip_time_t) count * per; - } - else - { - // Output amplitude transitions - int lamp = this->last_amp + dac_bias; - do - { - // Extract nybble - int nybble = wave [ph >> 1] << (ph << 2 & 4) & 0xF0; - ph = (ph + 1) & wave_mask; - - // Scale by volume - int amp = (nybble * volume_mul) >> (volume_shift + 4); - - int delta = amp - lamp; - if ( delta ) - { - lamp = amp; - med_synth->offset_inline( time, delta, out ); - } - time += per; - } - while ( time < end_time ); - this->last_amp = lamp - dac_bias; - } - ph = (ph - 1) & wave_mask; // undo pre-advance and mask position - - // Keep track of last byte read - if ( enabled ) - sample_buf = wave [ph >> 1]; - - this->phase = ph ^ swap_banks; // undo swapped banks - } - delay = time - end_time; -} +// Gb_Snd_Emu 0.2.0. http://www.slack.net/~ant/ + +#include "Gb_Apu.h" + +/* Copyright (C) 2003-2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +bool const cgb_02 = false; // enables bug in early CGB units that causes problems in some games +bool const cgb_05 = false; // enables CGB-05 zombie behavior + +int const trigger_mask = 0x80; +int const length_enabled = 0x40; + +void Gb_Osc::reset() +{ + output = 0; + last_amp = 0; + delay = 0; + phase = 0; + enabled = false; +} + +inline void Gb_Osc::update_amp( blip_time_t time, int new_amp ) +{ + output->set_modified(); + int delta = new_amp - last_amp; + if ( delta ) + { + last_amp = new_amp; + med_synth->offset( time, delta, output ); + } +} + +// Units + +void Gb_Osc::clock_length() +{ + if ( (regs [4] & length_enabled) && length_ctr ) + { + if ( --length_ctr <= 0 ) + enabled = false; + } +} + +inline int Gb_Env::reload_env_timer() +{ + int raw = regs [2] & 7; + env_delay = (raw ? raw : 8); + return raw; +} + +void Gb_Env::clock_envelope() +{ + if ( env_enabled && --env_delay <= 0 && reload_env_timer() ) + { + int v = volume + (regs [2] & 0x08 ? +1 : -1); + if ( 0 <= v && v <= 15 ) + volume = v; + else + env_enabled = false; + } +} + +inline void Gb_Sweep_Square::reload_sweep_timer() +{ + sweep_delay = (regs [0] & period_mask) >> 4; + if ( !sweep_delay ) + sweep_delay = 8; +} + +void Gb_Sweep_Square::calc_sweep( bool update ) +{ + int const shift = regs [0] & shift_mask; + int const delta = sweep_freq >> shift; + sweep_neg = (regs [0] & 0x08) != 0; + int const freq = sweep_freq + (sweep_neg ? -delta : delta); + + if ( freq > 0x7FF ) + { + enabled = false; + } + else if ( shift && update ) + { + sweep_freq = freq; + + regs [3] = freq & 0xFF; + regs [4] = (regs [4] & ~0x07) | (freq >> 8 & 0x07); + } +} + +void Gb_Sweep_Square::clock_sweep() +{ + if ( --sweep_delay <= 0 ) + { + reload_sweep_timer(); + if ( sweep_enabled && (regs [0] & period_mask) ) + { + calc_sweep( true ); + calc_sweep( false ); + } + } +} + +int Gb_Wave::access( unsigned addr ) const +{ + if ( enabled ) + { + addr = phase & (bank_size - 1); + if ( mode == Gb_Apu::mode_dmg ) + { + addr++; + if ( delay > clk_mul ) + return -1; // can only access within narrow time window while playing + } + addr >>= 1; + } + return addr & 0x0F; +} + +// write_register + +int Gb_Osc::write_trig( int frame_phase, int max_len, int old_data ) +{ + int data = regs [4]; + + if ( (frame_phase & 1) && !(old_data & length_enabled) && length_ctr ) + { + if ( (data & length_enabled) || cgb_02 ) + length_ctr--; + } + + if ( data & trigger_mask ) + { + enabled = true; + if ( !length_ctr ) + { + length_ctr = max_len; + if ( (frame_phase & 1) && (data & length_enabled) ) + length_ctr--; + } + } + + if ( !length_ctr ) + enabled = false; + + return data & trigger_mask; +} + +inline void Gb_Env::zombie_volume( int old, int data ) +{ + int v = volume; + if ( mode == Gb_Apu::mode_agb || cgb_05 ) + { + // CGB-05 behavior, very close to AGB behavior as well + if ( (old ^ data) & 8 ) + { + if ( !(old & 8) ) + { + v++; + if ( old & 7 ) + v++; + } + + v = 16 - v; + } + else if ( (old & 0x0F) == 8 ) + { + v++; + } + } + else + { + // CGB-04&02 behavior, very close to MGB behavior as well + if ( !(old & 7) && env_enabled ) + v++; + else if ( !(old & 8) ) + v += 2; + + if ( (old ^ data) & 8 ) + v = 16 - v; + } + volume = v & 0x0F; +} + +bool Gb_Env::write_register( int frame_phase, int reg, int old, int data ) +{ + int const max_len = 64; + + switch ( reg ) + { + case 1: + length_ctr = max_len - (data & (max_len - 1)); + break; + + case 2: + if ( !dac_enabled() ) + enabled = false; + + zombie_volume( old, data ); + + if ( (data & 7) && env_delay == 8 ) + { + env_delay = 1; + clock_envelope(); // TODO: really happens at next length clock + } + break; + + case 4: + if ( write_trig( frame_phase, max_len, old ) ) + { + volume = regs [2] >> 4; + reload_env_timer(); + env_enabled = true; + if ( frame_phase == 7 ) + env_delay++; + if ( !dac_enabled() ) + enabled = false; + return true; + } + } + return false; +} + +bool Gb_Square::write_register( int frame_phase, int reg, int old_data, int data ) +{ + bool result = Gb_Env::write_register( frame_phase, reg, old_data, data ); + if ( result ) + delay = (delay & (4 * clk_mul - 1)) + period(); + return result; +} + +inline void Gb_Noise::write_register( int frame_phase, int reg, int old_data, int data ) +{ + if ( Gb_Env::write_register( frame_phase, reg, old_data, data ) ) + { + phase = 0x7FFF; + delay += 8 * clk_mul; + } +} + +inline void Gb_Sweep_Square::write_register( int frame_phase, int reg, int old_data, int data ) +{ + if ( reg == 0 && sweep_enabled && sweep_neg && !(data & 0x08) ) + enabled = false; // sweep negate disabled after used + + if ( Gb_Square::write_register( frame_phase, reg, old_data, data ) ) + { + sweep_freq = frequency(); + sweep_neg = false; + reload_sweep_timer(); + sweep_enabled = (regs [0] & (period_mask | shift_mask)) != 0; + if ( regs [0] & shift_mask ) + calc_sweep( false ); + } +} + +void Gb_Wave::corrupt_wave() +{ + int pos = ((phase + 1) & (bank_size - 1)) >> 1; + if ( pos < 4 ) + wave_ram [0] = wave_ram [pos]; + else + for ( int i = 4; --i >= 0; ) + wave_ram [i] = wave_ram [(pos & ~3) + i]; +} + +inline void Gb_Wave::write_register( int frame_phase, int reg, int old_data, int data ) +{ + int const max_len = 256; + + switch ( reg ) + { + case 0: + if ( !dac_enabled() ) + enabled = false; + break; + + case 1: + length_ctr = max_len - data; + break; + + case 4: + bool was_enabled = enabled; + if ( write_trig( frame_phase, max_len, old_data ) ) + { + if ( !dac_enabled() ) + enabled = false; + else if ( mode == Gb_Apu::mode_dmg && was_enabled && + (unsigned) (delay - 2 * clk_mul) < 2 * clk_mul ) + corrupt_wave(); + + phase = 0; + delay = period() + 6 * clk_mul; + } + } +} + +void Gb_Apu::write_osc( int index, int reg, int old_data, int data ) +{ + reg -= index * 5; + switch ( index ) + { + case 0: square1.write_register( frame_phase, reg, old_data, data ); break; + case 1: square2.write_register( frame_phase, reg, old_data, data ); break; + case 2: wave .write_register( frame_phase, reg, old_data, data ); break; + case 3: noise .write_register( frame_phase, reg, old_data, data ); break; + } +} + +// Synthesis + +void Gb_Square::run( blip_time_t time, blip_time_t end_time ) +{ + // Calc duty and phase + static byte const duty_offsets [4] = { 1, 1, 3, 7 }; + static byte const duties [4] = { 1, 2, 4, 6 }; + int const duty_code = regs [1] >> 6; + int duty_offset = duty_offsets [duty_code]; + int duty = duties [duty_code]; + if ( mode == Gb_Apu::mode_agb ) + { + // AGB uses inverted duty + duty_offset -= duty; + duty = 8 - duty; + } + int ph = (this->phase + duty_offset) & 7; + + // Determine what will be generated + int vol = 0; + Blip_Buffer* const out = this->output; + if ( out ) + { + int amp = dac_off_amp; + if ( dac_enabled() ) + { + if ( enabled ) + vol = this->volume; + + amp = -dac_bias; + if ( mode == Gb_Apu::mode_agb ) + amp = -(vol >> 1); + + // Play inaudible frequencies as constant amplitude + if ( frequency() >= 0x7FA && delay < 32 * clk_mul ) + { + amp += (vol * duty) >> 3; + vol = 0; + } + + if ( ph < duty ) + { + amp += vol; + vol = -vol; + } + } + update_amp( time, amp ); + } + + // Generate wave + time += delay; + if ( time < end_time ) + { + int const per = this->period(); + if ( !vol ) + { + // Maintain phase when not playing + int count = (end_time - time + per - 1) / per; + ph += count; // will be masked below + time += (blip_time_t) count * per; + } + else + { + // Output amplitude transitions + int delta = vol; + do + { + ph = (ph + 1) & 7; + if ( ph == 0 || ph == duty ) + { + good_synth->offset_inline( time, delta, out ); + delta = -delta; + } + time += per; + } + while ( time < end_time ); + + if ( delta != vol ) + last_amp -= delta; + } + this->phase = (ph - duty_offset) & 7; + } + delay = time - end_time; +} + +// Quickly runs LFSR for a large number of clocks. For use when noise is generating +// no sound. +static unsigned run_lfsr( unsigned s, unsigned mask, int count ) +{ + bool const optimized = true; // set to false to use only unoptimized loop in middle + + // optimization used in several places: + // ((s & (1 << b)) << n) ^ ((s & (1 << b)) << (n + 1)) = (s & (1 << b)) * (3 << n) + + if ( mask == 0x4000 && optimized ) + { + if ( count >= 32767 ) + count %= 32767; + + // Convert from Fibonacci to Galois configuration, + // shifted left 1 bit + s ^= (s & 1) * 0x8000; + + // Each iteration is equivalent to clocking LFSR 255 times + while ( (count -= 255) > 0 ) + s ^= ((s & 0xE) << 12) ^ ((s & 0xE) << 11) ^ (s >> 3); + count += 255; + + // Each iteration is equivalent to clocking LFSR 15 times + // (interesting similarity to single clocking below) + while ( (count -= 15) > 0 ) + s ^= ((s & 2) * (3 << 13)) ^ (s >> 1); + count += 15; + + // Remaining singles + while ( --count >= 0 ) + s = ((s & 2) * (3 << 13)) ^ (s >> 1); + + // Convert back to Fibonacci configuration + s &= 0x7FFF; + } + else if ( count < 8 || !optimized ) + { + // won't fully replace upper 8 bits, so have to do the unoptimized way + while ( --count >= 0 ) + s = (s >> 1 | mask) ^ (mask & -((s - 1) & 2)); + } + else + { + if ( count > 127 ) + { + count %= 127; + if ( !count ) + count = 127; // must run at least once + } + + // Need to keep one extra bit of history + s = s << 1 & 0xFF; + + // Convert from Fibonacci to Galois configuration, + // shifted left 2 bits + s ^= (s & 2) * 0x80; + + // Each iteration is equivalent to clocking LFSR 7 times + // (interesting similarity to single clocking below) + while ( (count -= 7) > 0 ) + s ^= ((s & 4) * (3 << 5)) ^ (s >> 1); + count += 7; + + // Remaining singles + while ( --count >= 0 ) + s = ((s & 4) * (3 << 5)) ^ (s >> 1); + + // Convert back to Fibonacci configuration and + // repeat last 8 bits above significant 7 + s = (s << 7 & 0x7F80) | (s >> 1 & 0x7F); + } + + return s; +} + +void Gb_Noise::run( blip_time_t time, blip_time_t end_time ) +{ + // Determine what will be generated + int vol = 0; + Blip_Buffer* const out = this->output; + if ( out ) + { + int amp = dac_off_amp; + if ( dac_enabled() ) + { + if ( enabled ) + vol = this->volume; + + amp = -dac_bias; + if ( mode == Gb_Apu::mode_agb ) + amp = -(vol >> 1); + + if ( !(phase & 1) ) + { + amp += vol; + vol = -vol; + } + } + + // AGB negates final output + if ( mode == Gb_Apu::mode_agb ) + { + vol = -vol; + amp = -amp; + } + + update_amp( time, amp ); + } + + // Run timer and calculate time of next LFSR clock + static byte const period1s [8] = { 1, 2, 4, 6, 8, 10, 12, 14 }; + int const period1 = period1s [regs [3] & 7] * clk_mul; + { + int extra = (end_time - time) - delay; + int const per2 = this->period2(); + time += delay + ((divider ^ (per2 >> 1)) & (per2 - 1)) * period1; + + int count = (extra < 0 ? 0 : (extra + period1 - 1) / period1); + divider = (divider - count) & period2_mask; + delay = count * period1 - extra; + } + + // Generate wave + if ( time < end_time ) + { + unsigned const mask = this->lfsr_mask(); + unsigned bits = this->phase; + + int per = period2( period1 * 8 ); + if ( period2_index() >= 0xE ) + { + time = end_time; + } + else if ( !vol ) + { + // Maintain phase when not playing + int count = (end_time - time + per - 1) / per; + time += (blip_time_t) count * per; + bits = run_lfsr( bits, ~mask, count ); + } + else + { + // Output amplitude transitions + int delta = -vol; + do + { + unsigned changed = bits + 1; + bits = bits >> 1 & mask; + if ( changed & 2 ) + { + bits |= ~mask; + delta = -delta; + med_synth->offset_inline( time, delta, out ); + } + time += per; + } + while ( time < end_time ); + + if ( delta == vol ) + last_amp += delta; + } + this->phase = bits; + } +} + +void Gb_Wave::run( blip_time_t time, blip_time_t end_time ) +{ + // Calc volume + static byte const volumes [8] = { 0, 4, 2, 1, 3, 3, 3, 3 }; + int const volume_shift = 2; + int const volume_idx = regs [2] >> 5 & (agb_mask | 3); // 2 bits on DMG/CGB, 3 on AGB + int const volume_mul = volumes [volume_idx]; + + // Determine what will be generated + int playing = false; + Blip_Buffer* const out = this->output; + if ( out ) + { + int amp = dac_off_amp; + if ( dac_enabled() ) + { + // Play inaudible frequencies as constant amplitude + amp = 8 << 4; // really depends on average of all samples in wave + + // if delay is larger, constant amplitude won't start yet + if ( frequency() <= 0x7FB || delay > 15 * clk_mul ) + { + if ( volume_mul ) + playing = (int) enabled; + + amp = (sample_buf << (phase << 2 & 4) & 0xF0) * playing; + } + + amp = ((amp * volume_mul) >> (volume_shift + 4)) - dac_bias; + } + update_amp( time, amp ); + } + + // Generate wave + time += delay; + if ( time < end_time ) + { + byte const* wave = this->wave_ram; + + // wave size and bank + int const size20_mask = 0x20; + int const flags = regs [0] & agb_mask; + int const wave_mask = (flags & size20_mask) | 0x1F; + int swap_banks = 0; + if ( flags & bank40_mask ) + { + swap_banks = flags & size20_mask; + wave += bank_size/2 - (swap_banks >> 1); + } + + int ph = this->phase ^ swap_banks; + ph = (ph + 1) & wave_mask; // pre-advance + + int const per = this->period(); + if ( !playing ) + { + // Maintain phase when not playing + int count = (end_time - time + per - 1) / per; + ph += count; // will be masked below + time += (blip_time_t) count * per; + } + else + { + // Output amplitude transitions + int lamp = this->last_amp + dac_bias; + do + { + // Extract nybble + int nybble = wave [ph >> 1] << (ph << 2 & 4) & 0xF0; + ph = (ph + 1) & wave_mask; + + // Scale by volume + int amp = (nybble * volume_mul) >> (volume_shift + 4); + + int delta = amp - lamp; + if ( delta ) + { + lamp = amp; + med_synth->offset_inline( time, delta, out ); + } + time += per; + } + while ( time < end_time ); + this->last_amp = lamp - dac_bias; + } + ph = (ph - 1) & wave_mask; // undo pre-advance and mask position + + // Keep track of last byte read + if ( enabled ) + sample_buf = wave [ph >> 1]; + + this->phase = ph ^ swap_banks; // undo swapped banks + } + delay = time - end_time; +} diff --git a/src/dmg/gb_apu/Gb_Oscs.h b/src/dmg/gb_apu/Gb_Oscs.h index 260bb061..175127b9 100644 --- a/src/dmg/gb_apu/Gb_Oscs.h +++ b/src/dmg/gb_apu/Gb_Oscs.h @@ -1,190 +1,190 @@ -// Private oscillators used by Gb_Apu - -// Gb_Snd_Emu 0.2.0 -#ifndef GB_OSCS_H -#define GB_OSCS_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -#ifndef GB_APU_OVERCLOCK - #define GB_APU_OVERCLOCK 1 -#endif - -#if GB_APU_OVERCLOCK & (GB_APU_OVERCLOCK - 1) - #error "GB_APU_OVERCLOCK must be a power of 2" -#endif - -class Gb_Osc { -protected: - - // 11-bit frequency in NRx3 and NRx4 - int frequency() const { return (regs [4] & 7) * 0x100 + regs [3]; } - - void update_amp( blip_time_t, int new_amp ); - int write_trig( int frame_phase, int max_len, int old_data ); -public: - - enum { clk_mul = GB_APU_OVERCLOCK }; - enum { dac_bias = 7 }; - - Blip_Buffer* outputs [4];// NULL, right, left, center - Blip_Buffer* output; // where to output sound - BOOST::uint8_t* regs; // osc's 5 registers - int mode; // mode_dmg, mode_cgb, mode_agb - int dac_off_amp;// amplitude when DAC is off - int last_amp; // current amplitude in Blip_Buffer - typedef Blip_Synth Good_Synth; - typedef Blip_Synth Med_Synth; - Good_Synth const* good_synth; - Med_Synth const* med_synth; - - int delay; // clocks until frequency timer expires - int length_ctr; // length counter - unsigned phase; // waveform phase (or equivalent) - bool enabled; // internal enabled flag - - void clock_length(); - void reset(); -}; - -class Gb_Env : public Gb_Osc { -public: - int env_delay; - int volume; - bool env_enabled; - - void clock_envelope(); - bool write_register( int frame_phase, int reg, int old_data, int data ); - - void reset() - { - env_delay = 0; - volume = 0; - Gb_Osc::reset(); - } -protected: - // Non-zero if DAC is enabled - int dac_enabled() const { return regs [2] & 0xF8; } -private: - void zombie_volume( int old, int data ); - int reload_env_timer(); -}; - -class Gb_Square : public Gb_Env { -public: - bool write_register( int frame_phase, int reg, int old_data, int data ); - void run( blip_time_t, blip_time_t ); - - void reset() - { - Gb_Env::reset(); - delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger) - } -private: - // Frequency timer period - int period() const { return (2048 - frequency()) * (4 * clk_mul); } -}; - -class Gb_Sweep_Square : public Gb_Square { -public: - int sweep_freq; - int sweep_delay; - bool sweep_enabled; - bool sweep_neg; - - void clock_sweep(); - void write_register( int frame_phase, int reg, int old_data, int data ); - - void reset() - { - sweep_freq = 0; - sweep_delay = 0; - sweep_enabled = false; - sweep_neg = false; - Gb_Square::reset(); - } -private: - enum { period_mask = 0x70 }; - enum { shift_mask = 0x07 }; - - void calc_sweep( bool update ); - void reload_sweep_timer(); -}; - -class Gb_Noise : public Gb_Env { -public: - - int divider; // noise has more complex frequency divider setup - - void run( blip_time_t, blip_time_t ); - void write_register( int frame_phase, int reg, int old_data, int data ); - - void reset() - { - divider = 0; - Gb_Env::reset(); - delay = 4 * clk_mul; // TODO: remove? - } -private: - enum { period2_mask = 0x1FFFF }; - - int period2_index() const { return regs [3] >> 4; } - int period2( int base = 8 ) const { return base << period2_index(); } - unsigned lfsr_mask() const { return (regs [3] & 0x08) ? ~0x4040 : ~0x4000; } -}; - -class Gb_Wave : public Gb_Osc { -public: - int sample_buf; // last wave RAM byte read (hardware has this as well) - - void write_register( int frame_phase, int reg, int old_data, int data ); - void run( blip_time_t, blip_time_t ); - - // Reads/writes wave RAM - int read( unsigned addr ) const; - void write( unsigned addr, int data ); - - void reset() - { - sample_buf = 0; - Gb_Osc::reset(); - } - -private: - enum { bank40_mask = 0x40 }; - enum { bank_size = 32 }; - - int agb_mask; // 0xFF if AGB features enabled, 0 otherwise - BOOST::uint8_t* wave_ram; // 32 bytes (64 nybbles), stored in APU - - friend class Gb_Apu; - - // Frequency timer period - int period() const { return (2048 - frequency()) * (2 * clk_mul); } - - // Non-zero if DAC is enabled - int dac_enabled() const { return regs [0] & 0x80; } - - void corrupt_wave(); - - BOOST::uint8_t* wave_bank() const { return &wave_ram [(~regs [0] & bank40_mask) >> 2 & agb_mask]; } - - // Wave index that would be accessed, or -1 if no access would occur - int access( unsigned addr ) const; -}; - -inline int Gb_Wave::read( unsigned addr ) const -{ - int index = access( addr ); - return (index < 0 ? 0xFF : wave_bank() [index]); -} - -inline void Gb_Wave::write( unsigned addr, int data ) -{ - int index = access( addr ); - if ( index >= 0 ) - wave_bank() [index] = data;; -} - -#endif +// Private oscillators used by Gb_Apu + +// Gb_Snd_Emu 0.2.0 +#ifndef GB_OSCS_H +#define GB_OSCS_H + +#include "blargg_common.h" +#include "Blip_Buffer.h" + +#ifndef GB_APU_OVERCLOCK + #define GB_APU_OVERCLOCK 1 +#endif + +#if GB_APU_OVERCLOCK & (GB_APU_OVERCLOCK - 1) + #error "GB_APU_OVERCLOCK must be a power of 2" +#endif + +class Gb_Osc { +protected: + + // 11-bit frequency in NRx3 and NRx4 + int frequency() const { return (regs [4] & 7) * 0x100 + regs [3]; } + + void update_amp( blip_time_t, int new_amp ); + int write_trig( int frame_phase, int max_len, int old_data ); +public: + + enum { clk_mul = GB_APU_OVERCLOCK }; + enum { dac_bias = 7 }; + + Blip_Buffer* outputs [4];// NULL, right, left, center + Blip_Buffer* output; // where to output sound + BOOST::uint8_t* regs; // osc's 5 registers + int mode; // mode_dmg, mode_cgb, mode_agb + int dac_off_amp;// amplitude when DAC is off + int last_amp; // current amplitude in Blip_Buffer + typedef Blip_Synth Good_Synth; + typedef Blip_Synth Med_Synth; + Good_Synth const* good_synth; + Med_Synth const* med_synth; + + int delay; // clocks until frequency timer expires + int length_ctr; // length counter + unsigned phase; // waveform phase (or equivalent) + bool enabled; // internal enabled flag + + void clock_length(); + void reset(); +}; + +class Gb_Env : public Gb_Osc { +public: + int env_delay; + int volume; + bool env_enabled; + + void clock_envelope(); + bool write_register( int frame_phase, int reg, int old_data, int data ); + + void reset() + { + env_delay = 0; + volume = 0; + Gb_Osc::reset(); + } +protected: + // Non-zero if DAC is enabled + int dac_enabled() const { return regs [2] & 0xF8; } +private: + void zombie_volume( int old, int data ); + int reload_env_timer(); +}; + +class Gb_Square : public Gb_Env { +public: + bool write_register( int frame_phase, int reg, int old_data, int data ); + void run( blip_time_t, blip_time_t ); + + void reset() + { + Gb_Env::reset(); + delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger) + } +private: + // Frequency timer period + int period() const { return (2048 - frequency()) * (4 * clk_mul); } +}; + +class Gb_Sweep_Square : public Gb_Square { +public: + int sweep_freq; + int sweep_delay; + bool sweep_enabled; + bool sweep_neg; + + void clock_sweep(); + void write_register( int frame_phase, int reg, int old_data, int data ); + + void reset() + { + sweep_freq = 0; + sweep_delay = 0; + sweep_enabled = false; + sweep_neg = false; + Gb_Square::reset(); + } +private: + enum { period_mask = 0x70 }; + enum { shift_mask = 0x07 }; + + void calc_sweep( bool update ); + void reload_sweep_timer(); +}; + +class Gb_Noise : public Gb_Env { +public: + + int divider; // noise has more complex frequency divider setup + + void run( blip_time_t, blip_time_t ); + void write_register( int frame_phase, int reg, int old_data, int data ); + + void reset() + { + divider = 0; + Gb_Env::reset(); + delay = 4 * clk_mul; // TODO: remove? + } +private: + enum { period2_mask = 0x1FFFF }; + + int period2_index() const { return regs [3] >> 4; } + int period2( int base = 8 ) const { return base << period2_index(); } + unsigned lfsr_mask() const { return (regs [3] & 0x08) ? ~0x4040 : ~0x4000; } +}; + +class Gb_Wave : public Gb_Osc { +public: + int sample_buf; // last wave RAM byte read (hardware has this as well) + + void write_register( int frame_phase, int reg, int old_data, int data ); + void run( blip_time_t, blip_time_t ); + + // Reads/writes wave RAM + int read( unsigned addr ) const; + void write( unsigned addr, int data ); + + void reset() + { + sample_buf = 0; + Gb_Osc::reset(); + } + +private: + enum { bank40_mask = 0x40 }; + enum { bank_size = 32 }; + + int agb_mask; // 0xFF if AGB features enabled, 0 otherwise + BOOST::uint8_t* wave_ram; // 32 bytes (64 nybbles), stored in APU + + friend class Gb_Apu; + + // Frequency timer period + int period() const { return (2048 - frequency()) * (2 * clk_mul); } + + // Non-zero if DAC is enabled + int dac_enabled() const { return regs [0] & 0x80; } + + void corrupt_wave(); + + BOOST::uint8_t* wave_bank() const { return &wave_ram [(~regs [0] & bank40_mask) >> 2 & agb_mask]; } + + // Wave index that would be accessed, or -1 if no access would occur + int access( unsigned addr ) const; +}; + +inline int Gb_Wave::read( unsigned addr ) const +{ + int index = access( addr ); + return (index < 0 ? 0xFF : wave_bank() [index]); +} + +inline void Gb_Wave::write( unsigned addr, int data ) +{ + int index = access( addr ); + if ( index >= 0 ) + wave_bank() [index] = data;; +} + +#endif diff --git a/src/dmg/gb_apu/Multi_Buffer.cpp b/src/dmg/gb_apu/Multi_Buffer.cpp index 01e127d4..0923766a 100644 --- a/src/dmg/gb_apu/Multi_Buffer.cpp +++ b/src/dmg/gb_apu/Multi_Buffer.cpp @@ -1,281 +1,281 @@ -// Blip_Buffer 0.4.1. http://www.slack.net/~ant/ - -#include "Multi_Buffer.h" - -/* Copyright (C) 2003-2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - -Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf ) -{ - length_ = 0; - sample_rate_ = 0; - channels_changed_count_ = 1; - channel_types_ = 0; - channel_count_ = 0; - immediate_removal_ = true; -} - -Multi_Buffer::channel_t Multi_Buffer::channel( int /*index*/ ) -{ - static channel_t const ch = { 0, 0, 0 }; - return ch; -} - -// Silent_Buffer - -Silent_Buffer::Silent_Buffer() : Multi_Buffer( 1 ) // 0 channels would probably confuse -{ - // TODO: better to use empty Blip_Buffer so caller never has to check for NULL? - chan.left = 0; - chan.center = 0; - chan.right = 0; -} - -// Mono_Buffer - -Mono_Buffer::Mono_Buffer() : Multi_Buffer( 1 ) -{ - chan.center = &buf; - chan.left = &buf; - chan.right = &buf; -} - -Mono_Buffer::~Mono_Buffer() { } - -blargg_err_t Mono_Buffer::set_sample_rate( long rate, int msec ) -{ - RETURN_ERR( buf.set_sample_rate( rate, msec ) ); - return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() ); -} - - -// Tracked_Blip_Buffer - -Tracked_Blip_Buffer::Tracked_Blip_Buffer() -{ - last_non_silence = 0; -} - -void Tracked_Blip_Buffer::clear() -{ - last_non_silence = 0; - Blip_Buffer::clear(); -} - -void Tracked_Blip_Buffer::end_frame( blip_time_t t ) -{ - Blip_Buffer::end_frame( t ); - if ( clear_modified() ) - last_non_silence = samples_avail() + blip_buffer_extra_; -} - -blip_ulong Tracked_Blip_Buffer::non_silent() const -{ - return last_non_silence | unsettled(); -} - -inline void Tracked_Blip_Buffer::remove_( long n ) -{ - if ( (last_non_silence -= n) < 0 ) - last_non_silence = 0; -} - -void Tracked_Blip_Buffer::remove_silence( long n ) -{ - remove_( n ); - Blip_Buffer::remove_silence( n ); -} - -void Tracked_Blip_Buffer::remove_samples( long n ) -{ - remove_( n ); - Blip_Buffer::remove_samples( n ); -} - -void Tracked_Blip_Buffer::remove_all_samples() -{ - long avail = samples_avail(); - if ( !non_silent() ) - remove_silence( avail ); - else - remove_samples( avail ); -} - -long Tracked_Blip_Buffer::read_samples( blip_sample_t* out, long count ) -{ - count = Blip_Buffer::read_samples( out, count ); - remove_( count ); - return count; -} - -// Stereo_Buffer - -int const stereo = 2; - -Stereo_Buffer::Stereo_Buffer() : Multi_Buffer( 2 ) -{ - chan.center = mixer.bufs [2] = &bufs [2]; - chan.left = mixer.bufs [0] = &bufs [0]; - chan.right = mixer.bufs [1] = &bufs [1]; - mixer.samples_read = 0; -} - -Stereo_Buffer::~Stereo_Buffer() { } - -blargg_err_t Stereo_Buffer::set_sample_rate( long rate, int msec ) -{ - mixer.samples_read = 0; - for ( int i = bufs_size; --i >= 0; ) - RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) ); - return Multi_Buffer::set_sample_rate( bufs [0].sample_rate(), bufs [0].length() ); -} - -void Stereo_Buffer::clock_rate( long rate ) -{ - for ( int i = bufs_size; --i >= 0; ) - bufs [i].clock_rate( rate ); -} - -void Stereo_Buffer::bass_freq( int bass ) -{ - for ( int i = bufs_size; --i >= 0; ) - bufs [i].bass_freq( bass ); -} - -void Stereo_Buffer::clear() -{ - mixer.samples_read = 0; - for ( int i = bufs_size; --i >= 0; ) - bufs [i].clear(); -} - -void Stereo_Buffer::end_frame( blip_time_t time ) -{ - for ( int i = bufs_size; --i >= 0; ) - bufs [i].end_frame( time ); -} - -long Stereo_Buffer::read_samples( blip_sample_t* out, long out_size ) -{ - require( (out_size & 1) == 0 ); // must read an even number of samples - out_size = min( out_size, samples_avail() ); - - int pair_count = int (out_size >> 1); - if ( pair_count ) - { - mixer.read_pairs( out, pair_count ); - - if ( samples_avail() <= 0 || immediate_removal() ) - { - for ( int i = bufs_size; --i >= 0; ) - { - buf_t& b = bufs [i]; - // TODO: might miss non-silence settling since it checks END of last read - if ( !b.non_silent() ) - b.remove_silence( mixer.samples_read ); - else - b.remove_samples( mixer.samples_read ); - } - mixer.samples_read = 0; - } - } - return out_size; -} - - -// Stereo_Mixer - -// mixers use a single index value to improve performance on register-challenged processors -// offset goes from negative to zero - -void Stereo_Mixer::read_pairs( blip_sample_t* out, int count ) -{ - // TODO: if caller never marks buffers as modified, uses mono - // except that buffer isn't cleared, so caller can encounter - // subtle problems and not realize the cause. - samples_read += count; - if ( bufs [0]->non_silent() | bufs [1]->non_silent() ) - mix_stereo( out, count ); - else - mix_mono( out, count ); -} - -void Stereo_Mixer::mix_mono( blip_sample_t* out_, int count ) -{ - int const bass = BLIP_READER_BASS( *bufs [2] ); - BLIP_READER_BEGIN( center, *bufs [2] ); - BLIP_READER_ADJ_( center, samples_read ); - - typedef blip_sample_t stereo_blip_sample_t [stereo]; - stereo_blip_sample_t* BLIP_RESTRICT out = (stereo_blip_sample_t*) out_ + count; - int offset = -count; - do - { - blargg_long s = BLIP_READER_READ( center ); - BLIP_READER_NEXT_IDX_( center, bass, offset ); - BLIP_CLAMP( s, s ); - - out [offset] [0] = (blip_sample_t) s; - out [offset] [1] = (blip_sample_t) s; - } - while ( ++offset ); - - BLIP_READER_END( center, *bufs [2] ); -} - -void Stereo_Mixer::mix_stereo( blip_sample_t* out_, int count ) -{ - blip_sample_t* BLIP_RESTRICT out = out_ + count * stereo; - - // do left + center and right + center separately to reduce register load - Tracked_Blip_Buffer* const* buf = &bufs [2]; - while ( true ) // loop runs twice - { - --buf; - --out; - - int const bass = BLIP_READER_BASS( *bufs [2] ); - BLIP_READER_BEGIN( side, **buf ); - BLIP_READER_BEGIN( center, *bufs [2] ); - - BLIP_READER_ADJ_( side, samples_read ); - BLIP_READER_ADJ_( center, samples_read ); - - int offset = -count; - do - { - blargg_long s = BLIP_READER_READ_RAW( center ) + BLIP_READER_READ_RAW( side ); - s >>= blip_sample_bits - 16; - BLIP_READER_NEXT_IDX_( side, bass, offset ); - BLIP_READER_NEXT_IDX_( center, bass, offset ); - BLIP_CLAMP( s, s ); - - ++offset; // before write since out is decremented to slightly before end - out [offset * stereo] = (blip_sample_t) s; - } - while ( offset ); - - BLIP_READER_END( side, **buf ); - - if ( buf != bufs ) - continue; - - // only end center once - BLIP_READER_END( center, *bufs [2] ); - break; - } -} +// Blip_Buffer 0.4.1. http://www.slack.net/~ant/ + +#include "Multi_Buffer.h" + +/* Copyright (C) 2003-2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +#ifdef BLARGG_ENABLE_OPTIMIZER + #include BLARGG_ENABLE_OPTIMIZER +#endif + +Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf ) +{ + length_ = 0; + sample_rate_ = 0; + channels_changed_count_ = 1; + channel_types_ = 0; + channel_count_ = 0; + immediate_removal_ = true; +} + +Multi_Buffer::channel_t Multi_Buffer::channel( int /*index*/ ) +{ + static channel_t const ch = { 0, 0, 0 }; + return ch; +} + +// Silent_Buffer + +Silent_Buffer::Silent_Buffer() : Multi_Buffer( 1 ) // 0 channels would probably confuse +{ + // TODO: better to use empty Blip_Buffer so caller never has to check for NULL? + chan.left = 0; + chan.center = 0; + chan.right = 0; +} + +// Mono_Buffer + +Mono_Buffer::Mono_Buffer() : Multi_Buffer( 1 ) +{ + chan.center = &buf; + chan.left = &buf; + chan.right = &buf; +} + +Mono_Buffer::~Mono_Buffer() { } + +blargg_err_t Mono_Buffer::set_sample_rate( long rate, int msec ) +{ + RETURN_ERR( buf.set_sample_rate( rate, msec ) ); + return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() ); +} + + +// Tracked_Blip_Buffer + +Tracked_Blip_Buffer::Tracked_Blip_Buffer() +{ + last_non_silence = 0; +} + +void Tracked_Blip_Buffer::clear() +{ + last_non_silence = 0; + Blip_Buffer::clear(); +} + +void Tracked_Blip_Buffer::end_frame( blip_time_t t ) +{ + Blip_Buffer::end_frame( t ); + if ( clear_modified() ) + last_non_silence = samples_avail() + blip_buffer_extra_; +} + +blip_ulong Tracked_Blip_Buffer::non_silent() const +{ + return last_non_silence | unsettled(); +} + +inline void Tracked_Blip_Buffer::remove_( long n ) +{ + if ( (last_non_silence -= n) < 0 ) + last_non_silence = 0; +} + +void Tracked_Blip_Buffer::remove_silence( long n ) +{ + remove_( n ); + Blip_Buffer::remove_silence( n ); +} + +void Tracked_Blip_Buffer::remove_samples( long n ) +{ + remove_( n ); + Blip_Buffer::remove_samples( n ); +} + +void Tracked_Blip_Buffer::remove_all_samples() +{ + long avail = samples_avail(); + if ( !non_silent() ) + remove_silence( avail ); + else + remove_samples( avail ); +} + +long Tracked_Blip_Buffer::read_samples( blip_sample_t* out, long count ) +{ + count = Blip_Buffer::read_samples( out, count ); + remove_( count ); + return count; +} + +// Stereo_Buffer + +int const stereo = 2; + +Stereo_Buffer::Stereo_Buffer() : Multi_Buffer( 2 ) +{ + chan.center = mixer.bufs [2] = &bufs [2]; + chan.left = mixer.bufs [0] = &bufs [0]; + chan.right = mixer.bufs [1] = &bufs [1]; + mixer.samples_read = 0; +} + +Stereo_Buffer::~Stereo_Buffer() { } + +blargg_err_t Stereo_Buffer::set_sample_rate( long rate, int msec ) +{ + mixer.samples_read = 0; + for ( int i = bufs_size; --i >= 0; ) + RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) ); + return Multi_Buffer::set_sample_rate( bufs [0].sample_rate(), bufs [0].length() ); +} + +void Stereo_Buffer::clock_rate( long rate ) +{ + for ( int i = bufs_size; --i >= 0; ) + bufs [i].clock_rate( rate ); +} + +void Stereo_Buffer::bass_freq( int bass ) +{ + for ( int i = bufs_size; --i >= 0; ) + bufs [i].bass_freq( bass ); +} + +void Stereo_Buffer::clear() +{ + mixer.samples_read = 0; + for ( int i = bufs_size; --i >= 0; ) + bufs [i].clear(); +} + +void Stereo_Buffer::end_frame( blip_time_t time ) +{ + for ( int i = bufs_size; --i >= 0; ) + bufs [i].end_frame( time ); +} + +long Stereo_Buffer::read_samples( blip_sample_t* out, long out_size ) +{ + require( (out_size & 1) == 0 ); // must read an even number of samples + out_size = min( out_size, samples_avail() ); + + int pair_count = int (out_size >> 1); + if ( pair_count ) + { + mixer.read_pairs( out, pair_count ); + + if ( samples_avail() <= 0 || immediate_removal() ) + { + for ( int i = bufs_size; --i >= 0; ) + { + buf_t& b = bufs [i]; + // TODO: might miss non-silence settling since it checks END of last read + if ( !b.non_silent() ) + b.remove_silence( mixer.samples_read ); + else + b.remove_samples( mixer.samples_read ); + } + mixer.samples_read = 0; + } + } + return out_size; +} + + +// Stereo_Mixer + +// mixers use a single index value to improve performance on register-challenged processors +// offset goes from negative to zero + +void Stereo_Mixer::read_pairs( blip_sample_t* out, int count ) +{ + // TODO: if caller never marks buffers as modified, uses mono + // except that buffer isn't cleared, so caller can encounter + // subtle problems and not realize the cause. + samples_read += count; + if ( bufs [0]->non_silent() | bufs [1]->non_silent() ) + mix_stereo( out, count ); + else + mix_mono( out, count ); +} + +void Stereo_Mixer::mix_mono( blip_sample_t* out_, int count ) +{ + int const bass = BLIP_READER_BASS( *bufs [2] ); + BLIP_READER_BEGIN( center, *bufs [2] ); + BLIP_READER_ADJ_( center, samples_read ); + + typedef blip_sample_t stereo_blip_sample_t [stereo]; + stereo_blip_sample_t* BLIP_RESTRICT out = (stereo_blip_sample_t*) out_ + count; + int offset = -count; + do + { + blargg_long s = BLIP_READER_READ( center ); + BLIP_READER_NEXT_IDX_( center, bass, offset ); + BLIP_CLAMP( s, s ); + + out [offset] [0] = (blip_sample_t) s; + out [offset] [1] = (blip_sample_t) s; + } + while ( ++offset ); + + BLIP_READER_END( center, *bufs [2] ); +} + +void Stereo_Mixer::mix_stereo( blip_sample_t* out_, int count ) +{ + blip_sample_t* BLIP_RESTRICT out = out_ + count * stereo; + + // do left + center and right + center separately to reduce register load + Tracked_Blip_Buffer* const* buf = &bufs [2]; + while ( true ) // loop runs twice + { + --buf; + --out; + + int const bass = BLIP_READER_BASS( *bufs [2] ); + BLIP_READER_BEGIN( side, **buf ); + BLIP_READER_BEGIN( center, *bufs [2] ); + + BLIP_READER_ADJ_( side, samples_read ); + BLIP_READER_ADJ_( center, samples_read ); + + int offset = -count; + do + { + blargg_long s = BLIP_READER_READ_RAW( center ) + BLIP_READER_READ_RAW( side ); + s >>= blip_sample_bits - 16; + BLIP_READER_NEXT_IDX_( side, bass, offset ); + BLIP_READER_NEXT_IDX_( center, bass, offset ); + BLIP_CLAMP( s, s ); + + ++offset; // before write since out is decremented to slightly before end + out [offset * stereo] = (blip_sample_t) s; + } + while ( offset ); + + BLIP_READER_END( side, **buf ); + + if ( buf != bufs ) + continue; + + // only end center once + BLIP_READER_END( center, *bufs [2] ); + break; + } +} diff --git a/src/dmg/gb_apu/Multi_Buffer.h b/src/dmg/gb_apu/Multi_Buffer.h index bc5214c8..d22075d0 100644 --- a/src/dmg/gb_apu/Multi_Buffer.h +++ b/src/dmg/gb_apu/Multi_Buffer.h @@ -1,205 +1,205 @@ -// Multi-channel sound buffer interface, and basic mono and stereo buffers - -// Blip_Buffer 0.4.1 -#ifndef MULTI_BUFFER_H -#define MULTI_BUFFER_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -// Interface to one or more Blip_Buffers mapped to one or more channels -// consisting of left, center, and right buffers. -class Multi_Buffer { -public: - Multi_Buffer( int samples_per_frame ); - virtual ~Multi_Buffer() { } - - // Sets the number of channels available and optionally their types - // (type information used by Effects_Buffer) - enum { type_index_mask = 0xFF }; - enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type }; - virtual blargg_err_t set_channel_count( int, int const* types = 0 ); - int channel_count() const { return channel_count_; } - - // Gets indexed channel, from 0 to channel count - 1 - struct channel_t { - Blip_Buffer* center; - Blip_Buffer* left; - Blip_Buffer* right; - }; - virtual channel_t channel( int index ) BLARGG_PURE( ; ) - - // See Blip_Buffer.h - virtual blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ) BLARGG_PURE( ; ) - virtual void clock_rate( long ) BLARGG_PURE( { } ) - virtual void bass_freq( int ) BLARGG_PURE( { } ) - virtual void clear() BLARGG_PURE( { } ) - long sample_rate() const; - - // Length of buffer, in milliseconds - int length() const; - - // See Blip_Buffer.h - virtual void end_frame( blip_time_t ) BLARGG_PURE( { } ) - - // Number of samples per output frame (1 = mono, 2 = stereo) - int samples_per_frame() const; - - // Count of changes to channel configuration. Incremented whenever - // a change is made to any of the Blip_Buffers for any channel. - unsigned channels_changed_count() { return channels_changed_count_; } - - // See Blip_Buffer.h - virtual long read_samples( blip_sample_t*, long ) BLARGG_PURE( { return 0; } ) - virtual long samples_avail() const BLARGG_PURE( { return 0; } ) - -public: - BLARGG_DISABLE_NOTHROW - void disable_immediate_removal() { immediate_removal_ = false; } -protected: - bool immediate_removal() const { return immediate_removal_; } - int const* channel_types() const { return channel_types_; } - void channels_changed() { channels_changed_count_++; } -private: - // noncopyable - Multi_Buffer( const Multi_Buffer& ); - Multi_Buffer& operator = ( const Multi_Buffer& ); - - unsigned channels_changed_count_; - long sample_rate_; - int length_; - int channel_count_; - int const samples_per_frame_; - int const* channel_types_; - bool immediate_removal_; -}; - -// Uses a single buffer and outputs mono samples. -class Mono_Buffer : public Multi_Buffer { - Blip_Buffer buf; - channel_t chan; -public: - // Buffer used for all channels - Blip_Buffer* center() { return &buf; } - -public: - Mono_Buffer(); - ~Mono_Buffer(); - blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ); - void clock_rate( long rate ) { buf.clock_rate( rate ); } - void bass_freq( int freq ) { buf.bass_freq( freq ); } - void clear() { buf.clear(); } - long samples_avail() const { return buf.samples_avail(); } - long read_samples( blip_sample_t* p, long s ) { return buf.read_samples( p, s ); } - channel_t channel( int ) { return chan; } - void end_frame( blip_time_t t ) { buf.end_frame( t ); } -}; - - class Tracked_Blip_Buffer : public Blip_Buffer { - public: - // Non-zero if buffer still has non-silent samples in it. Requires that you call - // set_modified() appropriately. - blip_ulong non_silent() const; - - // remove_samples( samples_avail() ) - void remove_all_samples(); - - public: - BLARGG_DISABLE_NOTHROW - - long read_samples( blip_sample_t*, long ); - void remove_silence( long ); - void remove_samples( long ); - Tracked_Blip_Buffer(); - void clear(); - void end_frame( blip_time_t ); - private: - blip_long last_non_silence; - void remove_( long ); - }; - - class Stereo_Mixer { - public: - Tracked_Blip_Buffer* bufs [3]; - blargg_long samples_read; - - Stereo_Mixer() : samples_read( 0 ) { } - void read_pairs( blip_sample_t* out, int count ); - private: - void mix_mono ( blip_sample_t* out, int pair_count ); - void mix_stereo( blip_sample_t* out, int pair_count ); - }; - -// Uses three buffers (one for center) and outputs stereo sample pairs. -class Stereo_Buffer : public Multi_Buffer { -public: - - // Buffers used for all channels - Blip_Buffer* center() { return &bufs [2]; } - Blip_Buffer* left() { return &bufs [0]; } - Blip_Buffer* right() { return &bufs [1]; } - -public: - Stereo_Buffer(); - ~Stereo_Buffer(); - blargg_err_t set_sample_rate( long, int msec = blip_default_length ); - void clock_rate( long ); - void bass_freq( int ); - void clear(); - channel_t channel( int ) { return chan; } - void end_frame( blip_time_t ); - - long samples_avail() const { return (bufs [0].samples_avail() - mixer.samples_read) * 2; } - long read_samples( blip_sample_t*, long ); - -private: - enum { bufs_size = 3 }; - typedef Tracked_Blip_Buffer buf_t; - buf_t bufs [bufs_size]; - Stereo_Mixer mixer; - channel_t chan; - long samples_avail_; -}; - -// Silent_Buffer generates no samples, useful where no sound is wanted -class Silent_Buffer : public Multi_Buffer { - channel_t chan; -public: - Silent_Buffer(); - blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ); - void clock_rate( long ) { } - void bass_freq( int ) { } - void clear() { } - channel_t channel( int ) { return chan; } - void end_frame( blip_time_t ) { } - long samples_avail() const { return 0; } - long read_samples( blip_sample_t*, long ) { return 0; } -}; - - -inline blargg_err_t Multi_Buffer::set_sample_rate( long rate, int msec ) -{ - sample_rate_ = rate; - length_ = msec; - return 0; -} - -inline blargg_err_t Silent_Buffer::set_sample_rate( long rate, int msec ) -{ - return Multi_Buffer::set_sample_rate( rate, msec ); -} - -inline int Multi_Buffer::samples_per_frame() const { return samples_per_frame_; } - -inline long Multi_Buffer::sample_rate() const { return sample_rate_; } - -inline int Multi_Buffer::length() const { return length_; } - -inline blargg_err_t Multi_Buffer::set_channel_count( int n, int const* types ) -{ - channel_count_ = n; - channel_types_ = types; - return 0; -} - -#endif +// Multi-channel sound buffer interface, and basic mono and stereo buffers + +// Blip_Buffer 0.4.1 +#ifndef MULTI_BUFFER_H +#define MULTI_BUFFER_H + +#include "blargg_common.h" +#include "Blip_Buffer.h" + +// Interface to one or more Blip_Buffers mapped to one or more channels +// consisting of left, center, and right buffers. +class Multi_Buffer { +public: + Multi_Buffer( int samples_per_frame ); + virtual ~Multi_Buffer() { } + + // Sets the number of channels available and optionally their types + // (type information used by Effects_Buffer) + enum { type_index_mask = 0xFF }; + enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type }; + virtual blargg_err_t set_channel_count( int, int const* types = 0 ); + int channel_count() const { return channel_count_; } + + // Gets indexed channel, from 0 to channel count - 1 + struct channel_t { + Blip_Buffer* center; + Blip_Buffer* left; + Blip_Buffer* right; + }; + virtual channel_t channel( int index ) BLARGG_PURE( ; ) + + // See Blip_Buffer.h + virtual blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ) BLARGG_PURE( ; ) + virtual void clock_rate( long ) BLARGG_PURE( { } ) + virtual void bass_freq( int ) BLARGG_PURE( { } ) + virtual void clear() BLARGG_PURE( { } ) + long sample_rate() const; + + // Length of buffer, in milliseconds + int length() const; + + // See Blip_Buffer.h + virtual void end_frame( blip_time_t ) BLARGG_PURE( { } ) + + // Number of samples per output frame (1 = mono, 2 = stereo) + int samples_per_frame() const; + + // Count of changes to channel configuration. Incremented whenever + // a change is made to any of the Blip_Buffers for any channel. + unsigned channels_changed_count() { return channels_changed_count_; } + + // See Blip_Buffer.h + virtual long read_samples( blip_sample_t*, long ) BLARGG_PURE( { return 0; } ) + virtual long samples_avail() const BLARGG_PURE( { return 0; } ) + +public: + BLARGG_DISABLE_NOTHROW + void disable_immediate_removal() { immediate_removal_ = false; } +protected: + bool immediate_removal() const { return immediate_removal_; } + int const* channel_types() const { return channel_types_; } + void channels_changed() { channels_changed_count_++; } +private: + // noncopyable + Multi_Buffer( const Multi_Buffer& ); + Multi_Buffer& operator = ( const Multi_Buffer& ); + + unsigned channels_changed_count_; + long sample_rate_; + int length_; + int channel_count_; + int const samples_per_frame_; + int const* channel_types_; + bool immediate_removal_; +}; + +// Uses a single buffer and outputs mono samples. +class Mono_Buffer : public Multi_Buffer { + Blip_Buffer buf; + channel_t chan; +public: + // Buffer used for all channels + Blip_Buffer* center() { return &buf; } + +public: + Mono_Buffer(); + ~Mono_Buffer(); + blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ); + void clock_rate( long rate ) { buf.clock_rate( rate ); } + void bass_freq( int freq ) { buf.bass_freq( freq ); } + void clear() { buf.clear(); } + long samples_avail() const { return buf.samples_avail(); } + long read_samples( blip_sample_t* p, long s ) { return buf.read_samples( p, s ); } + channel_t channel( int ) { return chan; } + void end_frame( blip_time_t t ) { buf.end_frame( t ); } +}; + + class Tracked_Blip_Buffer : public Blip_Buffer { + public: + // Non-zero if buffer still has non-silent samples in it. Requires that you call + // set_modified() appropriately. + blip_ulong non_silent() const; + + // remove_samples( samples_avail() ) + void remove_all_samples(); + + public: + BLARGG_DISABLE_NOTHROW + + long read_samples( blip_sample_t*, long ); + void remove_silence( long ); + void remove_samples( long ); + Tracked_Blip_Buffer(); + void clear(); + void end_frame( blip_time_t ); + private: + blip_long last_non_silence; + void remove_( long ); + }; + + class Stereo_Mixer { + public: + Tracked_Blip_Buffer* bufs [3]; + blargg_long samples_read; + + Stereo_Mixer() : samples_read( 0 ) { } + void read_pairs( blip_sample_t* out, int count ); + private: + void mix_mono ( blip_sample_t* out, int pair_count ); + void mix_stereo( blip_sample_t* out, int pair_count ); + }; + +// Uses three buffers (one for center) and outputs stereo sample pairs. +class Stereo_Buffer : public Multi_Buffer { +public: + + // Buffers used for all channels + Blip_Buffer* center() { return &bufs [2]; } + Blip_Buffer* left() { return &bufs [0]; } + Blip_Buffer* right() { return &bufs [1]; } + +public: + Stereo_Buffer(); + ~Stereo_Buffer(); + blargg_err_t set_sample_rate( long, int msec = blip_default_length ); + void clock_rate( long ); + void bass_freq( int ); + void clear(); + channel_t channel( int ) { return chan; } + void end_frame( blip_time_t ); + + long samples_avail() const { return (bufs [0].samples_avail() - mixer.samples_read) * 2; } + long read_samples( blip_sample_t*, long ); + +private: + enum { bufs_size = 3 }; + typedef Tracked_Blip_Buffer buf_t; + buf_t bufs [bufs_size]; + Stereo_Mixer mixer; + channel_t chan; + long samples_avail_; +}; + +// Silent_Buffer generates no samples, useful where no sound is wanted +class Silent_Buffer : public Multi_Buffer { + channel_t chan; +public: + Silent_Buffer(); + blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ); + void clock_rate( long ) { } + void bass_freq( int ) { } + void clear() { } + channel_t channel( int ) { return chan; } + void end_frame( blip_time_t ) { } + long samples_avail() const { return 0; } + long read_samples( blip_sample_t*, long ) { return 0; } +}; + + +inline blargg_err_t Multi_Buffer::set_sample_rate( long rate, int msec ) +{ + sample_rate_ = rate; + length_ = msec; + return 0; +} + +inline blargg_err_t Silent_Buffer::set_sample_rate( long rate, int msec ) +{ + return Multi_Buffer::set_sample_rate( rate, msec ); +} + +inline int Multi_Buffer::samples_per_frame() const { return samples_per_frame_; } + +inline long Multi_Buffer::sample_rate() const { return sample_rate_; } + +inline int Multi_Buffer::length() const { return length_; } + +inline blargg_err_t Multi_Buffer::set_channel_count( int n, int const* types ) +{ + channel_count_ = n; + channel_types_ = types; + return 0; +} + +#endif diff --git a/src/dmg/gb_apu/blargg_common.h b/src/dmg/gb_apu/blargg_common.h index 85508541..1203d387 100644 --- a/src/dmg/gb_apu/blargg_common.h +++ b/src/dmg/gb_apu/blargg_common.h @@ -1,206 +1,206 @@ -// Sets up common environment for Shay Green's libraries. -// To change configuration options, modify blargg_config.h, not this file. - -// Gb_Snd_Emu 0.2.0 -#ifndef BLARGG_COMMON_H -#define BLARGG_COMMON_H - -#include -#include -#include -#include - -#undef BLARGG_COMMON_H -// allow blargg_config.h to #include blargg_common.h -#include "blargg_config.h" -#ifndef BLARGG_COMMON_H -#define BLARGG_COMMON_H - -// BLARGG_RESTRICT: equivalent to restrict, where supported -#if __GNUC__ >= 3 || _MSC_VER >= 1100 - #define BLARGG_RESTRICT __restrict -#else - #define BLARGG_RESTRICT -#endif - -// STATIC_CAST(T,expr): Used in place of static_cast (expr) -// CONST_CAST( T,expr): Used in place of const_cast (expr) -#ifndef STATIC_CAST - #if __GNUC__ >= 4 - #define STATIC_CAST(T,expr) static_cast (expr) - #define CONST_CAST( T,expr) const_cast (expr) - #else - #define STATIC_CAST(T,expr) ((T) (expr)) - #define CONST_CAST( T,expr) ((T) (expr)) - #endif -#endif - -// blargg_err_t (0 on success, otherwise error string) -#ifndef blargg_err_t - typedef const char* blargg_err_t; -#endif - -// blargg_vector - very lightweight vector of POD types (no constructor/destructor) -template -class blargg_vector { - T* begin_; - size_t size_; -public: - blargg_vector() : begin_( 0 ), size_( 0 ) { } - ~blargg_vector() { free( begin_ ); } - size_t size() const { return size_; } - T* begin() const { return begin_; } - T* end() const { return begin_ + size_; } - blargg_err_t resize( size_t n ) - { - // TODO: blargg_common.cpp to hold this as an outline function, ugh - void* p = realloc( begin_, n * sizeof (T) ); - if ( p ) - begin_ = (T*) p; - else if ( n > size_ ) // realloc failure only a problem if expanding - return "Out of memory"; - size_ = n; - return 0; - } - void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } - T& operator [] ( size_t n ) const - { - assert( n <= size_ ); // <= to allow past-the-end value - return begin_ [n]; - } -}; - -#ifndef BLARGG_DISABLE_NOTHROW - // throw spec mandatory in ISO C++ if operator new can return NULL - #if __cplusplus >= 199711 || __GNUC__ >= 3 - #define BLARGG_THROWS( spec ) throw spec - #else - #define BLARGG_THROWS( spec ) - #endif - #define BLARGG_DISABLE_NOTHROW \ - void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ - void operator delete ( void* p ) { free( p ); } - #define BLARGG_NEW new -#else - #include - #define BLARGG_NEW new (std::nothrow) -#endif - -// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant) -#define BLARGG_4CHAR( a, b, c, d ) \ - ((a&0xFF)*0x1000000 + (b&0xFF)*0x10000 + (c&0xFF)*0x100 + (d&0xFF)) - -// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. -#ifndef BOOST_STATIC_ASSERT - #ifdef _MSC_VER - // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified - #define BOOST_STATIC_ASSERT( expr ) \ - void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) - #else - // Some other compilers fail when declaring same function multiple times in class, - // so differentiate them by line - #define BOOST_STATIC_ASSERT( expr ) \ - void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) - #endif -#endif - -// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, -// compiler is assumed to support bool. If undefined, availability is determined. -#ifndef BLARGG_COMPILER_HAS_BOOL - #if defined (__MWERKS__) - #if !__option(bool) - #define BLARGG_COMPILER_HAS_BOOL 0 - #endif - #elif defined (_MSC_VER) - #if _MSC_VER < 1100 - #define BLARGG_COMPILER_HAS_BOOL 0 - #endif - #elif defined (__GNUC__) - // supports bool - #elif __cplusplus < 199711 - #define BLARGG_COMPILER_HAS_BOOL 0 - #endif -#endif -#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL - // If you get errors here, modify your blargg_config.h file - typedef int bool; - const bool true = 1; - const bool false = 0; -#endif - -// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough - -#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF - typedef long blargg_long; -#else - typedef int blargg_long; -#endif - -#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF - typedef unsigned long blargg_ulong; -#else - typedef unsigned blargg_ulong; -#endif - -// BOOST::int8_t etc. - -// HAVE_STDINT_H: If defined, use for int8_t etc. -#if defined (HAVE_STDINT_H) - #include - #define BOOST - -// HAVE_INTTYPES_H: If defined, use for int8_t etc. -#elif defined (HAVE_INTTYPES_H) - #include - #define BOOST - -#else - struct BOOST - { - #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F - typedef signed char int8_t; - typedef unsigned char uint8_t; - #else - // No suitable 8-bit type available - typedef struct see_blargg_common_h int8_t; - typedef struct see_blargg_common_h uint8_t; - #endif - - #if USHRT_MAX == 0xFFFF - typedef short int16_t; - typedef unsigned short uint16_t; - #else - // No suitable 16-bit type available - typedef struct see_blargg_common_h int16_t; - typedef struct see_blargg_common_h uint16_t; - #endif - - #if ULONG_MAX == 0xFFFFFFFF - typedef long int32_t; - typedef unsigned long uint32_t; - #elif UINT_MAX == 0xFFFFFFFF - typedef int int32_t; - typedef unsigned int uint32_t; - #else - // No suitable 32-bit type available - typedef struct see_blargg_common_h int32_t; - typedef struct see_blargg_common_h uint32_t; - #endif - }; -#endif - -#if __GNUC__ >= 3 - #define BLARGG_DEPRECATED __attribute__ ((deprecated)) -#else - #define BLARGG_DEPRECATED -#endif - -// Use in place of "= 0;" for a pure virtual, since these cause calls to std C++ lib. -// During development, BLARGG_PURE( x ) expands to = 0; -// virtual int func() BLARGG_PURE( { return 0; } ) -#ifndef BLARGG_PURE - #define BLARGG_PURE( def ) def -#endif - -#endif -#endif +// Sets up common environment for Shay Green's libraries. +// To change configuration options, modify blargg_config.h, not this file. + +// Gb_Snd_Emu 0.2.0 +#ifndef BLARGG_COMMON_H +#define BLARGG_COMMON_H + +#include +#include +#include +#include + +#undef BLARGG_COMMON_H +// allow blargg_config.h to #include blargg_common.h +#include "blargg_config.h" +#ifndef BLARGG_COMMON_H +#define BLARGG_COMMON_H + +// BLARGG_RESTRICT: equivalent to restrict, where supported +#if __GNUC__ >= 3 || _MSC_VER >= 1100 + #define BLARGG_RESTRICT __restrict +#else + #define BLARGG_RESTRICT +#endif + +// STATIC_CAST(T,expr): Used in place of static_cast (expr) +// CONST_CAST( T,expr): Used in place of const_cast (expr) +#ifndef STATIC_CAST + #if __GNUC__ >= 4 + #define STATIC_CAST(T,expr) static_cast (expr) + #define CONST_CAST( T,expr) const_cast (expr) + #else + #define STATIC_CAST(T,expr) ((T) (expr)) + #define CONST_CAST( T,expr) ((T) (expr)) + #endif +#endif + +// blargg_err_t (0 on success, otherwise error string) +#ifndef blargg_err_t + typedef const char* blargg_err_t; +#endif + +// blargg_vector - very lightweight vector of POD types (no constructor/destructor) +template +class blargg_vector { + T* begin_; + size_t size_; +public: + blargg_vector() : begin_( 0 ), size_( 0 ) { } + ~blargg_vector() { free( begin_ ); } + size_t size() const { return size_; } + T* begin() const { return begin_; } + T* end() const { return begin_ + size_; } + blargg_err_t resize( size_t n ) + { + // TODO: blargg_common.cpp to hold this as an outline function, ugh + void* p = realloc( begin_, n * sizeof (T) ); + if ( p ) + begin_ = (T*) p; + else if ( n > size_ ) // realloc failure only a problem if expanding + return "Out of memory"; + size_ = n; + return 0; + } + void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } + T& operator [] ( size_t n ) const + { + assert( n <= size_ ); // <= to allow past-the-end value + return begin_ [n]; + } +}; + +#ifndef BLARGG_DISABLE_NOTHROW + // throw spec mandatory in ISO C++ if operator new can return NULL + #if __cplusplus >= 199711 || __GNUC__ >= 3 + #define BLARGG_THROWS( spec ) throw spec + #else + #define BLARGG_THROWS( spec ) + #endif + #define BLARGG_DISABLE_NOTHROW \ + void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ + void operator delete ( void* p ) { free( p ); } + #define BLARGG_NEW new +#else + #include + #define BLARGG_NEW new (std::nothrow) +#endif + +// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant) +#define BLARGG_4CHAR( a, b, c, d ) \ + ((a&0xFF)*0x1000000 + (b&0xFF)*0x10000 + (c&0xFF)*0x100 + (d&0xFF)) + +// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. +#ifndef BOOST_STATIC_ASSERT + #ifdef _MSC_VER + // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified + #define BOOST_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) + #else + // Some other compilers fail when declaring same function multiple times in class, + // so differentiate them by line + #define BOOST_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) + #endif +#endif + +// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, +// compiler is assumed to support bool. If undefined, availability is determined. +#ifndef BLARGG_COMPILER_HAS_BOOL + #if defined (__MWERKS__) + #if !__option(bool) + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif + #elif defined (_MSC_VER) + #if _MSC_VER < 1100 + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif + #elif defined (__GNUC__) + // supports bool + #elif __cplusplus < 199711 + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif +#endif +#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL + // If you get errors here, modify your blargg_config.h file + typedef int bool; + const bool true = 1; + const bool false = 0; +#endif + +// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough + +#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF + typedef long blargg_long; +#else + typedef int blargg_long; +#endif + +#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF + typedef unsigned long blargg_ulong; +#else + typedef unsigned blargg_ulong; +#endif + +// BOOST::int8_t etc. + +// HAVE_STDINT_H: If defined, use for int8_t etc. +#if defined (HAVE_STDINT_H) + #include + #define BOOST + +// HAVE_INTTYPES_H: If defined, use for int8_t etc. +#elif defined (HAVE_INTTYPES_H) + #include + #define BOOST + +#else + struct BOOST + { + #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F + typedef signed char int8_t; + typedef unsigned char uint8_t; + #else + // No suitable 8-bit type available + typedef struct see_blargg_common_h int8_t; + typedef struct see_blargg_common_h uint8_t; + #endif + + #if USHRT_MAX == 0xFFFF + typedef short int16_t; + typedef unsigned short uint16_t; + #else + // No suitable 16-bit type available + typedef struct see_blargg_common_h int16_t; + typedef struct see_blargg_common_h uint16_t; + #endif + + #if ULONG_MAX == 0xFFFFFFFF + typedef long int32_t; + typedef unsigned long uint32_t; + #elif UINT_MAX == 0xFFFFFFFF + typedef int int32_t; + typedef unsigned int uint32_t; + #else + // No suitable 32-bit type available + typedef struct see_blargg_common_h int32_t; + typedef struct see_blargg_common_h uint32_t; + #endif + }; +#endif + +#if __GNUC__ >= 3 + #define BLARGG_DEPRECATED __attribute__ ((deprecated)) +#else + #define BLARGG_DEPRECATED +#endif + +// Use in place of "= 0;" for a pure virtual, since these cause calls to std C++ lib. +// During development, BLARGG_PURE( x ) expands to = 0; +// virtual int func() BLARGG_PURE( { return 0; } ) +#ifndef BLARGG_PURE + #define BLARGG_PURE( def ) def +#endif + +#endif +#endif diff --git a/src/dmg/gb_apu/blargg_config.h b/src/dmg/gb_apu/blargg_config.h index b861487f..961e0453 100644 --- a/src/dmg/gb_apu/blargg_config.h +++ b/src/dmg/gb_apu/blargg_config.h @@ -1,33 +1,33 @@ -// $package user configuration file. Don't replace when updating library. - -#ifndef BLARGG_CONFIG_H -#define BLARGG_CONFIG_H - -// Uncomment to have Gb_Apu run at 4x normal clock rate (16777216 Hz), useful in -// a Game Boy Advance emulator. -#define GB_APU_OVERCLOCK 4 - -#define GB_APU_CUSTOM_STATE 1 - -// Uncomment to enable platform-specific (and possibly non-portable) optimizations. -//#define BLARGG_NONPORTABLE 1 - -// Uncomment if automatic byte-order determination doesn't work -//#define BLARGG_BIG_ENDIAN 1 - -// Uncomment to use zlib for transparent decompression of gzipped files -//#define HAVE_ZLIB_H - -// Uncomment if you get errors in the bool section of blargg_common.h -//#define BLARGG_COMPILER_HAS_BOOL 1 - -// Uncomment to disable out-of-memory exceptions -//#include -//#define BLARGG_NEW new (std::nothrow) - -// Use standard config.h if present -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#endif +// $package user configuration file. Don't replace when updating library. + +#ifndef BLARGG_CONFIG_H +#define BLARGG_CONFIG_H + +// Uncomment to have Gb_Apu run at 4x normal clock rate (16777216 Hz), useful in +// a Game Boy Advance emulator. +#define GB_APU_OVERCLOCK 4 + +#define GB_APU_CUSTOM_STATE 1 + +// Uncomment to enable platform-specific (and possibly non-portable) optimizations. +//#define BLARGG_NONPORTABLE 1 + +// Uncomment if automatic byte-order determination doesn't work +//#define BLARGG_BIG_ENDIAN 1 + +// Uncomment to use zlib for transparent decompression of gzipped files +//#define HAVE_ZLIB_H + +// Uncomment if you get errors in the bool section of blargg_common.h +//#define BLARGG_COMPILER_HAS_BOOL 1 + +// Uncomment to disable out-of-memory exceptions +//#include +//#define BLARGG_NEW new (std::nothrow) + +// Use standard config.h if present +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#endif diff --git a/src/dmg/gb_apu/blargg_source.h b/src/dmg/gb_apu/blargg_source.h index 53c354aa..ddef37d6 100644 --- a/src/dmg/gb_apu/blargg_source.h +++ b/src/dmg/gb_apu/blargg_source.h @@ -1,92 +1,92 @@ -/* Included at the beginning of library source files, AFTER all other #include lines. -Sets up helpful macros and services used in my source code. Since this is only "active" -in my source code, I don't have to worry about polluting the global namespace with -unprefixed names. */ - -// Gb_Snd_Emu 0.2.0 -#ifndef BLARGG_SOURCE_H -#define BLARGG_SOURCE_H - -// The following four macros are for debugging only. Some or all might be defined -// to do nothing, depending on the circumstances. Described is what happens when -// a particular macro is defined to do something. When defined to do nothing, the -// macros do NOT evaluate their argument(s). - -// If expr is false, prints file and line number, then aborts program. Meant for -// checking internal state and consistency. A failed assertion indicates a bug -// in MY code. -// -// void assert( bool expr ); -#include - -// If expr is false, prints file and line number, then aborts program. Meant for -// checking caller-supplied parameters and operations that are outside the control -// of the module. A failed requirement probably indicates a bug in YOUR code. -// -// void require( bool expr ); -#undef require -#define require( expr ) assert( expr ) - -// Like printf() except output goes to debugging console/file. -// -// void dprintf( const char* format, ... ); -static inline void blargg_dprintf_( const char*, ... ) { } -#undef dprintf -#define dprintf (1) ? (void) 0 : blargg_dprintf_ - -// If expr is false, prints file and line number to debug console/log, then -// continues execution normally. Meant for flagging potential problems or things -// that should be looked into, but that aren't serious problems. -// -// void check( bool expr ); -#undef check -#define check( expr ) ((void) 0) - -// If expr yields non-NULL error string, returns it from current function, -// otherwise continues normally. -#undef RETURN_ERR -#define RETURN_ERR( expr ) do { \ - blargg_err_t blargg_return_err_ = (expr); \ - if ( blargg_return_err_ ) return blargg_return_err_; \ - } while ( 0 ) - -// If ptr is NULL, returns "Out of memory" error string, otherwise continues normally. -#undef CHECK_ALLOC -#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 ) - -// The usual min/max functions for built-in types. -// -// template T min( T x, T y ) { return x < y ? x : y; } -// template T max( T x, T y ) { return x > y ? x : y; } -#define BLARGG_DEF_MIN_MAX( type ) \ - static inline type blargg_min( type x, type y ) { if ( y < x ) x = y; return x; }\ - static inline type blargg_max( type x, type y ) { if ( x < y ) x = y; return x; } - -BLARGG_DEF_MIN_MAX( int ) -BLARGG_DEF_MIN_MAX( unsigned ) -BLARGG_DEF_MIN_MAX( long ) -BLARGG_DEF_MIN_MAX( unsigned long ) -BLARGG_DEF_MIN_MAX( float ) -BLARGG_DEF_MIN_MAX( double ) - -#undef min -#define min blargg_min - -#undef max -#define max blargg_max - -// typedef unsigned char byte; -typedef unsigned char blargg_byte; -#undef byte -#define byte blargg_byte - -// deprecated -#define BLARGG_CHECK_ALLOC CHECK_ALLOC -#define BLARGG_RETURN_ERR RETURN_ERR - -// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check -#ifdef BLARGG_SOURCE_BEGIN - #include BLARGG_SOURCE_BEGIN -#endif - -#endif +/* Included at the beginning of library source files, AFTER all other #include lines. +Sets up helpful macros and services used in my source code. Since this is only "active" +in my source code, I don't have to worry about polluting the global namespace with +unprefixed names. */ + +// Gb_Snd_Emu 0.2.0 +#ifndef BLARGG_SOURCE_H +#define BLARGG_SOURCE_H + +// The following four macros are for debugging only. Some or all might be defined +// to do nothing, depending on the circumstances. Described is what happens when +// a particular macro is defined to do something. When defined to do nothing, the +// macros do NOT evaluate their argument(s). + +// If expr is false, prints file and line number, then aborts program. Meant for +// checking internal state and consistency. A failed assertion indicates a bug +// in MY code. +// +// void assert( bool expr ); +#include + +// If expr is false, prints file and line number, then aborts program. Meant for +// checking caller-supplied parameters and operations that are outside the control +// of the module. A failed requirement probably indicates a bug in YOUR code. +// +// void require( bool expr ); +#undef require +#define require( expr ) assert( expr ) + +// Like printf() except output goes to debugging console/file. +// +// void dprintf( const char* format, ... ); +static inline void blargg_dprintf_( const char*, ... ) { } +#undef dprintf +#define dprintf (1) ? (void) 0 : blargg_dprintf_ + +// If expr is false, prints file and line number to debug console/log, then +// continues execution normally. Meant for flagging potential problems or things +// that should be looked into, but that aren't serious problems. +// +// void check( bool expr ); +#undef check +#define check( expr ) ((void) 0) + +// If expr yields non-NULL error string, returns it from current function, +// otherwise continues normally. +#undef RETURN_ERR +#define RETURN_ERR( expr ) do { \ + blargg_err_t blargg_return_err_ = (expr); \ + if ( blargg_return_err_ ) return blargg_return_err_; \ + } while ( 0 ) + +// If ptr is NULL, returns "Out of memory" error string, otherwise continues normally. +#undef CHECK_ALLOC +#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 ) + +// The usual min/max functions for built-in types. +// +// template T min( T x, T y ) { return x < y ? x : y; } +// template T max( T x, T y ) { return x > y ? x : y; } +#define BLARGG_DEF_MIN_MAX( type ) \ + static inline type blargg_min( type x, type y ) { if ( y < x ) x = y; return x; }\ + static inline type blargg_max( type x, type y ) { if ( x < y ) x = y; return x; } + +BLARGG_DEF_MIN_MAX( int ) +BLARGG_DEF_MIN_MAX( unsigned ) +BLARGG_DEF_MIN_MAX( long ) +BLARGG_DEF_MIN_MAX( unsigned long ) +BLARGG_DEF_MIN_MAX( float ) +BLARGG_DEF_MIN_MAX( double ) + +#undef min +#define min blargg_min + +#undef max +#define max blargg_max + +// typedef unsigned char byte; +typedef unsigned char blargg_byte; +#undef byte +#define byte blargg_byte + +// deprecated +#define BLARGG_CHECK_ALLOC CHECK_ALLOC +#define BLARGG_RETURN_ERR RETURN_ERR + +// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check +#ifdef BLARGG_SOURCE_BEGIN + #include BLARGG_SOURCE_BEGIN +#endif + +#endif diff --git a/src/qt/emu.cpp b/src/qt/emu.cpp index 575209dc..27afbf53 100644 --- a/src/qt/emu.cpp +++ b/src/qt/emu.cpp @@ -1,176 +1,176 @@ -// VBA-M, A Nintendo Handheld Console Emulator -// Copyright (C) 2008 VBA-M development team -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -// This file adds all the code required by System.h - - -#include "emu.h" - - -int emulating = 0; -int systemFrameSkip = 0; -int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; -bool systemSoundOn = false; -u32 systemColorMap32[0x10000]; -u16 systemColorMap16[0x10000]; -int systemRedShift = 0; -int systemBlueShift = 0; -int systemGreenShift = 0; -int systemColorDepth = 32; -int systemDebug = 0; -int systemVerbose = 0; - -void (*dbgSignal)( int sig, int number ) = debuggerSignal; -void (*dbgOutput)( const char *s, u32 addr ) = debuggerOutput; - - -bool systemReadJoypads() -{ - // TODO: implement - return false; -} - -u32 systemReadJoypad( int which ) -{ - // TODO: implement - return 0; -} - -void systemUpdateMotionSensor() -{ - // TODO: implement -} - - -int systemGetSensorX() -{ - // TODO: implement - return 0; -} - - -int systemGetSensorY() -{ - // TODO: implement - return 0; -} - - -u32 systemGetClock() -{ - // TODO: implement - return 0; -} - - -void systemMessage( int number, const char *defaultMsg, ... ) -{ - // TODO: implement -} - - -void systemScreenCapture( int captureNumber ) -{ - // TODO: implement -} - - -void systemDrawScreen() -{ - // TODO: implement -} - - -void systemShowSpeed( int speed ) -{ - // TODO: implement -} - - -void system10Frames( int rate ) -{ - // TODO: implement -} - - -void systemFrame() -{ - // TODO: implement -} - - -bool systemPauseOnFrame() -{ - // TODO: implement - return false; -} - - -void debuggerOutput( const char *s, u32 addr ) -{ - // TODO: implement -} - - -void debuggerSignal( int sig,int number ) -{ - // TODO: implement -} - - -void winlog( const char *msg, ... ) -{ - // TODO: implement -} - - -void systemWriteDataToSoundBuffer() -{ - // TODO: implement -} - -void systemSoundShutdown() -{ - // TODO: implement -} - -void systemSoundPause() -{ - // TODO: implement -} - -void systemSoundResume() -{ - // TODO: implement -} - -void systemSoundReset() -{ - // TODO: implement -} - -bool systemSoundInit() -{ - // TODO: implement - return false; -} - -bool systemCanChangeSoundQuality() -{ - // TODO: implement - return false; -} +// VBA-M, A Nintendo Handheld Console Emulator +// Copyright (C) 2008 VBA-M development team +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +// This file adds all the code required by System.h + + +#include "emu.h" + + +int emulating = 0; +int systemFrameSkip = 0; +int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; +bool systemSoundOn = false; +u32 systemColorMap32[0x10000]; +u16 systemColorMap16[0x10000]; +int systemRedShift = 0; +int systemBlueShift = 0; +int systemGreenShift = 0; +int systemColorDepth = 32; +int systemDebug = 0; +int systemVerbose = 0; + +void (*dbgSignal)( int sig, int number ) = debuggerSignal; +void (*dbgOutput)( const char *s, u32 addr ) = debuggerOutput; + + +bool systemReadJoypads() +{ + // TODO: implement + return false; +} + +u32 systemReadJoypad( int which ) +{ + // TODO: implement + return 0; +} + +void systemUpdateMotionSensor() +{ + // TODO: implement +} + + +int systemGetSensorX() +{ + // TODO: implement + return 0; +} + + +int systemGetSensorY() +{ + // TODO: implement + return 0; +} + + +u32 systemGetClock() +{ + // TODO: implement + return 0; +} + + +void systemMessage( int number, const char *defaultMsg, ... ) +{ + // TODO: implement +} + + +void systemScreenCapture( int captureNumber ) +{ + // TODO: implement +} + + +void systemDrawScreen() +{ + // TODO: implement +} + + +void systemShowSpeed( int speed ) +{ + // TODO: implement +} + + +void system10Frames( int rate ) +{ + // TODO: implement +} + + +void systemFrame() +{ + // TODO: implement +} + + +bool systemPauseOnFrame() +{ + // TODO: implement + return false; +} + + +void debuggerOutput( const char *s, u32 addr ) +{ + // TODO: implement +} + + +void debuggerSignal( int sig,int number ) +{ + // TODO: implement +} + + +void winlog( const char *msg, ... ) +{ + // TODO: implement +} + + +void systemWriteDataToSoundBuffer() +{ + // TODO: implement +} + +void systemSoundShutdown() +{ + // TODO: implement +} + +void systemSoundPause() +{ + // TODO: implement +} + +void systemSoundResume() +{ + // TODO: implement +} + +void systemSoundReset() +{ + // TODO: implement +} + +bool systemSoundInit() +{ + // TODO: implement + return false; +} + +bool systemCanChangeSoundQuality() +{ + // TODO: implement + return false; +} diff --git a/src/qt/emu.h b/src/qt/emu.h index a1e8050c..6c7bce6e 100644 --- a/src/qt/emu.h +++ b/src/qt/emu.h @@ -1,71 +1,71 @@ -// VBA-M, A Nintendo Handheld Console Emulator -// Copyright (C) 2008 VBA-M development team -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - -#ifndef EMU_H -#define EMU_H - - -#include "../System.h" - - -// Global Variables -extern int emulating; -extern int systemFrameSkip; -extern int systemSaveUpdateCounter; -extern bool systemSoundOn; -extern u32 systemColorMap32[0x10000]; -extern u16 systemColorMap16[0x10000]; -extern int systemRedShift; -extern int systemBlueShift; -extern int systemGreenShift; -extern int systemColorDepth; -extern int systemDebug; -extern int systemVerbose; - - -// Global Functions -bool systemReadJoypads(); -u32 systemReadJoypad( int which ); -void systemUpdateMotionSensor(); -int systemGetSensorX(); -int systemGetSensorY(); -u32 systemGetClock(); - -void systemMessage( int number, const char *defaultMsg, ... ); -void winlog( const char *msg, ... ); - -void debuggerSignal( int sig,int number ); -void debuggerOutput( const char *s, u32 addr ); - -bool systemPauseOnFrame(); -void systemScreenCapture( int captureNumber ); -void systemDrawScreen(); -void systemShowSpeed( int speed ); -void system10Frames( int rate ); -void systemFrame(); - -void systemWriteDataToSoundBuffer(); -void systemSoundShutdown(); -void systemSoundPause(); -void systemSoundResume(); -void systemSoundReset(); -bool systemSoundInit(); -bool systemCanChangeSoundQuality(); - - -#endif // #ifndef EMU_H +// VBA-M, A Nintendo Handheld Console Emulator +// Copyright (C) 2008 VBA-M development team +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifndef EMU_H +#define EMU_H + + +#include "../System.h" + + +// Global Variables +extern int emulating; +extern int systemFrameSkip; +extern int systemSaveUpdateCounter; +extern bool systemSoundOn; +extern u32 systemColorMap32[0x10000]; +extern u16 systemColorMap16[0x10000]; +extern int systemRedShift; +extern int systemBlueShift; +extern int systemGreenShift; +extern int systemColorDepth; +extern int systemDebug; +extern int systemVerbose; + + +// Global Functions +bool systemReadJoypads(); +u32 systemReadJoypad( int which ); +void systemUpdateMotionSensor(); +int systemGetSensorX(); +int systemGetSensorY(); +u32 systemGetClock(); + +void systemMessage( int number, const char *defaultMsg, ... ); +void winlog( const char *msg, ... ); + +void debuggerSignal( int sig,int number ); +void debuggerOutput( const char *s, u32 addr ); + +bool systemPauseOnFrame(); +void systemScreenCapture( int captureNumber ); +void systemDrawScreen(); +void systemShowSpeed( int speed ); +void system10Frames( int rate ); +void systemFrame(); + +void systemWriteDataToSoundBuffer(); +void systemSoundShutdown(); +void systemSoundPause(); +void systemSoundResume(); +void systemSoundReset(); +bool systemSoundInit(); +bool systemCanChangeSoundQuality(); + + +#endif // #ifndef EMU_H diff --git a/src/win32/AccelEditor.cpp b/src/win32/AccelEditor.cpp index 536087cb..a44aa653 100644 --- a/src/win32/AccelEditor.cpp +++ b/src/win32/AccelEditor.cpp @@ -1,290 +1,290 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -// AccelEditor.cpp : implementation file -// - -#include "stdafx.h" -#include "vba.h" -#include "AccelEditor.h" -#include "CmdAccelOb.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// AccelEditor dialog - - -AccelEditor::AccelEditor(CWnd* pParent /*=NULL*/) - : ResizeDlg(AccelEditor::IDD, pParent) -{ - //{{AFX_DATA_INIT(AccelEditor) - // NOTE: the ClassWizard will add member initialization here - //}}AFX_DATA_INIT - mgr = theApp.winAccelMgr; -} - - -void AccelEditor::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(AccelEditor) - DDX_Control(pDX, IDC_CURRENTS, m_currents); - DDX_Control(pDX, IDC_ALREADY_AFFECTED, m_alreadyAffected); - DDX_Control(pDX, IDC_COMMANDS, m_commands); - DDX_Control(pDX, IDC_EDIT_KEY, m_key); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(AccelEditor, CDialog) - //{{AFX_MSG_MAP(AccelEditor) - ON_BN_CLICKED(ID_OK, OnOk) - ON_LBN_SELCHANGE(IDC_COMMANDS, OnSelchangeCommands) - ON_BN_CLICKED(IDC_RESET, OnReset) - ON_BN_CLICKED(IDC_ASSIGN, OnAssign) - ON_BN_CLICKED(ID_CANCEL, OnCancel) - ON_BN_CLICKED(IDC_REMOVE, OnRemove) - //}}AFX_MSG_MAP - END_MESSAGE_MAP() - - ///////////////////////////////////////////////////////////////////////////// -// AccelEditor message handlers - -BOOL AccelEditor::OnInitDialog() -{ - CDialog::OnInitDialog(); - - DIALOG_SIZER_START( sz ) - DIALOG_SIZER_ENTRY( IDC_STATIC1, DS_MoveX) - DIALOG_SIZER_ENTRY( IDC_STATIC2, DS_MoveY) - DIALOG_SIZER_ENTRY( IDC_STATIC3, DS_MoveX | DS_MoveY) - DIALOG_SIZER_ENTRY( IDC_ALREADY_AFFECTED, DS_MoveY) - DIALOG_SIZER_ENTRY( ID_OK, DS_MoveX) - DIALOG_SIZER_ENTRY( ID_CANCEL, DS_MoveX) - DIALOG_SIZER_ENTRY( IDC_ASSIGN, DS_MoveX) - DIALOG_SIZER_ENTRY( IDC_REMOVE, DS_MoveX) - DIALOG_SIZER_ENTRY( IDC_RESET, DS_MoveX) - DIALOG_SIZER_ENTRY( IDC_CLOSE, DS_MoveY) - DIALOG_SIZER_ENTRY( IDC_COMMANDS, DS_SizeX | DS_SizeY) - DIALOG_SIZER_ENTRY( IDC_CURRENTS, DS_MoveX | DS_SizeY) - DIALOG_SIZER_ENTRY( IDC_EDIT_KEY, DS_MoveX | DS_MoveY) - DIALOG_SIZER_END() - - SetData(sz, - TRUE, - HKEY_CURRENT_USER, - "Software\\Emulators\\VisualBoyAdvance\\Viewer\\AccelEditor", - NULL); - - InitCommands(); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void AccelEditor::InitCommands() -{ - m_commands.ResetContent(); - m_alreadyAffected.SetWindowText(""); - - POSITION pos = mgr.m_mapAccelString.GetStartPosition(); - - while(pos != NULL) { - CString command; - WORD wID; - mgr.m_mapAccelString.GetNextAssoc(pos, command, wID); - - int index = m_commands.AddString(command); - m_commands.SetItemData(index, wID); - } - - // Update the currents accels associated with the selected command - if (m_commands.SetCurSel(0) != LB_ERR) - OnSelchangeCommands(); -} - -void AccelEditor::OnCancel() -{ - EndDialog(FALSE); -} - -void AccelEditor::OnOk() -{ - EndDialog(TRUE); -} - -void AccelEditor::OnSelchangeCommands() -{ - // Check if some commands exist. - int index = m_commands.GetCurSel(); - if (index == LB_ERR) - return; - - WORD wIDCommand = LOWORD(m_commands.GetItemData(index)); - m_currents.ResetContent(); - - CCmdAccelOb* pCmdAccel; - - if (mgr.m_mapAccelTable.Lookup(wIDCommand, pCmdAccel)) { - CAccelsOb* pAccel; - CString szBuffer; - POSITION pos = pCmdAccel->m_Accels.GetHeadPosition(); - - // Add the keys to the 'currents keys' listbox. - while (pos != NULL) { - pAccel = pCmdAccel->m_Accels.GetNext(pos); - pAccel->GetString(szBuffer); - index = m_currents.AddString(szBuffer); - // and a pointer to the accel object. - m_currents.SetItemData(index, (DWORD_PTR)pAccel); - } - } - // Init the key editor - // m_pKey->ResetKey(); - -} - -void AccelEditor::OnReset() -{ - mgr.Default(); - InitCommands(); // update the listboxes. -} - -void AccelEditor::OnAssign() -{ - // Control if it's not already affected - CCmdAccelOb* pCmdAccel; - CAccelsOb* pAccel; - WORD wIDCommand; - POSITION pos; - - WORD wKey; - bool bCtrl, bAlt, bShift; - - if (!m_key.GetAccelKey(wKey, bCtrl, bAlt, bShift)) - return; // no valid key, abort - - int count = m_commands.GetCount(); - int index; - for (index = 0; index < count; index++) { - - wIDCommand = LOWORD(m_commands.GetItemData(index)); - mgr.m_mapAccelTable.Lookup(wIDCommand, pCmdAccel); - - pos = pCmdAccel->m_Accels.GetHeadPosition(); - while (pos != NULL) { - pAccel = pCmdAccel->m_Accels.GetNext(pos); - if (pAccel->IsEqual(wKey, bCtrl, bAlt, bShift)) { - // the key is already affected (in the same or other command) - m_alreadyAffected.SetWindowText(pCmdAccel->m_szCommand); - m_key.SetSel(0, -1); - return; // abort - } - } - } - - // OK, we can add the accel key in the currently selected group - index = m_commands.GetCurSel(); - if (index == LB_ERR) - return; - - // Get the object who manage the accels list, associated to the command. - wIDCommand = LOWORD(m_commands.GetItemData(index)); - - if (mgr.m_mapAccelTable.Lookup(wIDCommand, pCmdAccel) != TRUE) - return; - - BYTE cVirt = 0; - if (bCtrl) - cVirt |= FCONTROL; - if (bAlt) - cVirt |= FALT; - if (bShift) - cVirt |= FSHIFT; - - cVirt |= FVIRTKEY; - - // Create the new key... - pAccel = new CAccelsOb(cVirt, wKey, false); - ASSERT(pAccel != NULL); - // ...and add in the list. - pCmdAccel->m_Accels.AddTail(pAccel); - - // Update the listbox. - CString szBuffer; - pAccel->GetString(szBuffer); - - index = m_currents.AddString(szBuffer); - m_currents.SetItemData(index, (DWORD_PTR)pAccel); - - // Reset the key editor. - m_key.ResetKey(); -} - -void AccelEditor::OnRemove() -{ - // Some controls - int indexCurrent = m_currents.GetCurSel(); - if (indexCurrent == LB_ERR) - return; - - // 2nd part. - int indexCmd = m_commands.GetCurSel(); - if (indexCmd == LB_ERR) - return; - - // Ref to the ID command - WORD wIDCommand = LOWORD(m_commands.GetItemData(indexCmd)); - - // Run through the accels,and control if it can be deleted. - CCmdAccelOb* pCmdAccel; - if (mgr.m_mapAccelTable.Lookup(wIDCommand, pCmdAccel) == TRUE) { - CAccelsOb* pAccel; - CAccelsOb* pAccelCurrent = (CAccelsOb*)(m_currents.GetItemData(indexCurrent)); - CString szBuffer; - POSITION pos = pCmdAccel->m_Accels.GetHeadPosition(); - POSITION PrevPos; - while (pos != NULL) { - PrevPos = pos; - pAccel = pCmdAccel->m_Accels.GetNext(pos); - if (pAccel == pAccelCurrent) { - if (!pAccel->m_bLocked) { - // not locked, so we delete the key - pCmdAccel->m_Accels.RemoveAt(PrevPos); - delete pAccel; - // and update the listboxes/key editor/static text - m_currents.DeleteString(indexCurrent); - m_key.ResetKey(); - m_alreadyAffected.SetWindowText(""); - return; - } else { - systemMessage(0,"Unable to remove this\naccelerator (Locked)"); - return; - } - } - } - systemMessage(0,"internal error (CAccelDlgHelper::Remove : pAccel unavailable)"); - return; - } - systemMessage(0,"internal error (CAccelDlgHelper::Remove : Lookup failed)"); -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +// AccelEditor.cpp : implementation file +// + +#include "stdafx.h" +#include "vba.h" +#include "AccelEditor.h" +#include "CmdAccelOb.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// AccelEditor dialog + + +AccelEditor::AccelEditor(CWnd* pParent /*=NULL*/) + : ResizeDlg(AccelEditor::IDD, pParent) +{ + //{{AFX_DATA_INIT(AccelEditor) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT + mgr = theApp.winAccelMgr; +} + + +void AccelEditor::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(AccelEditor) + DDX_Control(pDX, IDC_CURRENTS, m_currents); + DDX_Control(pDX, IDC_ALREADY_AFFECTED, m_alreadyAffected); + DDX_Control(pDX, IDC_COMMANDS, m_commands); + DDX_Control(pDX, IDC_EDIT_KEY, m_key); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(AccelEditor, CDialog) + //{{AFX_MSG_MAP(AccelEditor) + ON_BN_CLICKED(ID_OK, OnOk) + ON_LBN_SELCHANGE(IDC_COMMANDS, OnSelchangeCommands) + ON_BN_CLICKED(IDC_RESET, OnReset) + ON_BN_CLICKED(IDC_ASSIGN, OnAssign) + ON_BN_CLICKED(ID_CANCEL, OnCancel) + ON_BN_CLICKED(IDC_REMOVE, OnRemove) + //}}AFX_MSG_MAP + END_MESSAGE_MAP() + + ///////////////////////////////////////////////////////////////////////////// +// AccelEditor message handlers + +BOOL AccelEditor::OnInitDialog() +{ + CDialog::OnInitDialog(); + + DIALOG_SIZER_START( sz ) + DIALOG_SIZER_ENTRY( IDC_STATIC1, DS_MoveX) + DIALOG_SIZER_ENTRY( IDC_STATIC2, DS_MoveY) + DIALOG_SIZER_ENTRY( IDC_STATIC3, DS_MoveX | DS_MoveY) + DIALOG_SIZER_ENTRY( IDC_ALREADY_AFFECTED, DS_MoveY) + DIALOG_SIZER_ENTRY( ID_OK, DS_MoveX) + DIALOG_SIZER_ENTRY( ID_CANCEL, DS_MoveX) + DIALOG_SIZER_ENTRY( IDC_ASSIGN, DS_MoveX) + DIALOG_SIZER_ENTRY( IDC_REMOVE, DS_MoveX) + DIALOG_SIZER_ENTRY( IDC_RESET, DS_MoveX) + DIALOG_SIZER_ENTRY( IDC_CLOSE, DS_MoveY) + DIALOG_SIZER_ENTRY( IDC_COMMANDS, DS_SizeX | DS_SizeY) + DIALOG_SIZER_ENTRY( IDC_CURRENTS, DS_MoveX | DS_SizeY) + DIALOG_SIZER_ENTRY( IDC_EDIT_KEY, DS_MoveX | DS_MoveY) + DIALOG_SIZER_END() + + SetData(sz, + TRUE, + HKEY_CURRENT_USER, + "Software\\Emulators\\VisualBoyAdvance\\Viewer\\AccelEditor", + NULL); + + InitCommands(); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void AccelEditor::InitCommands() +{ + m_commands.ResetContent(); + m_alreadyAffected.SetWindowText(""); + + POSITION pos = mgr.m_mapAccelString.GetStartPosition(); + + while(pos != NULL) { + CString command; + WORD wID; + mgr.m_mapAccelString.GetNextAssoc(pos, command, wID); + + int index = m_commands.AddString(command); + m_commands.SetItemData(index, wID); + } + + // Update the currents accels associated with the selected command + if (m_commands.SetCurSel(0) != LB_ERR) + OnSelchangeCommands(); +} + +void AccelEditor::OnCancel() +{ + EndDialog(FALSE); +} + +void AccelEditor::OnOk() +{ + EndDialog(TRUE); +} + +void AccelEditor::OnSelchangeCommands() +{ + // Check if some commands exist. + int index = m_commands.GetCurSel(); + if (index == LB_ERR) + return; + + WORD wIDCommand = LOWORD(m_commands.GetItemData(index)); + m_currents.ResetContent(); + + CCmdAccelOb* pCmdAccel; + + if (mgr.m_mapAccelTable.Lookup(wIDCommand, pCmdAccel)) { + CAccelsOb* pAccel; + CString szBuffer; + POSITION pos = pCmdAccel->m_Accels.GetHeadPosition(); + + // Add the keys to the 'currents keys' listbox. + while (pos != NULL) { + pAccel = pCmdAccel->m_Accels.GetNext(pos); + pAccel->GetString(szBuffer); + index = m_currents.AddString(szBuffer); + // and a pointer to the accel object. + m_currents.SetItemData(index, (DWORD_PTR)pAccel); + } + } + // Init the key editor + // m_pKey->ResetKey(); + +} + +void AccelEditor::OnReset() +{ + mgr.Default(); + InitCommands(); // update the listboxes. +} + +void AccelEditor::OnAssign() +{ + // Control if it's not already affected + CCmdAccelOb* pCmdAccel; + CAccelsOb* pAccel; + WORD wIDCommand; + POSITION pos; + + WORD wKey; + bool bCtrl, bAlt, bShift; + + if (!m_key.GetAccelKey(wKey, bCtrl, bAlt, bShift)) + return; // no valid key, abort + + int count = m_commands.GetCount(); + int index; + for (index = 0; index < count; index++) { + + wIDCommand = LOWORD(m_commands.GetItemData(index)); + mgr.m_mapAccelTable.Lookup(wIDCommand, pCmdAccel); + + pos = pCmdAccel->m_Accels.GetHeadPosition(); + while (pos != NULL) { + pAccel = pCmdAccel->m_Accels.GetNext(pos); + if (pAccel->IsEqual(wKey, bCtrl, bAlt, bShift)) { + // the key is already affected (in the same or other command) + m_alreadyAffected.SetWindowText(pCmdAccel->m_szCommand); + m_key.SetSel(0, -1); + return; // abort + } + } + } + + // OK, we can add the accel key in the currently selected group + index = m_commands.GetCurSel(); + if (index == LB_ERR) + return; + + // Get the object who manage the accels list, associated to the command. + wIDCommand = LOWORD(m_commands.GetItemData(index)); + + if (mgr.m_mapAccelTable.Lookup(wIDCommand, pCmdAccel) != TRUE) + return; + + BYTE cVirt = 0; + if (bCtrl) + cVirt |= FCONTROL; + if (bAlt) + cVirt |= FALT; + if (bShift) + cVirt |= FSHIFT; + + cVirt |= FVIRTKEY; + + // Create the new key... + pAccel = new CAccelsOb(cVirt, wKey, false); + ASSERT(pAccel != NULL); + // ...and add in the list. + pCmdAccel->m_Accels.AddTail(pAccel); + + // Update the listbox. + CString szBuffer; + pAccel->GetString(szBuffer); + + index = m_currents.AddString(szBuffer); + m_currents.SetItemData(index, (DWORD_PTR)pAccel); + + // Reset the key editor. + m_key.ResetKey(); +} + +void AccelEditor::OnRemove() +{ + // Some controls + int indexCurrent = m_currents.GetCurSel(); + if (indexCurrent == LB_ERR) + return; + + // 2nd part. + int indexCmd = m_commands.GetCurSel(); + if (indexCmd == LB_ERR) + return; + + // Ref to the ID command + WORD wIDCommand = LOWORD(m_commands.GetItemData(indexCmd)); + + // Run through the accels,and control if it can be deleted. + CCmdAccelOb* pCmdAccel; + if (mgr.m_mapAccelTable.Lookup(wIDCommand, pCmdAccel) == TRUE) { + CAccelsOb* pAccel; + CAccelsOb* pAccelCurrent = (CAccelsOb*)(m_currents.GetItemData(indexCurrent)); + CString szBuffer; + POSITION pos = pCmdAccel->m_Accels.GetHeadPosition(); + POSITION PrevPos; + while (pos != NULL) { + PrevPos = pos; + pAccel = pCmdAccel->m_Accels.GetNext(pos); + if (pAccel == pAccelCurrent) { + if (!pAccel->m_bLocked) { + // not locked, so we delete the key + pCmdAccel->m_Accels.RemoveAt(PrevPos); + delete pAccel; + // and update the listboxes/key editor/static text + m_currents.DeleteString(indexCurrent); + m_key.ResetKey(); + m_alreadyAffected.SetWindowText(""); + return; + } else { + systemMessage(0,"Unable to remove this\naccelerator (Locked)"); + return; + } + } + } + systemMessage(0,"internal error (CAccelDlgHelper::Remove : pAccel unavailable)"); + return; + } + systemMessage(0,"internal error (CAccelDlgHelper::Remove : Lookup failed)"); +} diff --git a/src/win32/CmdAccelOb.cpp b/src/win32/CmdAccelOb.cpp index 5c5f7270..805425a0 100644 --- a/src/win32/CmdAccelOb.cpp +++ b/src/win32/CmdAccelOb.cpp @@ -1,527 +1,527 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998 by Thierry Maurel -// All rights reserved -// -// Distribute freely, except: don't remove my name from the source or -// documentation (don't take credit for my work), mark your changes (don't -// get me blamed for your possible bugs), don't alter or remove this -// notice. -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc., and -// I'll try to keep a version up to date. I can be reached as follows: -// tmaurel@caramail.com (or tmaurel@hol.fr) -// -//////////////////////////////////////////////////////////////////////////////// -// File : CmdAccelOb.cpp -// Project : AccelsEditor -//////////////////////////////////////////////////////////////////////////////// -// Version : 1.0 * Author : T.Maurel -// Date : 17.08.98 -// -// Remarks : -// -//////////////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#include "CmdAccelOb.h" - -//////////////////////////////////////////////////////////////////////// -// -// -MAPVIRTKEYS mapVirtKeys[] = { - {VK_LBUTTON, "VK_LBUTTON"}, - {VK_RBUTTON, "VK_RBUTTON"}, - {VK_CANCEL, "VK_CANCEL"}, - {VK_MBUTTON, "VK_MBUTTON"}, - {VK_BACK, "BACK"}, - {VK_TAB, "TAB"}, - {VK_CLEAR, "VK_CLEAR"}, - {VK_RETURN, "RETURN"}, - {VK_SHIFT, "SHIFT"}, - {VK_CONTROL, "CONTROL"}, - {VK_MENU, "MENU"}, - {VK_PAUSE, "PAUSE"}, - {VK_CAPITAL, "CAPITAL"}, - {VK_ESCAPE, "ESCAPE"}, - {VK_SPACE, "SPACE"}, - {VK_PRIOR, "PRIOR"}, - {VK_NEXT, "NEXT"}, - {VK_END, "END"}, - {VK_HOME, "HOME"}, - {VK_LEFT, "LEFT"}, - {VK_UP, "UP"}, - {VK_RIGHT, "RIGHT"}, - {VK_DOWN, "DOWN"}, - {VK_SELECT, "VK_SELECT"}, - {VK_PRINT, "PRINT"}, - {VK_EXECUTE, "EXECUTE"}, - {VK_SNAPSHOT, "SNAPSHOT"}, - {VK_INSERT, "INSERT"}, - {VK_DELETE, "DELETE"}, - {VK_HELP, "VK_HELP"}, - {WORD('0'), "0"}, - {WORD('1'), "1"}, - {WORD('2'), "2"}, - {WORD('3'), "3"}, - {WORD('4'), "4"}, - {WORD('5'), "5"}, - {WORD('6'), "6"}, - {WORD('7'), "7"}, - {WORD('8'), "8"}, - {WORD('9'), "9"}, - {WORD('A'), "A"}, - {WORD('B'), "B"}, - {WORD('C'), "C"}, - {WORD('D'), "D"}, - {WORD('E'), "E"}, - {WORD('F'), "F"}, - {WORD('G'), "G"}, - {WORD('H'), "H"}, - {WORD('I'), "I"}, - {WORD('J'), "J"}, - {WORD('K'), "K"}, - {WORD('L'), "L"}, - {WORD('M'), "M"}, - {WORD('N'), "N"}, - {WORD('O'), "O"}, - {WORD('P'), "P"}, - {WORD('Q'), "Q"}, - {WORD('R'), "R"}, - {WORD('S'), "S"}, - {WORD('T'), "T"}, - {WORD('U'), "U"}, - {WORD('V'), "V"}, - {WORD('W'), "W"}, - {WORD('X'), "X"}, - {WORD('Y'), "Y"}, - {WORD('Z'), "Z"}, - {VK_LWIN, "VK_LWIN"}, - {VK_RWIN, "VK_RWIN"}, - {VK_APPS, "VK_APPS"}, - {VK_NUMPAD0, "NUMPAD0"}, - {VK_NUMPAD1, "NUMPAD1"}, - {VK_NUMPAD2, "NUMPAD2"}, - {VK_NUMPAD3, "NUMPAD3"}, - {VK_NUMPAD4, "NUMPAD4"}, - {VK_NUMPAD5, "NUMPAD5"}, - {VK_NUMPAD6, "NUMPAD6"}, - {VK_NUMPAD7, "NUMPAD7"}, - {VK_NUMPAD8, "NUMPAD8"}, - {VK_NUMPAD9, "NUMPAD9"}, - {VK_MULTIPLY, "MULTIPLY"}, - {VK_ADD, "ADD"}, - {VK_SEPARATOR, "SEPARATOR"}, - {VK_SUBTRACT, "SUBTRACT"}, - {VK_DECIMAL, "DECIMAL"}, - {VK_DIVIDE, "DIVIDE"}, - {VK_F1, "F1"}, - {VK_F2, "F2"}, - {VK_F3, "F3"}, - {VK_F4, "F4"}, - {VK_F5, "F5"}, - {VK_F6, "F6"}, - {VK_F7, "F7"}, - {VK_F8, "F8"}, - {VK_F9, "F9"}, - {VK_F10, "F10"}, - {VK_F11, "F11"}, - {VK_F12, "F12"}, - {VK_F13, "F13"}, - {VK_F14, "F14"}, - {VK_F15, "F15"}, - {VK_F16, "F16"}, - {VK_F17, "F17"}, - {VK_F18, "F18"}, - {VK_F19, "F19"}, - {VK_F20, "F20"}, - {VK_F21, "F21"}, - {VK_F22, "F22"}, - {VK_F23, "F23"}, - {VK_F24, "F24"}, - {VK_NUMLOCK, "NUMLOCK"}, - {VK_SCROLL, "VK_SCROLL"}, - {VK_ATTN, "VK_ATTN"}, - {VK_CRSEL, "VK_CRSEL"}, - {VK_EXSEL, "VK_EXSEL"}, - {VK_EREOF, "VK_EREOF"}, - {VK_PLAY, "VK_PLAY"}, - {VK_ZOOM, "VK_ZOOM"}, - {VK_NONAME, "VK_NONAME"}, - {VK_PA1, "VK_PA1"}, - {VK_OEM_CLEAR, "VK_OEM_CLEAR"}, -}; - - -//////////////////////////////////////////////////////////////////////// -// -// -MAPVIRTKEYS mapVirtSysKeys[] = { - {FCONTROL, "Ctrl"}, - {FALT, "Alt"}, - {FSHIFT, "Shift"}, -}; - - -//////////////////////////////////////////////////////////////////////// -// helper fct for external access -//////////////////////////////////////////////////////////////////////// -// -// -TCHAR* mapVirtKeysStringFromWORD(WORD wKey) -{ - for (int index = 0; index < sizeof(mapVirtKeys)/sizeof(mapVirtKeys[0]); index++) { - if (mapVirtKeys[index].wKey == wKey) - return mapVirtKeys[index].szKey; - } - return NULL; -} - - - -//////////////////////////////////////////////////////////////////////// -// -#define DEFAULT_ACCEL 0x01 -#define USER_ACCEL 0x02 - - -//////////////////////////////////////////////////////////////////////// -// -//////////////////////////////////////////////////////////////////////// -// -// -CAccelsOb::CAccelsOb() -{ - m_cVirt = 0; - m_wKey = 0; - m_bLocked = false; -} - - -//////////////////////////////////////////////////////////////////////// -// -// -CAccelsOb::CAccelsOb(CAccelsOb* pFrom) -{ - ASSERT(pFrom != NULL); - - m_cVirt = pFrom->m_cVirt; - m_wKey = pFrom->m_wKey; - m_bLocked = pFrom->m_bLocked; -} - - -//////////////////////////////////////////////////////////////////////// -// -// -CAccelsOb::CAccelsOb(BYTE cVirt, WORD wKey, bool bLocked) -{ - m_cVirt = cVirt; - m_wKey = wKey; - m_bLocked = bLocked; -} - - -//////////////////////////////////////////////////////////////////////// -// -// -CAccelsOb::CAccelsOb(LPACCEL pACCEL) -{ - ASSERT(pACCEL != NULL); - - m_cVirt = pACCEL->fVirt; - m_wKey = pACCEL->key; - m_bLocked = false; -} - - -//////////////////////////////////////////////////////////////////////// -// -// -CAccelsOb& CAccelsOb::operator=(const CAccelsOb& from) -{ - m_cVirt = from.m_cVirt; - m_wKey = from.m_wKey; - m_bLocked = from.m_bLocked; - - return *this; -} - - -//////////////////////////////////////////////////////////////////////// -// -//////////////////////////////////////////////////////////////////////// -// -// -void CAccelsOb::GetString(CString& szBuffer) -{ - szBuffer = ""; - // in case of the object is not assigned, we avoid error messages - if (m_wKey == 0) - return; - - // modifiers part - int i; - for (i = 0; i < sizetable(mapVirtSysKeys); i++) { - if (m_cVirt & mapVirtSysKeys[i].wKey) { - szBuffer += mapVirtSysKeys[i].szKey; - szBuffer += "+"; - } - } - // and virtual key part - for (i = 0; i < sizetable(mapVirtKeys); i++) { - if (m_wKey == mapVirtKeys[i].wKey) { - szBuffer += mapVirtKeys[i].szKey; - return; - } - } - AfxMessageBox("Internal error : (CAccelsOb::GetString) m_wKey invalid"); -} - - -//////////////////////////////////////////////////////////////////////// -// -// -bool CAccelsOb::IsEqual(WORD wKey, bool bCtrl, bool bAlt, bool bShift) -{ - // CString szTemp; - // GetString(szTemp); - - - bool m_bCtrl = (m_cVirt & FCONTROL) ? true : false; - bool bRet = (bCtrl == m_bCtrl); - - bool m_bAlt = (m_cVirt & FALT) ? true : false; - bRet &= (bAlt == m_bAlt); - - bool m_bShift = (m_cVirt & FSHIFT) ? true : false; - bRet &= (bShift == m_bShift); - - bRet &= static_cast(m_wKey == wKey); - - return bRet; -} - - -//////////////////////////////////////////////////////////////////////// -// -// -DWORD CAccelsOb::GetData() -{ - BYTE cLocalCodes = 0; - if (m_bLocked) - cLocalCodes = DEFAULT_ACCEL; - else - cLocalCodes = USER_ACCEL; - - WORD bCodes = MAKEWORD(m_cVirt, cLocalCodes); - return MAKELONG(m_wKey, bCodes); -} - - -//////////////////////////////////////////////////////////////////////// -// -// -bool CAccelsOb::SetData(DWORD dwDatas) -{ - m_wKey = LOWORD(dwDatas); - - WORD bCodes = HIWORD(dwDatas); - m_cVirt = LOBYTE(bCodes); - - BYTE cLocalCodes = HIBYTE(bCodes); - m_bLocked = static_cast(cLocalCodes == DEFAULT_ACCEL); - return true; -} - -//////////////////////////////////////////////////////////////////////// -// -#ifdef _DEBUG -//////////////////////////////////////////////////////////////////////// -// -// -void CAccelsOb::AssertValid() const -{ - CObject::AssertValid(); -} - -//////////////////////////////////////////////////////////////////////// -// -// -void CAccelsOb::Dump(CDumpContext& dc) const -{ - dc << "\t\t"; - CObject::Dump(dc); - dc << "\t\tlocked=" << m_bLocked << ", cVirt=" << m_cVirt << ", wKey=" << m_wKey << "\n\n"; - -} -#endif - -//////////////////////////////////////////////////////////////////////// -// -//////////////////////////////////////////////////////////////////////// -// -// -CCmdAccelOb::CCmdAccelOb() -{ -} - - -//////////////////////////////////////////////////////////////////////// -// -// -CCmdAccelOb::CCmdAccelOb(WORD wIDCommand, LPCTSTR szCommand) -{ - ASSERT(szCommand != NULL); - - m_wIDCommand = wIDCommand; - m_szCommand = szCommand; -} - - -//////////////////////////////////////////////////////////////////////// -// -// -CCmdAccelOb::CCmdAccelOb(BYTE cVirt, WORD wIDCommand, WORD wKey, LPCTSTR szCommand, bool bLocked) -{ - ASSERT(szCommand != NULL); - - m_wIDCommand = wIDCommand; - m_szCommand = szCommand; - - CAccelsOb* pAccel = DEBUG_NEW CAccelsOb(cVirt, wKey, bLocked); - ASSERT(pAccel != NULL); - m_Accels.AddTail(pAccel); -} - - -//////////////////////////////////////////////////////////////////////// -// -// -CCmdAccelOb::~CCmdAccelOb() -{ - POSITION pos = m_Accels.GetHeadPosition(); - while (pos != NULL) - delete m_Accels.GetNext(pos); - m_Accels.RemoveAll(); -} - - -//////////////////////////////////////////////////////////////////////// -// -//////////////////////////////////////////////////////////////////////// -// -// -void CCmdAccelOb::Add(BYTE cVirt, WORD wKey, bool bLocked) -{ - CAccelsOb* pAccel = DEBUG_NEW CAccelsOb(cVirt, wKey, bLocked); - ASSERT(pAccel != NULL); - m_Accels.AddTail(pAccel); -} - - -//////////////////////////////////////////////////////////////////////// -// -// -void CCmdAccelOb::Add(CAccelsOb* pAccel) -{ - ASSERT(pAccel != NULL); - m_Accels.AddTail(pAccel); -} - - -//////////////////////////////////////////////////////////////////////// -// -// -CCmdAccelOb& CCmdAccelOb::operator=(const CCmdAccelOb& from) -{ - Reset(); - - m_wIDCommand = from.m_wIDCommand; - m_szCommand = from.m_szCommand; - - CAccelsOb* pAccel; - POSITION pos = from.m_Accels.GetHeadPosition(); - while (pos != NULL) { - pAccel = DEBUG_NEW CAccelsOb(from.m_Accels.GetNext(pos)); - ASSERT(pAccel != NULL); - m_Accels.AddTail(pAccel); - } - return *this; -} - - -//////////////////////////////////////////////////////////////////////// -// -// -void CCmdAccelOb::DeleteUserAccels() -{ - CAccelsOb* pAccel; - POSITION prevPos; - POSITION pos = m_Accels.GetHeadPosition(); - while (pos != NULL) { - prevPos = pos; - pAccel = m_Accels.GetNext(pos); - if (!pAccel->m_bLocked) { - delete pAccel; - m_Accels.RemoveAt(prevPos); - } - } -} - - -//////////////////////////////////////////////////////////////////////// -// -// -void CCmdAccelOb::Reset() -{ - m_wIDCommand = 0; - m_szCommand = "Empty command"; - - CAccelsOb* pAccel; - POSITION pos = m_Accels.GetHeadPosition(); - while (pos != NULL) { - pAccel = m_Accels.GetNext(pos); - delete pAccel; - } -} - -//////////////////////////////////////////////////////////////////////// -// -#ifdef _DEBUG -//////////////////////////////////////////////////////////////////////// -// -// -void CCmdAccelOb::AssertValid() const -{ - // call base class function first - CObject::AssertValid(); -} - - -//////////////////////////////////////////////////////////////////////// -// -// -void CCmdAccelOb::Dump( CDumpContext& dc ) const -{ - // call base class function first - dc << "\t"; - CObject::Dump( dc ); - - // now do the stuff for our specific class - dc << "\tIDCommand = " << m_wIDCommand; - dc << "\n\tszCommand = " << m_szCommand; - dc << "\n\tAccelerators = {\n"; - - CAccelsOb* pAccel; - POSITION pos = m_Accels.GetHeadPosition(); - while (pos != NULL) { - pAccel = m_Accels.GetNext(pos); - dc << pAccel; - } - dc << "\t}\n"; -} -#endif +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998 by Thierry Maurel +// All rights reserved +// +// Distribute freely, except: don't remove my name from the source or +// documentation (don't take credit for my work), mark your changes (don't +// get me blamed for your possible bugs), don't alter or remove this +// notice. +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc., and +// I'll try to keep a version up to date. I can be reached as follows: +// tmaurel@caramail.com (or tmaurel@hol.fr) +// +//////////////////////////////////////////////////////////////////////////////// +// File : CmdAccelOb.cpp +// Project : AccelsEditor +//////////////////////////////////////////////////////////////////////////////// +// Version : 1.0 * Author : T.Maurel +// Date : 17.08.98 +// +// Remarks : +// +//////////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "CmdAccelOb.h" + +//////////////////////////////////////////////////////////////////////// +// +// +MAPVIRTKEYS mapVirtKeys[] = { + {VK_LBUTTON, "VK_LBUTTON"}, + {VK_RBUTTON, "VK_RBUTTON"}, + {VK_CANCEL, "VK_CANCEL"}, + {VK_MBUTTON, "VK_MBUTTON"}, + {VK_BACK, "BACK"}, + {VK_TAB, "TAB"}, + {VK_CLEAR, "VK_CLEAR"}, + {VK_RETURN, "RETURN"}, + {VK_SHIFT, "SHIFT"}, + {VK_CONTROL, "CONTROL"}, + {VK_MENU, "MENU"}, + {VK_PAUSE, "PAUSE"}, + {VK_CAPITAL, "CAPITAL"}, + {VK_ESCAPE, "ESCAPE"}, + {VK_SPACE, "SPACE"}, + {VK_PRIOR, "PRIOR"}, + {VK_NEXT, "NEXT"}, + {VK_END, "END"}, + {VK_HOME, "HOME"}, + {VK_LEFT, "LEFT"}, + {VK_UP, "UP"}, + {VK_RIGHT, "RIGHT"}, + {VK_DOWN, "DOWN"}, + {VK_SELECT, "VK_SELECT"}, + {VK_PRINT, "PRINT"}, + {VK_EXECUTE, "EXECUTE"}, + {VK_SNAPSHOT, "SNAPSHOT"}, + {VK_INSERT, "INSERT"}, + {VK_DELETE, "DELETE"}, + {VK_HELP, "VK_HELP"}, + {WORD('0'), "0"}, + {WORD('1'), "1"}, + {WORD('2'), "2"}, + {WORD('3'), "3"}, + {WORD('4'), "4"}, + {WORD('5'), "5"}, + {WORD('6'), "6"}, + {WORD('7'), "7"}, + {WORD('8'), "8"}, + {WORD('9'), "9"}, + {WORD('A'), "A"}, + {WORD('B'), "B"}, + {WORD('C'), "C"}, + {WORD('D'), "D"}, + {WORD('E'), "E"}, + {WORD('F'), "F"}, + {WORD('G'), "G"}, + {WORD('H'), "H"}, + {WORD('I'), "I"}, + {WORD('J'), "J"}, + {WORD('K'), "K"}, + {WORD('L'), "L"}, + {WORD('M'), "M"}, + {WORD('N'), "N"}, + {WORD('O'), "O"}, + {WORD('P'), "P"}, + {WORD('Q'), "Q"}, + {WORD('R'), "R"}, + {WORD('S'), "S"}, + {WORD('T'), "T"}, + {WORD('U'), "U"}, + {WORD('V'), "V"}, + {WORD('W'), "W"}, + {WORD('X'), "X"}, + {WORD('Y'), "Y"}, + {WORD('Z'), "Z"}, + {VK_LWIN, "VK_LWIN"}, + {VK_RWIN, "VK_RWIN"}, + {VK_APPS, "VK_APPS"}, + {VK_NUMPAD0, "NUMPAD0"}, + {VK_NUMPAD1, "NUMPAD1"}, + {VK_NUMPAD2, "NUMPAD2"}, + {VK_NUMPAD3, "NUMPAD3"}, + {VK_NUMPAD4, "NUMPAD4"}, + {VK_NUMPAD5, "NUMPAD5"}, + {VK_NUMPAD6, "NUMPAD6"}, + {VK_NUMPAD7, "NUMPAD7"}, + {VK_NUMPAD8, "NUMPAD8"}, + {VK_NUMPAD9, "NUMPAD9"}, + {VK_MULTIPLY, "MULTIPLY"}, + {VK_ADD, "ADD"}, + {VK_SEPARATOR, "SEPARATOR"}, + {VK_SUBTRACT, "SUBTRACT"}, + {VK_DECIMAL, "DECIMAL"}, + {VK_DIVIDE, "DIVIDE"}, + {VK_F1, "F1"}, + {VK_F2, "F2"}, + {VK_F3, "F3"}, + {VK_F4, "F4"}, + {VK_F5, "F5"}, + {VK_F6, "F6"}, + {VK_F7, "F7"}, + {VK_F8, "F8"}, + {VK_F9, "F9"}, + {VK_F10, "F10"}, + {VK_F11, "F11"}, + {VK_F12, "F12"}, + {VK_F13, "F13"}, + {VK_F14, "F14"}, + {VK_F15, "F15"}, + {VK_F16, "F16"}, + {VK_F17, "F17"}, + {VK_F18, "F18"}, + {VK_F19, "F19"}, + {VK_F20, "F20"}, + {VK_F21, "F21"}, + {VK_F22, "F22"}, + {VK_F23, "F23"}, + {VK_F24, "F24"}, + {VK_NUMLOCK, "NUMLOCK"}, + {VK_SCROLL, "VK_SCROLL"}, + {VK_ATTN, "VK_ATTN"}, + {VK_CRSEL, "VK_CRSEL"}, + {VK_EXSEL, "VK_EXSEL"}, + {VK_EREOF, "VK_EREOF"}, + {VK_PLAY, "VK_PLAY"}, + {VK_ZOOM, "VK_ZOOM"}, + {VK_NONAME, "VK_NONAME"}, + {VK_PA1, "VK_PA1"}, + {VK_OEM_CLEAR, "VK_OEM_CLEAR"}, +}; + + +//////////////////////////////////////////////////////////////////////// +// +// +MAPVIRTKEYS mapVirtSysKeys[] = { + {FCONTROL, "Ctrl"}, + {FALT, "Alt"}, + {FSHIFT, "Shift"}, +}; + + +//////////////////////////////////////////////////////////////////////// +// helper fct for external access +//////////////////////////////////////////////////////////////////////// +// +// +TCHAR* mapVirtKeysStringFromWORD(WORD wKey) +{ + for (int index = 0; index < sizeof(mapVirtKeys)/sizeof(mapVirtKeys[0]); index++) { + if (mapVirtKeys[index].wKey == wKey) + return mapVirtKeys[index].szKey; + } + return NULL; +} + + + +//////////////////////////////////////////////////////////////////////// +// +#define DEFAULT_ACCEL 0x01 +#define USER_ACCEL 0x02 + + +//////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////// +// +// +CAccelsOb::CAccelsOb() +{ + m_cVirt = 0; + m_wKey = 0; + m_bLocked = false; +} + + +//////////////////////////////////////////////////////////////////////// +// +// +CAccelsOb::CAccelsOb(CAccelsOb* pFrom) +{ + ASSERT(pFrom != NULL); + + m_cVirt = pFrom->m_cVirt; + m_wKey = pFrom->m_wKey; + m_bLocked = pFrom->m_bLocked; +} + + +//////////////////////////////////////////////////////////////////////// +// +// +CAccelsOb::CAccelsOb(BYTE cVirt, WORD wKey, bool bLocked) +{ + m_cVirt = cVirt; + m_wKey = wKey; + m_bLocked = bLocked; +} + + +//////////////////////////////////////////////////////////////////////// +// +// +CAccelsOb::CAccelsOb(LPACCEL pACCEL) +{ + ASSERT(pACCEL != NULL); + + m_cVirt = pACCEL->fVirt; + m_wKey = pACCEL->key; + m_bLocked = false; +} + + +//////////////////////////////////////////////////////////////////////// +// +// +CAccelsOb& CAccelsOb::operator=(const CAccelsOb& from) +{ + m_cVirt = from.m_cVirt; + m_wKey = from.m_wKey; + m_bLocked = from.m_bLocked; + + return *this; +} + + +//////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////// +// +// +void CAccelsOb::GetString(CString& szBuffer) +{ + szBuffer = ""; + // in case of the object is not assigned, we avoid error messages + if (m_wKey == 0) + return; + + // modifiers part + int i; + for (i = 0; i < sizetable(mapVirtSysKeys); i++) { + if (m_cVirt & mapVirtSysKeys[i].wKey) { + szBuffer += mapVirtSysKeys[i].szKey; + szBuffer += "+"; + } + } + // and virtual key part + for (i = 0; i < sizetable(mapVirtKeys); i++) { + if (m_wKey == mapVirtKeys[i].wKey) { + szBuffer += mapVirtKeys[i].szKey; + return; + } + } + AfxMessageBox("Internal error : (CAccelsOb::GetString) m_wKey invalid"); +} + + +//////////////////////////////////////////////////////////////////////// +// +// +bool CAccelsOb::IsEqual(WORD wKey, bool bCtrl, bool bAlt, bool bShift) +{ + // CString szTemp; + // GetString(szTemp); + + + bool m_bCtrl = (m_cVirt & FCONTROL) ? true : false; + bool bRet = (bCtrl == m_bCtrl); + + bool m_bAlt = (m_cVirt & FALT) ? true : false; + bRet &= (bAlt == m_bAlt); + + bool m_bShift = (m_cVirt & FSHIFT) ? true : false; + bRet &= (bShift == m_bShift); + + bRet &= static_cast(m_wKey == wKey); + + return bRet; +} + + +//////////////////////////////////////////////////////////////////////// +// +// +DWORD CAccelsOb::GetData() +{ + BYTE cLocalCodes = 0; + if (m_bLocked) + cLocalCodes = DEFAULT_ACCEL; + else + cLocalCodes = USER_ACCEL; + + WORD bCodes = MAKEWORD(m_cVirt, cLocalCodes); + return MAKELONG(m_wKey, bCodes); +} + + +//////////////////////////////////////////////////////////////////////// +// +// +bool CAccelsOb::SetData(DWORD dwDatas) +{ + m_wKey = LOWORD(dwDatas); + + WORD bCodes = HIWORD(dwDatas); + m_cVirt = LOBYTE(bCodes); + + BYTE cLocalCodes = HIBYTE(bCodes); + m_bLocked = static_cast(cLocalCodes == DEFAULT_ACCEL); + return true; +} + +//////////////////////////////////////////////////////////////////////// +// +#ifdef _DEBUG +//////////////////////////////////////////////////////////////////////// +// +// +void CAccelsOb::AssertValid() const +{ + CObject::AssertValid(); +} + +//////////////////////////////////////////////////////////////////////// +// +// +void CAccelsOb::Dump(CDumpContext& dc) const +{ + dc << "\t\t"; + CObject::Dump(dc); + dc << "\t\tlocked=" << m_bLocked << ", cVirt=" << m_cVirt << ", wKey=" << m_wKey << "\n\n"; + +} +#endif + +//////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////// +// +// +CCmdAccelOb::CCmdAccelOb() +{ +} + + +//////////////////////////////////////////////////////////////////////// +// +// +CCmdAccelOb::CCmdAccelOb(WORD wIDCommand, LPCTSTR szCommand) +{ + ASSERT(szCommand != NULL); + + m_wIDCommand = wIDCommand; + m_szCommand = szCommand; +} + + +//////////////////////////////////////////////////////////////////////// +// +// +CCmdAccelOb::CCmdAccelOb(BYTE cVirt, WORD wIDCommand, WORD wKey, LPCTSTR szCommand, bool bLocked) +{ + ASSERT(szCommand != NULL); + + m_wIDCommand = wIDCommand; + m_szCommand = szCommand; + + CAccelsOb* pAccel = DEBUG_NEW CAccelsOb(cVirt, wKey, bLocked); + ASSERT(pAccel != NULL); + m_Accels.AddTail(pAccel); +} + + +//////////////////////////////////////////////////////////////////////// +// +// +CCmdAccelOb::~CCmdAccelOb() +{ + POSITION pos = m_Accels.GetHeadPosition(); + while (pos != NULL) + delete m_Accels.GetNext(pos); + m_Accels.RemoveAll(); +} + + +//////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////// +// +// +void CCmdAccelOb::Add(BYTE cVirt, WORD wKey, bool bLocked) +{ + CAccelsOb* pAccel = DEBUG_NEW CAccelsOb(cVirt, wKey, bLocked); + ASSERT(pAccel != NULL); + m_Accels.AddTail(pAccel); +} + + +//////////////////////////////////////////////////////////////////////// +// +// +void CCmdAccelOb::Add(CAccelsOb* pAccel) +{ + ASSERT(pAccel != NULL); + m_Accels.AddTail(pAccel); +} + + +//////////////////////////////////////////////////////////////////////// +// +// +CCmdAccelOb& CCmdAccelOb::operator=(const CCmdAccelOb& from) +{ + Reset(); + + m_wIDCommand = from.m_wIDCommand; + m_szCommand = from.m_szCommand; + + CAccelsOb* pAccel; + POSITION pos = from.m_Accels.GetHeadPosition(); + while (pos != NULL) { + pAccel = DEBUG_NEW CAccelsOb(from.m_Accels.GetNext(pos)); + ASSERT(pAccel != NULL); + m_Accels.AddTail(pAccel); + } + return *this; +} + + +//////////////////////////////////////////////////////////////////////// +// +// +void CCmdAccelOb::DeleteUserAccels() +{ + CAccelsOb* pAccel; + POSITION prevPos; + POSITION pos = m_Accels.GetHeadPosition(); + while (pos != NULL) { + prevPos = pos; + pAccel = m_Accels.GetNext(pos); + if (!pAccel->m_bLocked) { + delete pAccel; + m_Accels.RemoveAt(prevPos); + } + } +} + + +//////////////////////////////////////////////////////////////////////// +// +// +void CCmdAccelOb::Reset() +{ + m_wIDCommand = 0; + m_szCommand = "Empty command"; + + CAccelsOb* pAccel; + POSITION pos = m_Accels.GetHeadPosition(); + while (pos != NULL) { + pAccel = m_Accels.GetNext(pos); + delete pAccel; + } +} + +//////////////////////////////////////////////////////////////////////// +// +#ifdef _DEBUG +//////////////////////////////////////////////////////////////////////// +// +// +void CCmdAccelOb::AssertValid() const +{ + // call base class function first + CObject::AssertValid(); +} + + +//////////////////////////////////////////////////////////////////////// +// +// +void CCmdAccelOb::Dump( CDumpContext& dc ) const +{ + // call base class function first + dc << "\t"; + CObject::Dump( dc ); + + // now do the stuff for our specific class + dc << "\tIDCommand = " << m_wIDCommand; + dc << "\n\tszCommand = " << m_szCommand; + dc << "\n\tAccelerators = {\n"; + + CAccelsOb* pAccel; + POSITION pos = m_Accels.GetHeadPosition(); + while (pos != NULL) { + pAccel = m_Accels.GetNext(pos); + dc << pAccel; + } + dc << "\t}\n"; +} +#endif diff --git a/src/win32/Direct3D.cpp b/src/win32/Direct3D.cpp index 76ce8f48..38ec4896 100644 --- a/src/win32/Direct3D.cpp +++ b/src/win32/Direct3D.cpp @@ -1,902 +1,902 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team -// Copyright (C) 2005-2006 VBA development team -// Copyright (C) 2007-2008 VBA-M development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef NO_D3D - -#pragma comment( lib, "d3d9.lib" ) -#pragma comment( lib, "d3dx9.lib" ) -#pragma comment( lib, "dxerr9.lib" ) - -#include "stdafx.h" - -#include "Display.h" - -#include "MainWnd.h" -#include "FullscreenSettings.h" - -#include "../System.h" -#include "../agb/GBA.h" -#include "../Globals.h" -#include "../Util.h" -#include "../dmg/gbGlobals.h" - -#include - -// Direct3D -#ifdef _DEBUG -#define D3D_DEBUG_INFO -#endif -#define DIRECT3D_VERSION 0x0900 -#include // main include file -#include // required for font rendering -#include // contains debug functions - -extern int Init_2xSaI(u32); // initializes all pixel filters -extern int systemSpeed; - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -extern void log(const char *,...); -#endif - -#ifdef MMX -extern "C" bool cpu_mmx; -extern bool detectMMX(); -#endif - -class Direct3DDisplay : public IDisplay { -private: - bool initialized; - LPDIRECT3D9 pD3D; - LPDIRECT3DDEVICE9 pDevice; - D3DDISPLAYMODE mode; - D3DPRESENT_PARAMETERS dpp; - D3DFORMAT screenFormat; - LPDIRECT3DTEXTURE9 tempImage; - LPDIRECT3DTEXTURE9 emulatedImage[2]; - unsigned char mbCurrentTexture; // current texture for motion blur - bool mbTextureEmpty; - unsigned int width, height; - unsigned int textureSize; - RECT destRect; - bool failed; - ID3DXFont *pFont; - bool rectangleFillsScreen; - - struct VERTEX { - FLOAT x, y, z, rhw; // screen coordinates - FLOAT tx, ty; // texture coordinates - } Vertices[4]; - // Vertices order: - // 1 3 - // 0 2 - - struct TRANSP_VERTEX { - FLOAT x, y, z, rhw; - D3DCOLOR color; - FLOAT tx, ty; - } transpVertices[4]; - - void createFont(); - void destroyFont(); - bool clearTexture( LPDIRECT3DTEXTURE9 texture, size_t textureHeight ); - void createTexture( unsigned int textureWidth, unsigned int textureHeight ); - void destroyTexture(); - void calculateDestRect(); - bool resetDevice(); - void prepareDisplayMode(); - -public: - Direct3DDisplay(); - virtual ~Direct3DDisplay(); - virtual DISPLAY_TYPE getType() { return DIRECT_3D; }; - - virtual bool initialize(); - virtual void cleanup(); - virtual void clear(); - virtual void render(); - - virtual bool changeRenderSize( int w, int h ); - virtual void resize( int w, int h ); - virtual void setOption( const char *option, int value ); - virtual bool selectFullScreenMode( VIDEO_MODE &mode ); -}; - - -Direct3DDisplay::Direct3DDisplay() -{ - initialized = false; - pD3D = NULL; - pDevice = NULL; - screenFormat = D3DFMT_X8R8G8B8; - width = 0; - height = 0; - textureSize = 0; - failed = false; - pFont = NULL; - tempImage = NULL; - emulatedImage[0] = NULL; - emulatedImage[1] = NULL; - mbCurrentTexture = 0; - mbTextureEmpty = true; - rectangleFillsScreen = false; -} - - -Direct3DDisplay::~Direct3DDisplay() -{ - cleanup(); -} - -void Direct3DDisplay::prepareDisplayMode() -{ - // Change display mode - memset(&dpp, 0, sizeof(dpp)); - dpp.Windowed = !( theApp.videoOption >= VIDEO_320x240 ); - if( !dpp.Windowed ) { - dpp.BackBufferFormat = (theApp.fsColorDepth == 32) ? D3DFMT_X8R8G8B8 : D3DFMT_R5G6B5; - } else { - dpp.BackBufferFormat = mode.Format; - } - dpp.BackBufferCount = theApp.tripleBuffering ? 2 : 1; - dpp.MultiSampleType = D3DMULTISAMPLE_NONE; - dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; - dpp.BackBufferWidth = !dpp.Windowed ? theApp.fsWidth : theApp.surfaceSizeX; - dpp.BackBufferHeight = !dpp.Windowed ? theApp.fsHeight : theApp.surfaceSizeY; - dpp.hDeviceWindow = theApp.m_pMainWnd->GetSafeHwnd(); - dpp.FullScreen_RefreshRateInHz = ( dpp.Windowed == TRUE ) ? 0 : theApp.fsFrequency; - dpp.Flags = 0; - dpp.PresentationInterval = theApp.vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; - // D3DPRESENT_INTERVAL_ONE means VSync ON - - -#ifdef _DEBUG - // make debugging full screen easier - if( dpp.Windowed == FALSE ) { - dpp.Windowed = TRUE; - dpp.BackBufferFormat = D3DFMT_UNKNOWN; - dpp.BackBufferCount = 0; - dpp.FullScreen_RefreshRateInHz = 0; - dpp.Flags = 0; - } - - TRACE( _T("prepareDisplayMode:\n") ); - TRACE( _T("%i x %i @ %iHz:\n"), dpp.BackBufferWidth, dpp.BackBufferHeight, dpp.FullScreen_RefreshRateInHz ); - TRACE( _T("Buffer Count: %i\n"), dpp.BackBufferCount+1 ); - TRACE( _T("VSync: %i\n"), dpp.PresentationInterval==D3DPRESENT_INTERVAL_ONE ); - TRACE( _T("LOCKABLE_BACKBUFFER: %i\n\n"), dpp.Flags==D3DPRESENTFLAG_LOCKABLE_BACKBUFFER ); -#endif -} - - -void Direct3DDisplay::cleanup() -{ - destroyFont(); - destroyTexture(); - - if( pDevice ) { - pDevice->Release(); - pDevice = NULL; - } - - if( pD3D ) { - pD3D->Release(); - pD3D = NULL; - } -} - - -bool Direct3DDisplay::initialize() -{ -#ifdef _DEBUG - TRACE( _T("Initializing Direct3D renderer {\n") ); -#endif - - // load Direct3D v9 - pD3D = Direct3DCreate9( D3D_SDK_VERSION ); - - if(pD3D == NULL) { - DXTRACE_ERR_MSGBOX( _T("Error creating Direct3D object"), 0 ); - return false; - } - pD3D->GetAdapterDisplayMode(theApp.fsAdapter, &mode); - - theApp.mode320Available = FALSE; - theApp.mode640Available = FALSE; - theApp.mode800Available = FALSE; - theApp.mode1024Available = FALSE; - theApp.mode1280Available = FALSE; - - unsigned int nModes, i; - D3DDISPLAYMODE dm; - - nModes = pD3D->GetAdapterModeCount(theApp.fsAdapter, mode.Format); - for( i = 0; iEnumAdapterModes(theApp.fsAdapter, mode.Format, i, &dm) ) - { - if( (dm.Width == 320) && (dm.Height == 240) ) - theApp.mode320Available = true; - if( (dm.Width == 640) && (dm.Height == 480) ) - theApp.mode640Available = true; - if( (dm.Width == 800) && (dm.Height == 600) ) - theApp.mode800Available = true; - if( (dm.Width == 1024) && (dm.Height == 768) ) - theApp.mode1024Available = true; - if( (dm.Width == 1280) && (dm.Height == 1024) ) - theApp.mode1280Available = true; - } - } - - - screenFormat = mode.Format; - - switch(mode.Format) { - case D3DFMT_A2R10G10B10: - systemColorDepth = 32; - systemRedShift = 25; - systemGreenShift = 15; - systemBlueShift = 5; - Init_2xSaI(32); // TODO: verify - break; - case D3DFMT_X8R8G8B8: - systemColorDepth = 32; - systemRedShift = 19; - systemGreenShift = 11; - systemBlueShift = 3; - Init_2xSaI(32); - break; - case D3DFMT_R5G6B5: - systemColorDepth = 16; - systemRedShift = 11; - systemGreenShift = 6; - systemBlueShift = 0; - Init_2xSaI(565); - break; - case D3DFMT_X1R5G5B5: - systemColorDepth = 16; - systemRedShift = 10; - systemGreenShift = 5; - systemBlueShift = 0; - Init_2xSaI(555); - break; - default: - DXTRACE_ERR_MSGBOX( _T("Unsupport D3D format"), 0 ); - return false; - } - theApp.fsColorDepth = systemColorDepth; - utilUpdateSystemColorMaps(); - - -#ifdef MMX - if(!theApp.disableMMX) { - cpu_mmx = theApp.detectMMX(); - } else { - cpu_mmx = 0; - } -#endif - - - theApp.updateFilter(); - theApp.updateIFB(); - - - // create device - // Direct3D will use the selected full screen adapter for windowed mode as well - prepareDisplayMode(); - - HRESULT hret = pD3D->CreateDevice( - theApp.fsAdapter, - D3DDEVTYPE_HAL, - theApp.m_pMainWnd->GetSafeHwnd(), - D3DCREATE_FPU_PRESERVE | - D3DCREATE_SOFTWARE_VERTEXPROCESSING, - &dpp, - &pDevice); - if( FAILED( hret ) ) { - DXTRACE_ERR_MSGBOX( _T("Error creating Direct3D device"), hret ); - return false; - } - - createFont(); - // width and height will be set from a prior call to changeRenderSize() before initialize() - createTexture( width, height ); - calculateDestRect(); - setOption( _T("d3dFilter"), theApp.d3dFilter ); - setOption( _T("motionBlur"), theApp.d3dMotionBlur ); - - if(failed) return false; - - initialized = true; - -#ifdef _DEBUG - TRACE( _T("} Finished Direct3D renderer initialization\n\n") ); -#endif - - return TRUE; -} - - -void Direct3DDisplay::clear() -{ - if( pDevice ) { -#ifdef _DEBUG - pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0xFF,0x00,0xFF), 0.0f, 0 ); -#else - pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0x00,0x00,0x00), 0.0f, 0 ); -#endif - } -} - - -void Direct3DDisplay::render() -{ - if( failed ) return; - if(!pDevice) return; - - // Multi-Tasking fix - HRESULT hr = pDevice->TestCooperativeLevel(); - if( FAILED( hr ) ) { - switch( hr ) { - case D3DERR_DEVICELOST: - // The device has been lost but cannot be reset at this time. - // Therefore, rendering is not possible. - return; - case D3DERR_DEVICENOTRESET: - // The device has been lost but can be reset at this time. - resetDevice(); - return; - default: - DXTRACE_ERR( _T("ERROR: D3D device has serious problems"), hr ); - return; - } - } - - if( !rectangleFillsScreen ) { - // performance: clear only when you must - clear(); - } - - pDevice->BeginScene(); - - // copy pix to tempImage and apply pixel filter if selected - D3DLOCKED_RECT lr; - const RECT target = { 0, 0, width, height }; - - if( FAILED( hr = tempImage->LockRect( 0, &lr, &target, 0 ) ) ) { - DXTRACE_ERR_MSGBOX( _T("Can not lock texture"), hr ); - return; - } else { - unsigned short pitch = theApp.sizeX * ( systemColorDepth >> 3 ) + 4; - if( theApp.filterFunction ) { - // pixel filter enabled - theApp.filterFunction( - pix + pitch, - pitch, - (u8*)theApp.delta, - (u8*)lr.pBits, - lr.Pitch, - theApp.sizeX, - theApp.sizeY - ); - } else { - // pixel filter disabled - switch( systemColorDepth ) - { - case 32: - cpyImg32( - (unsigned char *)lr.pBits, - lr.Pitch, - pix + pitch, - pitch, - theApp.sizeX, - theApp.sizeY - ); - break; - case 16: - cpyImg16( - (unsigned char *)lr.pBits, - lr.Pitch, - pix + pitch, - pitch, - theApp.sizeX, - theApp.sizeY - ); - break; - } - } - tempImage->UnlockRect( 0 ); - pDevice->UpdateTexture( tempImage, emulatedImage[ mbCurrentTexture ] ); - } - - - if( !theApp.d3dMotionBlur ) { - // draw the current frame to the screen - pDevice->SetTexture( 0, emulatedImage[ mbCurrentTexture ] ); - pDevice->SetFVF( D3DFVF_XYZRHW | D3DFVF_TEX1 ); - pDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, Vertices, sizeof(VERTEX) ); - } else { - // Motion Blur enabled - if( !mbTextureEmpty ) { - // draw previous frame to the screen - pDevice->SetTexture( 0, emulatedImage[ mbCurrentTexture ^ 1 ] ); - pDevice->SetFVF( D3DFVF_XYZRHW | D3DFVF_TEX1 ); - pDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, Vertices, sizeof(VERTEX) ); - // draw the current frame with transparency to the screen - pDevice->SetTexture( 0, emulatedImage[ mbCurrentTexture ] ); - pDevice->SetFVF( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 ); - pDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, transpVertices, sizeof(TRANSP_VERTEX) ); - } else { - mbTextureEmpty = false; - // draw the current frame to the screen - pDevice->SetTexture( 0, emulatedImage[ mbCurrentTexture ] ); - pDevice->SetFVF( D3DFVF_XYZRHW | D3DFVF_TEX1 ); - pDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, Vertices, sizeof(VERTEX) ); - } - mbCurrentTexture ^= 1; // switch current texture - } - - - // render speed and status messages - D3DCOLOR color; - RECT r; - r.left = 0; - r.top = 0; - r.right = dpp.BackBufferWidth - 1; - r.bottom = dpp.BackBufferHeight - 1; - - if( theApp.showSpeed && ( theApp.videoOption > VIDEO_4X ) ) { - color = theApp.showSpeedTransparent ? D3DCOLOR_ARGB(0x7F, 0x00, 0x00, 0xFF) : D3DCOLOR_ARGB(0xFF, 0x00, 0x00, 0xFF); - char buffer[30]; - if( theApp.showSpeed == 1 ) { - sprintf( buffer, "%3d%%", systemSpeed ); - } else { - sprintf( buffer, "%3d%%(%d, %d fps)", systemSpeed, systemFrameSkip, theApp.showRenderedFrames ); - } - - pFont->DrawText( NULL, buffer, -1, &r, DT_CENTER | DT_TOP, color ); - } - - if( theApp.screenMessage ) { - color = theApp.showSpeedTransparent ? D3DCOLOR_ARGB(0x7F, 0xFF, 0x00, 0x00) : D3DCOLOR_ARGB(0xFF, 0xFF, 0x00, 0x00); - if( ( ( GetTickCount() - theApp.screenMessageTime ) < 3000 ) && !theApp.disableStatusMessage && pFont ) { - pFont->DrawText( NULL, theApp.screenMessageBuffer, -1, &r, DT_CENTER | DT_BOTTOM, color ); - } else { - theApp.screenMessage = false; - } - } - - pDevice->EndScene(); - - pDevice->Present( NULL, NULL, NULL, NULL ); - - return; -} - - -bool Direct3DDisplay::changeRenderSize( int w, int h ) -{ - if( (w != width) || (h != height) ) { - width = (unsigned int)w; - height = (unsigned int)h; - if( pDevice ) { - destroyTexture(); - createTexture( width, height ); - calculateDestRect(); - } - } - return true; -} - - -void Direct3DDisplay::resize( int w, int h ) -{ - if( !initialized ) { - return; - } - - if( (w != dpp.BackBufferWidth) || - (h != dpp.BackBufferHeight) || - (theApp.videoOption > VIDEO_4X) ) { - resetDevice(); - calculateDestRect(); - } -} - - -bool Direct3DDisplay::selectFullScreenMode( VIDEO_MODE &mode ) -{ - FullscreenSettings dlg; - dlg.setAPI( this->getType() ); - INT_PTR ret = dlg.DoModal(); - if( ret == IDOK ) { - mode.adapter = dlg.m_device; - switch( dlg.m_colorDepth ) - { - case 30: - // TODO: support - return false; - break; - case 24: - mode.bitDepth = 32; - break; - case 16: - case 15: - mode.bitDepth = 16; - break; - } - mode.width = dlg.m_width; - mode.height = dlg.m_height; - mode.frequency = dlg.m_refreshRate; - return true; - } else { - return false; - } -} - - -void Direct3DDisplay::createFont() -{ - if( !pFont ) { - HRESULT hr = D3DXCreateFont( - pDevice, - dpp.BackBufferHeight/20, // dynamic font size - 0, - FW_BOLD, - 1, - FALSE, - DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, - DEFAULT_QUALITY, - DEFAULT_PITCH || FF_DONTCARE, - _T("Arial"), - &pFont ); - if( FAILED( hr ) ) { - DXTRACE_ERR_MSGBOX( _T("createFont failed"), hr ); - } - } -} - - -void Direct3DDisplay::destroyFont() -{ - if( pFont ) { - pFont->Release(); - pFont = NULL; - } -} - - -// fill texture completely with black -bool Direct3DDisplay::clearTexture( LPDIRECT3DTEXTURE9 texture, size_t textureHeight ) -{ - D3DLOCKED_RECT lr; - HRESULT hr; - - if( FAILED( hr = texture->LockRect( 0, &lr, NULL, 0 ) ) ) { - DXTRACE_ERR_MSGBOX( _T("Can not lock texture"), hr ); - return false; - } else { - memset( lr.pBits, 0x00, lr.Pitch * textureHeight ); - texture->UnlockRect( 0 ); - return true; - } -} - - -// when either textureWidth or textureHeight is 0, last texture size will be used -void Direct3DDisplay::createTexture( unsigned int textureWidth, unsigned int textureHeight ) -{ - if( ( textureWidth != 0 ) && ( textureWidth != 0 ) ) { - // calculate next possible square texture size - textureSize = 1; - unsigned int reqSizeMin = ( textureWidth > textureHeight ) ? textureWidth : textureHeight; - while( textureSize < reqSizeMin ) { - textureSize <<= 1; // multiply by 2 - } - } else { - // do not recalculate texture size - - if( textureSize == 0 ) { - DXTRACE_MSG( _T("Error: createTexture: textureSize == 0") ); - return; - } - } - - - if( !tempImage ) { - HRESULT hr = pDevice->CreateTexture( - textureSize, textureSize, - 1, // 1 level, no mipmaps - 0, // dynamic textures can be locked - dpp.BackBufferFormat, - D3DPOOL_SYSTEMMEM, - &tempImage, - NULL ); - - if( FAILED( hr ) ) { - DXTRACE_ERR_MSGBOX( _T("createTexture(temp) failed"), hr ); - return; - } - - // initialize whole texture with black since we might see - // the initial noise when using bilinear texture filtering - clearTexture( tempImage, textureSize ); - } - - - if( !emulatedImage[0] ) { - HRESULT hr = pDevice->CreateTexture( - textureSize, textureSize, - 1, // 1 level, no mipmaps - 0, - dpp.BackBufferFormat, - D3DPOOL_DEFAULT, - &emulatedImage[0], - NULL ); - - if( FAILED( hr ) ) { - DXTRACE_ERR_MSGBOX( _T("createTexture(0) failed"), hr ); - return; - } - } - - if( !emulatedImage[1] && theApp.d3dMotionBlur ) { - HRESULT hr = pDevice->CreateTexture( - textureSize, textureSize, - 1, - 0, - dpp.BackBufferFormat, - D3DPOOL_DEFAULT, - &emulatedImage[1], - NULL ); - - if( FAILED( hr ) ) { - DXTRACE_ERR_MSGBOX( _T("createTexture(1) failed"), hr ); - return; - } - - mbTextureEmpty = true; - } -} - - -void Direct3DDisplay::destroyTexture() -{ - if( tempImage ) { - tempImage->Release(); - tempImage = NULL; - } - - if( emulatedImage[0] ) { - emulatedImage[0]->Release(); - emulatedImage[0] = NULL; - } - - if( emulatedImage[1] ) { - emulatedImage[1]->Release(); - emulatedImage[1] = NULL; - } -} - - -void Direct3DDisplay::calculateDestRect() -{ - if( theApp.fullScreenStretch ) { - rectangleFillsScreen = true; // no clear() necessary - destRect.left = 0; - destRect.top = 0; - destRect.right = dpp.BackBufferWidth; // for some reason there'l be a black - destRect.bottom = dpp.BackBufferHeight; // border line when using -1 at the end - } else { - // use aspect ratio - float scaleX = (float)dpp.BackBufferWidth / (float)width; - float scaleY = (float)dpp.BackBufferHeight / (float)height; - float min = (scaleX < scaleY) ? scaleX : scaleY; - if( theApp.fsMaxScale && (min > theApp.fsMaxScale) ) { - min = (float)theApp.fsMaxScale; - } - destRect.left = 0; - destRect.top = 0; - destRect.right = (LONG)(width * min); - destRect.bottom = (LONG)(height * min); - if( destRect.right != dpp.BackBufferWidth ) { - LONG diff = (dpp.BackBufferWidth - destRect.right) / 2; - destRect.left += diff; - destRect.right += diff; - } - if( destRect.bottom != dpp.BackBufferHeight ) { - LONG diff = (dpp.BackBufferHeight - destRect.bottom) / 2; - destRect.top += diff; - destRect.bottom += diff; - } - - if( ( destRect.left == 0 ) && - ( destRect.top == 0 ) && - ( destRect.right == dpp.BackBufferWidth ) && - ( destRect.bottom == dpp.BackBufferHeight ) ) { - rectangleFillsScreen = true; - } else { - rectangleFillsScreen = false; - } - } - - FLOAT textureX = (FLOAT)width / (FLOAT)textureSize; - FLOAT textureY = (FLOAT)height / (FLOAT)textureSize; - - // configure triangles - Vertices[0].x = (FLOAT)destRect.left - 0.5f; - // -0.5f is necessary in order to match texture alignment to display pixels - Vertices[0].y = (FLOAT)destRect.bottom - 0.5f; - Vertices[0].z = 0.0f; - Vertices[0].rhw = 1.0f; - Vertices[0].tx = 0.0f; - Vertices[0].ty = textureY; - Vertices[1].x = (FLOAT)destRect.left - 0.5f; - Vertices[1].y = (FLOAT)destRect.top - 0.5f; - Vertices[1].z = 0.0f; - Vertices[1].rhw = 1.0f; - Vertices[1].tx = 0.0f; - Vertices[1].ty = 0.0f; - Vertices[2].x = (FLOAT)destRect.right - 0.5f; - Vertices[2].y = (FLOAT)destRect.bottom - 0.5f; - Vertices[2].z = 0.0f; - Vertices[2].rhw = 1.0f; - Vertices[2].tx = textureX; - Vertices[2].ty = textureY; - Vertices[3].x = (FLOAT)destRect.right - 0.5f; - Vertices[3].y = (FLOAT)destRect.top - 0.5f; - Vertices[3].z = 0.0f; - Vertices[3].rhw = 1.0f; - Vertices[3].tx = textureX; - Vertices[3].ty = 0.0f; - - if( theApp.d3dMotionBlur ) { - // configure semi-transparent triangles - D3DCOLOR semiTrans = D3DCOLOR_ARGB( 0x7F, 0xFF, 0xFF, 0xFF ); - transpVertices[0].x = Vertices[0].x; - transpVertices[0].y = Vertices[0].y; - transpVertices[0].z = Vertices[0].z; - transpVertices[0].rhw = Vertices[0].rhw; - transpVertices[0].color = semiTrans; - transpVertices[0].tx = Vertices[0].tx; - transpVertices[0].ty = Vertices[0].ty; - transpVertices[1].x = Vertices[1].x; - transpVertices[1].y = Vertices[1].y; - transpVertices[1].z = Vertices[1].z; - transpVertices[1].rhw = Vertices[1].rhw; - transpVertices[1].color = semiTrans; - transpVertices[1].tx = Vertices[1].tx; - transpVertices[1].ty = Vertices[1].ty; - transpVertices[2].x = Vertices[2].x; - transpVertices[2].y = Vertices[2].y; - transpVertices[2].z = Vertices[2].z; - transpVertices[2].rhw = Vertices[2].rhw; - transpVertices[2].color = semiTrans; - transpVertices[2].tx = Vertices[2].tx; - transpVertices[2].ty = Vertices[2].ty; - transpVertices[3].x = Vertices[3].x; - transpVertices[3].y = Vertices[3].y; - transpVertices[3].z = Vertices[3].z; - transpVertices[3].rhw = Vertices[3].rhw; - transpVertices[3].color = semiTrans; - transpVertices[3].tx = Vertices[3].tx; - transpVertices[3].ty = Vertices[3].ty; - } -} - - -void Direct3DDisplay::setOption( const char *option, int value ) -{ - if( !_tcscmp( option, _T("vsync") ) ) { - // value of theApp.vsync has already been changed by the menu handler - // 'value' has the same value as theApp.vsync - resetDevice(); - } - - if( !_tcscmp( option, _T("tripleBuffering") ) ) { - // value of theApp.tripleBuffering has already been changed by the menu handler - // 'value' has the same value as theApp.tripleBuffering - resetDevice(); - } - - if( !_tcscmp( option, _T("d3dFilter") ) ) { - switch( value ) - { - case 0: //point - pDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT ); - pDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT ); - break; - case 1: //linear - pDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); - pDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); - break; - } - } - - if( !_tcscmp( option, _T("maxScale") ) ) { - calculateDestRect(); - } - - if( !_tcscmp( option, _T("fullScreenStretch") ) ) { - calculateDestRect(); - } - - if( !_tcscmp( option, _T("motionBlur") ) ) { - switch( value ) - { - case 0: - mbCurrentTexture = 0; - pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); - break; - case 1: - // enable vertex alpha blending - pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); - pDevice->SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1 ); - pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); - pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); - // apply vertex alpha values to texture - pDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); - calculateDestRect(); - createTexture( 0, 0 ); // create the second texture - break; - } - } -} - - -bool Direct3DDisplay::resetDevice() -{ - if( !pDevice ) return false; - - HRESULT hr; - if( pFont ) { - // prepares font for reset - pFont->OnLostDevice(); - } - destroyTexture(); - prepareDisplayMode(); - - if( FAILED( hr = pDevice->Reset( &dpp ) ) ) { - DXTRACE_ERR( _T("pDevice->Reset failed\n"), hr ); - failed = true; - return false; - } - - if( pFont ) { - // re-aquires font resources - pFont->OnResetDevice(); - } - createTexture( 0, 0 ); - setOption( _T("d3dFilter"), theApp.d3dFilter ); - setOption( _T("motionBlur"), theApp.d3dMotionBlur ); - failed = false; - return true; -} - - -IDisplay *newDirect3DDisplay() -{ - return new Direct3DDisplay(); -} - -#endif +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team +// Copyright (C) 2005-2006 VBA development team +// Copyright (C) 2007-2008 VBA-M development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef NO_D3D + +#pragma comment( lib, "d3d9.lib" ) +#pragma comment( lib, "d3dx9.lib" ) +#pragma comment( lib, "dxerr9.lib" ) + +#include "stdafx.h" + +#include "Display.h" + +#include "MainWnd.h" +#include "FullscreenSettings.h" + +#include "../System.h" +#include "../agb/GBA.h" +#include "../Globals.h" +#include "../Util.h" +#include "../dmg/gbGlobals.h" + +#include + +// Direct3D +#ifdef _DEBUG +#define D3D_DEBUG_INFO +#endif +#define DIRECT3D_VERSION 0x0900 +#include // main include file +#include // required for font rendering +#include // contains debug functions + +extern int Init_2xSaI(u32); // initializes all pixel filters +extern int systemSpeed; + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +extern void log(const char *,...); +#endif + +#ifdef MMX +extern "C" bool cpu_mmx; +extern bool detectMMX(); +#endif + +class Direct3DDisplay : public IDisplay { +private: + bool initialized; + LPDIRECT3D9 pD3D; + LPDIRECT3DDEVICE9 pDevice; + D3DDISPLAYMODE mode; + D3DPRESENT_PARAMETERS dpp; + D3DFORMAT screenFormat; + LPDIRECT3DTEXTURE9 tempImage; + LPDIRECT3DTEXTURE9 emulatedImage[2]; + unsigned char mbCurrentTexture; // current texture for motion blur + bool mbTextureEmpty; + unsigned int width, height; + unsigned int textureSize; + RECT destRect; + bool failed; + ID3DXFont *pFont; + bool rectangleFillsScreen; + + struct VERTEX { + FLOAT x, y, z, rhw; // screen coordinates + FLOAT tx, ty; // texture coordinates + } Vertices[4]; + // Vertices order: + // 1 3 + // 0 2 + + struct TRANSP_VERTEX { + FLOAT x, y, z, rhw; + D3DCOLOR color; + FLOAT tx, ty; + } transpVertices[4]; + + void createFont(); + void destroyFont(); + bool clearTexture( LPDIRECT3DTEXTURE9 texture, size_t textureHeight ); + void createTexture( unsigned int textureWidth, unsigned int textureHeight ); + void destroyTexture(); + void calculateDestRect(); + bool resetDevice(); + void prepareDisplayMode(); + +public: + Direct3DDisplay(); + virtual ~Direct3DDisplay(); + virtual DISPLAY_TYPE getType() { return DIRECT_3D; }; + + virtual bool initialize(); + virtual void cleanup(); + virtual void clear(); + virtual void render(); + + virtual bool changeRenderSize( int w, int h ); + virtual void resize( int w, int h ); + virtual void setOption( const char *option, int value ); + virtual bool selectFullScreenMode( VIDEO_MODE &mode ); +}; + + +Direct3DDisplay::Direct3DDisplay() +{ + initialized = false; + pD3D = NULL; + pDevice = NULL; + screenFormat = D3DFMT_X8R8G8B8; + width = 0; + height = 0; + textureSize = 0; + failed = false; + pFont = NULL; + tempImage = NULL; + emulatedImage[0] = NULL; + emulatedImage[1] = NULL; + mbCurrentTexture = 0; + mbTextureEmpty = true; + rectangleFillsScreen = false; +} + + +Direct3DDisplay::~Direct3DDisplay() +{ + cleanup(); +} + +void Direct3DDisplay::prepareDisplayMode() +{ + // Change display mode + memset(&dpp, 0, sizeof(dpp)); + dpp.Windowed = !( theApp.videoOption >= VIDEO_320x240 ); + if( !dpp.Windowed ) { + dpp.BackBufferFormat = (theApp.fsColorDepth == 32) ? D3DFMT_X8R8G8B8 : D3DFMT_R5G6B5; + } else { + dpp.BackBufferFormat = mode.Format; + } + dpp.BackBufferCount = theApp.tripleBuffering ? 2 : 1; + dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + dpp.BackBufferWidth = !dpp.Windowed ? theApp.fsWidth : theApp.surfaceSizeX; + dpp.BackBufferHeight = !dpp.Windowed ? theApp.fsHeight : theApp.surfaceSizeY; + dpp.hDeviceWindow = theApp.m_pMainWnd->GetSafeHwnd(); + dpp.FullScreen_RefreshRateInHz = ( dpp.Windowed == TRUE ) ? 0 : theApp.fsFrequency; + dpp.Flags = 0; + dpp.PresentationInterval = theApp.vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; + // D3DPRESENT_INTERVAL_ONE means VSync ON + + +#ifdef _DEBUG + // make debugging full screen easier + if( dpp.Windowed == FALSE ) { + dpp.Windowed = TRUE; + dpp.BackBufferFormat = D3DFMT_UNKNOWN; + dpp.BackBufferCount = 0; + dpp.FullScreen_RefreshRateInHz = 0; + dpp.Flags = 0; + } + + TRACE( _T("prepareDisplayMode:\n") ); + TRACE( _T("%i x %i @ %iHz:\n"), dpp.BackBufferWidth, dpp.BackBufferHeight, dpp.FullScreen_RefreshRateInHz ); + TRACE( _T("Buffer Count: %i\n"), dpp.BackBufferCount+1 ); + TRACE( _T("VSync: %i\n"), dpp.PresentationInterval==D3DPRESENT_INTERVAL_ONE ); + TRACE( _T("LOCKABLE_BACKBUFFER: %i\n\n"), dpp.Flags==D3DPRESENTFLAG_LOCKABLE_BACKBUFFER ); +#endif +} + + +void Direct3DDisplay::cleanup() +{ + destroyFont(); + destroyTexture(); + + if( pDevice ) { + pDevice->Release(); + pDevice = NULL; + } + + if( pD3D ) { + pD3D->Release(); + pD3D = NULL; + } +} + + +bool Direct3DDisplay::initialize() +{ +#ifdef _DEBUG + TRACE( _T("Initializing Direct3D renderer {\n") ); +#endif + + // load Direct3D v9 + pD3D = Direct3DCreate9( D3D_SDK_VERSION ); + + if(pD3D == NULL) { + DXTRACE_ERR_MSGBOX( _T("Error creating Direct3D object"), 0 ); + return false; + } + pD3D->GetAdapterDisplayMode(theApp.fsAdapter, &mode); + + theApp.mode320Available = FALSE; + theApp.mode640Available = FALSE; + theApp.mode800Available = FALSE; + theApp.mode1024Available = FALSE; + theApp.mode1280Available = FALSE; + + unsigned int nModes, i; + D3DDISPLAYMODE dm; + + nModes = pD3D->GetAdapterModeCount(theApp.fsAdapter, mode.Format); + for( i = 0; iEnumAdapterModes(theApp.fsAdapter, mode.Format, i, &dm) ) + { + if( (dm.Width == 320) && (dm.Height == 240) ) + theApp.mode320Available = true; + if( (dm.Width == 640) && (dm.Height == 480) ) + theApp.mode640Available = true; + if( (dm.Width == 800) && (dm.Height == 600) ) + theApp.mode800Available = true; + if( (dm.Width == 1024) && (dm.Height == 768) ) + theApp.mode1024Available = true; + if( (dm.Width == 1280) && (dm.Height == 1024) ) + theApp.mode1280Available = true; + } + } + + + screenFormat = mode.Format; + + switch(mode.Format) { + case D3DFMT_A2R10G10B10: + systemColorDepth = 32; + systemRedShift = 25; + systemGreenShift = 15; + systemBlueShift = 5; + Init_2xSaI(32); // TODO: verify + break; + case D3DFMT_X8R8G8B8: + systemColorDepth = 32; + systemRedShift = 19; + systemGreenShift = 11; + systemBlueShift = 3; + Init_2xSaI(32); + break; + case D3DFMT_R5G6B5: + systemColorDepth = 16; + systemRedShift = 11; + systemGreenShift = 6; + systemBlueShift = 0; + Init_2xSaI(565); + break; + case D3DFMT_X1R5G5B5: + systemColorDepth = 16; + systemRedShift = 10; + systemGreenShift = 5; + systemBlueShift = 0; + Init_2xSaI(555); + break; + default: + DXTRACE_ERR_MSGBOX( _T("Unsupport D3D format"), 0 ); + return false; + } + theApp.fsColorDepth = systemColorDepth; + utilUpdateSystemColorMaps(); + + +#ifdef MMX + if(!theApp.disableMMX) { + cpu_mmx = theApp.detectMMX(); + } else { + cpu_mmx = 0; + } +#endif + + + theApp.updateFilter(); + theApp.updateIFB(); + + + // create device + // Direct3D will use the selected full screen adapter for windowed mode as well + prepareDisplayMode(); + + HRESULT hret = pD3D->CreateDevice( + theApp.fsAdapter, + D3DDEVTYPE_HAL, + theApp.m_pMainWnd->GetSafeHwnd(), + D3DCREATE_FPU_PRESERVE | + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &dpp, + &pDevice); + if( FAILED( hret ) ) { + DXTRACE_ERR_MSGBOX( _T("Error creating Direct3D device"), hret ); + return false; + } + + createFont(); + // width and height will be set from a prior call to changeRenderSize() before initialize() + createTexture( width, height ); + calculateDestRect(); + setOption( _T("d3dFilter"), theApp.d3dFilter ); + setOption( _T("motionBlur"), theApp.d3dMotionBlur ); + + if(failed) return false; + + initialized = true; + +#ifdef _DEBUG + TRACE( _T("} Finished Direct3D renderer initialization\n\n") ); +#endif + + return TRUE; +} + + +void Direct3DDisplay::clear() +{ + if( pDevice ) { +#ifdef _DEBUG + pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0xFF,0x00,0xFF), 0.0f, 0 ); +#else + pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0x00,0x00,0x00), 0.0f, 0 ); +#endif + } +} + + +void Direct3DDisplay::render() +{ + if( failed ) return; + if(!pDevice) return; + + // Multi-Tasking fix + HRESULT hr = pDevice->TestCooperativeLevel(); + if( FAILED( hr ) ) { + switch( hr ) { + case D3DERR_DEVICELOST: + // The device has been lost but cannot be reset at this time. + // Therefore, rendering is not possible. + return; + case D3DERR_DEVICENOTRESET: + // The device has been lost but can be reset at this time. + resetDevice(); + return; + default: + DXTRACE_ERR( _T("ERROR: D3D device has serious problems"), hr ); + return; + } + } + + if( !rectangleFillsScreen ) { + // performance: clear only when you must + clear(); + } + + pDevice->BeginScene(); + + // copy pix to tempImage and apply pixel filter if selected + D3DLOCKED_RECT lr; + const RECT target = { 0, 0, width, height }; + + if( FAILED( hr = tempImage->LockRect( 0, &lr, &target, 0 ) ) ) { + DXTRACE_ERR_MSGBOX( _T("Can not lock texture"), hr ); + return; + } else { + unsigned short pitch = theApp.sizeX * ( systemColorDepth >> 3 ) + 4; + if( theApp.filterFunction ) { + // pixel filter enabled + theApp.filterFunction( + pix + pitch, + pitch, + (u8*)theApp.delta, + (u8*)lr.pBits, + lr.Pitch, + theApp.sizeX, + theApp.sizeY + ); + } else { + // pixel filter disabled + switch( systemColorDepth ) + { + case 32: + cpyImg32( + (unsigned char *)lr.pBits, + lr.Pitch, + pix + pitch, + pitch, + theApp.sizeX, + theApp.sizeY + ); + break; + case 16: + cpyImg16( + (unsigned char *)lr.pBits, + lr.Pitch, + pix + pitch, + pitch, + theApp.sizeX, + theApp.sizeY + ); + break; + } + } + tempImage->UnlockRect( 0 ); + pDevice->UpdateTexture( tempImage, emulatedImage[ mbCurrentTexture ] ); + } + + + if( !theApp.d3dMotionBlur ) { + // draw the current frame to the screen + pDevice->SetTexture( 0, emulatedImage[ mbCurrentTexture ] ); + pDevice->SetFVF( D3DFVF_XYZRHW | D3DFVF_TEX1 ); + pDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, Vertices, sizeof(VERTEX) ); + } else { + // Motion Blur enabled + if( !mbTextureEmpty ) { + // draw previous frame to the screen + pDevice->SetTexture( 0, emulatedImage[ mbCurrentTexture ^ 1 ] ); + pDevice->SetFVF( D3DFVF_XYZRHW | D3DFVF_TEX1 ); + pDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, Vertices, sizeof(VERTEX) ); + // draw the current frame with transparency to the screen + pDevice->SetTexture( 0, emulatedImage[ mbCurrentTexture ] ); + pDevice->SetFVF( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 ); + pDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, transpVertices, sizeof(TRANSP_VERTEX) ); + } else { + mbTextureEmpty = false; + // draw the current frame to the screen + pDevice->SetTexture( 0, emulatedImage[ mbCurrentTexture ] ); + pDevice->SetFVF( D3DFVF_XYZRHW | D3DFVF_TEX1 ); + pDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, Vertices, sizeof(VERTEX) ); + } + mbCurrentTexture ^= 1; // switch current texture + } + + + // render speed and status messages + D3DCOLOR color; + RECT r; + r.left = 0; + r.top = 0; + r.right = dpp.BackBufferWidth - 1; + r.bottom = dpp.BackBufferHeight - 1; + + if( theApp.showSpeed && ( theApp.videoOption > VIDEO_4X ) ) { + color = theApp.showSpeedTransparent ? D3DCOLOR_ARGB(0x7F, 0x00, 0x00, 0xFF) : D3DCOLOR_ARGB(0xFF, 0x00, 0x00, 0xFF); + char buffer[30]; + if( theApp.showSpeed == 1 ) { + sprintf( buffer, "%3d%%", systemSpeed ); + } else { + sprintf( buffer, "%3d%%(%d, %d fps)", systemSpeed, systemFrameSkip, theApp.showRenderedFrames ); + } + + pFont->DrawText( NULL, buffer, -1, &r, DT_CENTER | DT_TOP, color ); + } + + if( theApp.screenMessage ) { + color = theApp.showSpeedTransparent ? D3DCOLOR_ARGB(0x7F, 0xFF, 0x00, 0x00) : D3DCOLOR_ARGB(0xFF, 0xFF, 0x00, 0x00); + if( ( ( GetTickCount() - theApp.screenMessageTime ) < 3000 ) && !theApp.disableStatusMessage && pFont ) { + pFont->DrawText( NULL, theApp.screenMessageBuffer, -1, &r, DT_CENTER | DT_BOTTOM, color ); + } else { + theApp.screenMessage = false; + } + } + + pDevice->EndScene(); + + pDevice->Present( NULL, NULL, NULL, NULL ); + + return; +} + + +bool Direct3DDisplay::changeRenderSize( int w, int h ) +{ + if( (w != width) || (h != height) ) { + width = (unsigned int)w; + height = (unsigned int)h; + if( pDevice ) { + destroyTexture(); + createTexture( width, height ); + calculateDestRect(); + } + } + return true; +} + + +void Direct3DDisplay::resize( int w, int h ) +{ + if( !initialized ) { + return; + } + + if( (w != dpp.BackBufferWidth) || + (h != dpp.BackBufferHeight) || + (theApp.videoOption > VIDEO_4X) ) { + resetDevice(); + calculateDestRect(); + } +} + + +bool Direct3DDisplay::selectFullScreenMode( VIDEO_MODE &mode ) +{ + FullscreenSettings dlg; + dlg.setAPI( this->getType() ); + INT_PTR ret = dlg.DoModal(); + if( ret == IDOK ) { + mode.adapter = dlg.m_device; + switch( dlg.m_colorDepth ) + { + case 30: + // TODO: support + return false; + break; + case 24: + mode.bitDepth = 32; + break; + case 16: + case 15: + mode.bitDepth = 16; + break; + } + mode.width = dlg.m_width; + mode.height = dlg.m_height; + mode.frequency = dlg.m_refreshRate; + return true; + } else { + return false; + } +} + + +void Direct3DDisplay::createFont() +{ + if( !pFont ) { + HRESULT hr = D3DXCreateFont( + pDevice, + dpp.BackBufferHeight/20, // dynamic font size + 0, + FW_BOLD, + 1, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + DEFAULT_QUALITY, + DEFAULT_PITCH || FF_DONTCARE, + _T("Arial"), + &pFont ); + if( FAILED( hr ) ) { + DXTRACE_ERR_MSGBOX( _T("createFont failed"), hr ); + } + } +} + + +void Direct3DDisplay::destroyFont() +{ + if( pFont ) { + pFont->Release(); + pFont = NULL; + } +} + + +// fill texture completely with black +bool Direct3DDisplay::clearTexture( LPDIRECT3DTEXTURE9 texture, size_t textureHeight ) +{ + D3DLOCKED_RECT lr; + HRESULT hr; + + if( FAILED( hr = texture->LockRect( 0, &lr, NULL, 0 ) ) ) { + DXTRACE_ERR_MSGBOX( _T("Can not lock texture"), hr ); + return false; + } else { + memset( lr.pBits, 0x00, lr.Pitch * textureHeight ); + texture->UnlockRect( 0 ); + return true; + } +} + + +// when either textureWidth or textureHeight is 0, last texture size will be used +void Direct3DDisplay::createTexture( unsigned int textureWidth, unsigned int textureHeight ) +{ + if( ( textureWidth != 0 ) && ( textureWidth != 0 ) ) { + // calculate next possible square texture size + textureSize = 1; + unsigned int reqSizeMin = ( textureWidth > textureHeight ) ? textureWidth : textureHeight; + while( textureSize < reqSizeMin ) { + textureSize <<= 1; // multiply by 2 + } + } else { + // do not recalculate texture size + + if( textureSize == 0 ) { + DXTRACE_MSG( _T("Error: createTexture: textureSize == 0") ); + return; + } + } + + + if( !tempImage ) { + HRESULT hr = pDevice->CreateTexture( + textureSize, textureSize, + 1, // 1 level, no mipmaps + 0, // dynamic textures can be locked + dpp.BackBufferFormat, + D3DPOOL_SYSTEMMEM, + &tempImage, + NULL ); + + if( FAILED( hr ) ) { + DXTRACE_ERR_MSGBOX( _T("createTexture(temp) failed"), hr ); + return; + } + + // initialize whole texture with black since we might see + // the initial noise when using bilinear texture filtering + clearTexture( tempImage, textureSize ); + } + + + if( !emulatedImage[0] ) { + HRESULT hr = pDevice->CreateTexture( + textureSize, textureSize, + 1, // 1 level, no mipmaps + 0, + dpp.BackBufferFormat, + D3DPOOL_DEFAULT, + &emulatedImage[0], + NULL ); + + if( FAILED( hr ) ) { + DXTRACE_ERR_MSGBOX( _T("createTexture(0) failed"), hr ); + return; + } + } + + if( !emulatedImage[1] && theApp.d3dMotionBlur ) { + HRESULT hr = pDevice->CreateTexture( + textureSize, textureSize, + 1, + 0, + dpp.BackBufferFormat, + D3DPOOL_DEFAULT, + &emulatedImage[1], + NULL ); + + if( FAILED( hr ) ) { + DXTRACE_ERR_MSGBOX( _T("createTexture(1) failed"), hr ); + return; + } + + mbTextureEmpty = true; + } +} + + +void Direct3DDisplay::destroyTexture() +{ + if( tempImage ) { + tempImage->Release(); + tempImage = NULL; + } + + if( emulatedImage[0] ) { + emulatedImage[0]->Release(); + emulatedImage[0] = NULL; + } + + if( emulatedImage[1] ) { + emulatedImage[1]->Release(); + emulatedImage[1] = NULL; + } +} + + +void Direct3DDisplay::calculateDestRect() +{ + if( theApp.fullScreenStretch ) { + rectangleFillsScreen = true; // no clear() necessary + destRect.left = 0; + destRect.top = 0; + destRect.right = dpp.BackBufferWidth; // for some reason there'l be a black + destRect.bottom = dpp.BackBufferHeight; // border line when using -1 at the end + } else { + // use aspect ratio + float scaleX = (float)dpp.BackBufferWidth / (float)width; + float scaleY = (float)dpp.BackBufferHeight / (float)height; + float min = (scaleX < scaleY) ? scaleX : scaleY; + if( theApp.fsMaxScale && (min > theApp.fsMaxScale) ) { + min = (float)theApp.fsMaxScale; + } + destRect.left = 0; + destRect.top = 0; + destRect.right = (LONG)(width * min); + destRect.bottom = (LONG)(height * min); + if( destRect.right != dpp.BackBufferWidth ) { + LONG diff = (dpp.BackBufferWidth - destRect.right) / 2; + destRect.left += diff; + destRect.right += diff; + } + if( destRect.bottom != dpp.BackBufferHeight ) { + LONG diff = (dpp.BackBufferHeight - destRect.bottom) / 2; + destRect.top += diff; + destRect.bottom += diff; + } + + if( ( destRect.left == 0 ) && + ( destRect.top == 0 ) && + ( destRect.right == dpp.BackBufferWidth ) && + ( destRect.bottom == dpp.BackBufferHeight ) ) { + rectangleFillsScreen = true; + } else { + rectangleFillsScreen = false; + } + } + + FLOAT textureX = (FLOAT)width / (FLOAT)textureSize; + FLOAT textureY = (FLOAT)height / (FLOAT)textureSize; + + // configure triangles + Vertices[0].x = (FLOAT)destRect.left - 0.5f; + // -0.5f is necessary in order to match texture alignment to display pixels + Vertices[0].y = (FLOAT)destRect.bottom - 0.5f; + Vertices[0].z = 0.0f; + Vertices[0].rhw = 1.0f; + Vertices[0].tx = 0.0f; + Vertices[0].ty = textureY; + Vertices[1].x = (FLOAT)destRect.left - 0.5f; + Vertices[1].y = (FLOAT)destRect.top - 0.5f; + Vertices[1].z = 0.0f; + Vertices[1].rhw = 1.0f; + Vertices[1].tx = 0.0f; + Vertices[1].ty = 0.0f; + Vertices[2].x = (FLOAT)destRect.right - 0.5f; + Vertices[2].y = (FLOAT)destRect.bottom - 0.5f; + Vertices[2].z = 0.0f; + Vertices[2].rhw = 1.0f; + Vertices[2].tx = textureX; + Vertices[2].ty = textureY; + Vertices[3].x = (FLOAT)destRect.right - 0.5f; + Vertices[3].y = (FLOAT)destRect.top - 0.5f; + Vertices[3].z = 0.0f; + Vertices[3].rhw = 1.0f; + Vertices[3].tx = textureX; + Vertices[3].ty = 0.0f; + + if( theApp.d3dMotionBlur ) { + // configure semi-transparent triangles + D3DCOLOR semiTrans = D3DCOLOR_ARGB( 0x7F, 0xFF, 0xFF, 0xFF ); + transpVertices[0].x = Vertices[0].x; + transpVertices[0].y = Vertices[0].y; + transpVertices[0].z = Vertices[0].z; + transpVertices[0].rhw = Vertices[0].rhw; + transpVertices[0].color = semiTrans; + transpVertices[0].tx = Vertices[0].tx; + transpVertices[0].ty = Vertices[0].ty; + transpVertices[1].x = Vertices[1].x; + transpVertices[1].y = Vertices[1].y; + transpVertices[1].z = Vertices[1].z; + transpVertices[1].rhw = Vertices[1].rhw; + transpVertices[1].color = semiTrans; + transpVertices[1].tx = Vertices[1].tx; + transpVertices[1].ty = Vertices[1].ty; + transpVertices[2].x = Vertices[2].x; + transpVertices[2].y = Vertices[2].y; + transpVertices[2].z = Vertices[2].z; + transpVertices[2].rhw = Vertices[2].rhw; + transpVertices[2].color = semiTrans; + transpVertices[2].tx = Vertices[2].tx; + transpVertices[2].ty = Vertices[2].ty; + transpVertices[3].x = Vertices[3].x; + transpVertices[3].y = Vertices[3].y; + transpVertices[3].z = Vertices[3].z; + transpVertices[3].rhw = Vertices[3].rhw; + transpVertices[3].color = semiTrans; + transpVertices[3].tx = Vertices[3].tx; + transpVertices[3].ty = Vertices[3].ty; + } +} + + +void Direct3DDisplay::setOption( const char *option, int value ) +{ + if( !_tcscmp( option, _T("vsync") ) ) { + // value of theApp.vsync has already been changed by the menu handler + // 'value' has the same value as theApp.vsync + resetDevice(); + } + + if( !_tcscmp( option, _T("tripleBuffering") ) ) { + // value of theApp.tripleBuffering has already been changed by the menu handler + // 'value' has the same value as theApp.tripleBuffering + resetDevice(); + } + + if( !_tcscmp( option, _T("d3dFilter") ) ) { + switch( value ) + { + case 0: //point + pDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT ); + pDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT ); + break; + case 1: //linear + pDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); + pDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); + break; + } + } + + if( !_tcscmp( option, _T("maxScale") ) ) { + calculateDestRect(); + } + + if( !_tcscmp( option, _T("fullScreenStretch") ) ) { + calculateDestRect(); + } + + if( !_tcscmp( option, _T("motionBlur") ) ) { + switch( value ) + { + case 0: + mbCurrentTexture = 0; + pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); + break; + case 1: + // enable vertex alpha blending + pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); + pDevice->SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1 ); + pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); + pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); + // apply vertex alpha values to texture + pDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + calculateDestRect(); + createTexture( 0, 0 ); // create the second texture + break; + } + } +} + + +bool Direct3DDisplay::resetDevice() +{ + if( !pDevice ) return false; + + HRESULT hr; + if( pFont ) { + // prepares font for reset + pFont->OnLostDevice(); + } + destroyTexture(); + prepareDisplayMode(); + + if( FAILED( hr = pDevice->Reset( &dpp ) ) ) { + DXTRACE_ERR( _T("pDevice->Reset failed\n"), hr ); + failed = true; + return false; + } + + if( pFont ) { + // re-aquires font resources + pFont->OnResetDevice(); + } + createTexture( 0, 0 ); + setOption( _T("d3dFilter"), theApp.d3dFilter ); + setOption( _T("motionBlur"), theApp.d3dMotionBlur ); + failed = false; + return true; +} + + +IDisplay *newDirect3DDisplay() +{ + return new Direct3DDisplay(); +} + +#endif diff --git a/src/win32/MainWnd.cpp b/src/win32/MainWnd.cpp index 26ab402d..0c8548d7 100644 --- a/src/win32/MainWnd.cpp +++ b/src/win32/MainWnd.cpp @@ -1,1307 +1,1307 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005-2006 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -// MainWnd.cpp : implementation file -// - -#include "stdafx.h" -#include "VBA.h" -#include "MainWnd.h" - -#include -#include - -#include "FileDlg.h" -#include "Reg.h" -#include "WinResUtil.h" -#include "Logging.h" - -#include "../System.h" -#include "../AutoBuild.h" -#include "../cheatSearch.h" -#include "../agb/GBA.h" -#include "../Globals.h" -#include "../Flash.h" -#include "../Globals.h" -#include "../dmg/GB.h" -#include "../dmg/gbCheats.h" -#include "../dmg/gbGlobals.h" -#include "../RTC.h" -#include "../Sound.h" -#include "../Util.h" -#include "../agb/GBALink.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -extern void remoteCleanUp(); -extern int gbHardware; - -///////////////////////////////////////////////////////////////////////////// -// MainWnd - -MainWnd::MainWnd() -{ - m_hAccelTable = NULL; - arrow = LoadCursor(NULL, IDC_ARROW); -} - -MainWnd::~MainWnd() -{ -} - - -BEGIN_MESSAGE_MAP(MainWnd, CWnd) - //{{AFX_MSG_MAP(MainWnd) - ON_WM_CLOSE() - ON_COMMAND(ID_HELP_ABOUT, OnHelpAbout) - ON_COMMAND(ID_HELP_FAQ, OnHelpFaq) - ON_COMMAND(ID_FILE_OPEN, OnFileOpen) - ON_WM_INITMENUPOPUP() - ON_COMMAND(ID_FILE_PAUSE, OnFilePause) - ON_UPDATE_COMMAND_UI(ID_FILE_PAUSE, OnUpdateFilePause) - ON_COMMAND(ID_FILE_RESET, OnFileReset) - ON_UPDATE_COMMAND_UI(ID_FILE_RESET, OnUpdateFileReset) - ON_UPDATE_COMMAND_UI(ID_FILE_RECENT_FREEZE, OnUpdateFileRecentFreeze) - ON_COMMAND(ID_FILE_RECENT_RESET, OnFileRecentReset) - ON_COMMAND(ID_FILE_RECENT_FREEZE, OnFileRecentFreeze) - ON_COMMAND(ID_FILE_EXIT, OnFileExit) - ON_COMMAND(ID_FILE_CLOSE, OnFileClose) - ON_UPDATE_COMMAND_UI(ID_FILE_CLOSE, OnUpdateFileClose) - ON_COMMAND(ID_FILE_OPENGAMEBOY, OnFileOpengameboy) - ON_COMMAND(ID_FILE_LOAD, OnFileLoad) - ON_UPDATE_COMMAND_UI(ID_FILE_LOAD, OnUpdateFileLoad) - ON_COMMAND(ID_FILE_SAVE, OnFileSave) - ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave) - ON_COMMAND(ID_FILE_IMPORT_BATTERYFILE, OnFileImportBatteryfile) - ON_UPDATE_COMMAND_UI(ID_FILE_IMPORT_BATTERYFILE, OnUpdateFileImportBatteryfile) - ON_COMMAND(ID_FILE_IMPORT_GAMESHARKCODEFILE, OnFileImportGamesharkcodefile) - ON_UPDATE_COMMAND_UI(ID_FILE_IMPORT_GAMESHARKCODEFILE, OnUpdateFileImportGamesharkcodefile) - ON_COMMAND(ID_FILE_IMPORT_GAMESHARKSNAPSHOT, OnFileImportGamesharksnapshot) - ON_UPDATE_COMMAND_UI(ID_FILE_IMPORT_GAMESHARKSNAPSHOT, OnUpdateFileImportGamesharksnapshot) - ON_COMMAND(ID_FILE_EXPORT_BATTERYFILE, OnFileExportBatteryfile) - ON_UPDATE_COMMAND_UI(ID_FILE_EXPORT_BATTERYFILE, OnUpdateFileExportBatteryfile) - ON_COMMAND(ID_FILE_EXPORT_GAMESHARKSNAPSHOT, OnFileExportGamesharksnapshot) - ON_UPDATE_COMMAND_UI(ID_FILE_EXPORT_GAMESHARKSNAPSHOT, OnUpdateFileExportGamesharksnapshot) - ON_COMMAND(ID_FILE_SCREENCAPTURE, OnFileScreencapture) - ON_UPDATE_COMMAND_UI(ID_FILE_SCREENCAPTURE, OnUpdateFileScreencapture) - ON_COMMAND(ID_FILE_ROMINFORMATION, OnFileRominformation) - ON_UPDATE_COMMAND_UI(ID_FILE_ROMINFORMATION, OnUpdateFileRominformation) - ON_COMMAND(ID_FILE_TOGGLEMENU, OnFileTogglemenu) - ON_UPDATE_COMMAND_UI(ID_FILE_TOGGLEMENU, OnUpdateFileTogglemenu) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_NOTHROTTLE, OnUpdateOptionsFrameskipThrottleNothrottle) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_25, OnUpdateOptionsFrameskipThrottle25) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_50, OnUpdateOptionsFrameskipThrottle50) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_100, OnUpdateOptionsFrameskipThrottle100) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_150, OnUpdateOptionsFrameskipThrottle150) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_200, OnUpdateOptionsFrameskipThrottle200) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_OTHER, OnUpdateOptionsFrameskipThrottleOther) - ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_NOTHROTTLE, OnOptionsFrameskipThrottleNothrottle) - ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_25, OnOptionsFrameskipThrottle25) - ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_50, OnOptionsFrameskipThrottle50) - ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_100, OnOptionsFrameskipThrottle100) - ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_150, OnOptionsFrameskipThrottle150) - ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_200, OnOptionsFrameskipThrottle200) - ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_OTHER, OnOptionsFrameskipThrottleOther) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_0, OnUpdateOptionsVideoFrameskip0) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_1, OnUpdateOptionsVideoFrameskip1) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_2, OnUpdateOptionsVideoFrameskip2) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_3, OnUpdateOptionsVideoFrameskip3) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_4, OnUpdateOptionsVideoFrameskip4) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_5, OnUpdateOptionsVideoFrameskip5) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_6, OnUpdateOptionsVideoFrameskip6) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_7, OnUpdateOptionsVideoFrameskip7) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_8, OnUpdateOptionsVideoFrameskip8) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_9, OnUpdateOptionsVideoFrameskip9) - ON_COMMAND(ID_OPTIONS_VIDEO_VSYNC, OnOptionsVideoVsync) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_VSYNC, OnUpdateOptionsVideoVsync) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_X1, OnUpdateOptionsVideoX1) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_X2, OnUpdateOptionsVideoX2) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_X3, OnUpdateOptionsVideoX3) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_X4, OnUpdateOptionsVideoX4) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREEN320X240, OnUpdateOptionsVideoFullscreen320x240) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREEN640X480, OnUpdateOptionsVideoFullscreen640x480) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREEN800X600, OnUpdateOptionsVideoFullscreen800x600) - ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREEN320X240, OnOptionsVideoFullscreen320x240) - ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREEN640X480, OnOptionsVideoFullscreen640x480) - ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREEN800X600, OnOptionsVideoFullscreen800x600) - ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREEN, OnOptionsVideoFullscreen) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREEN, OnUpdateOptionsVideoFullscreen) - ON_WM_MOVING() - ON_WM_MOVE() - ON_WM_SIZING() - ON_WM_SIZE() - ON_COMMAND(ID_OPTIONS_VIDEO_DISABLESFX, OnOptionsVideoDisablesfx) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_DISABLESFX, OnUpdateOptionsVideoDisablesfx) - ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREENSTRETCHTOFIT, OnOptionsVideoFullscreenstretchtofit) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREENSTRETCHTOFIT, OnUpdateOptionsVideoFullscreenstretchtofit) - ON_COMMAND(ID_OPTIONS_VIDEO_RENDERMETHOD_DIRECT3D, OnOptionsVideoRendermethodDirect3d) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDERMETHOD_DIRECT3D, OnUpdateOptionsVideoRendermethodDirect3d) - ON_COMMAND(ID_OPTIONS_VIDEO_RENDERMETHOD_OPENGL, OnOptionsVideoRendermethodOpengl) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDERMETHOD_OPENGL, OnUpdateOptionsVideoRendermethodOpengl) - ON_COMMAND(ID_OPTIONS_VIDEO_TRIPLEBUFFERING, OnOptionsVideoTriplebuffering) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_TRIPLEBUFFERING, OnUpdateOptionsVideoTriplebuffering) - ON_COMMAND(ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DNOFILTER, OnOptionsVideoRenderoptionsD3dnofilter) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DNOFILTER, OnUpdateOptionsVideoRenderoptionsD3dnofilter) - ON_COMMAND(ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DBILINEAR, OnOptionsVideoRenderoptionsD3dbilinear) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DBILINEAR, OnUpdateOptionsVideoRenderoptionsD3dbilinear) - ON_COMMAND(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLNEAREST, OnOptionsVideoRenderoptionsGlnearest) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLNEAREST, OnUpdateOptionsVideoRenderoptionsGlnearest) - ON_COMMAND(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLBILINEAR, OnOptionsVideoRenderoptionsGlbilinear) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLBILINEAR, OnUpdateOptionsVideoRenderoptionsGlbilinear) - - ON_WM_CONTEXTMENU() - ON_COMMAND(ID_OPTIONS_EMULATOR_ASSOCIATE, OnOptionsEmulatorAssociate) - ON_COMMAND(ID_OPTIONS_EMULATOR_DIRECTORIES, OnOptionsEmulatorDirectories) - ON_COMMAND(ID_OPTIONS_EMULATOR_DISABLESTATUSMESSAGES, OnOptionsEmulatorDisablestatusmessages) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_DISABLESTATUSMESSAGES, OnUpdateOptionsEmulatorDisablestatusmessages) - ON_COMMAND(ID_OPTIONS_EMULATOR_SYNCHRONIZE, OnOptionsEmulatorSynchronize) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SYNCHRONIZE, OnUpdateOptionsEmulatorSynchronize) - ON_COMMAND(ID_OPTIONS_EMULATOR_PAUSEWHENINACTIVE, OnOptionsEmulatorPausewheninactive) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_PAUSEWHENINACTIVE, OnUpdateOptionsEmulatorPausewheninactive) - ON_COMMAND(ID_OPTIONS_EMULATOR_SPEEDUPTOGGLE, OnOptionsEmulatorSpeeduptoggle) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SPEEDUPTOGGLE, OnUpdateOptionsEmulatorSpeeduptoggle) - ON_COMMAND(ID_OPTIONS_EMULATOR_AUTOMATICALLYIPSPATCH, OnOptionsEmulatorAutomaticallyipspatch) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_AUTOMATICALLYIPSPATCH, OnUpdateOptionsEmulatorAutomaticallyipspatch) - ON_COMMAND(ID_OPTIONS_EMULATOR_AGBPRINT, OnOptionsEmulatorAgbprint) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_AGBPRINT, OnUpdateOptionsEmulatorAgbprint) - ON_COMMAND(ID_OPTIONS_EMULATOR_REALTIMECLOCK, OnOptionsEmulatorRealtimeclock) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_REALTIMECLOCK, OnUpdateOptionsEmulatorRealtimeclock) - ON_COMMAND(ID_OPTIONS_EMULATOR_GENERICFLASHCARD, OnOptionsEmulatorGenericflashcard) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_GENERICFLASHCARD, OnUpdateOptionsEmulatorGenericflashcard) - ON_COMMAND(ID_OPTIONS_EMULATOR_REWINDINTERVAL, OnOptionsEmulatorRewindinterval) - ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_AUTOMATIC, OnOptionsEmulatorSavetypeAutomatic) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_AUTOMATIC, OnUpdateOptionsEmulatorSavetypeAutomatic) - ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_EEPROM, OnOptionsEmulatorSavetypeEeprom) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_EEPROM, OnUpdateOptionsEmulatorSavetypeEeprom) - ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_SRAM, OnOptionsEmulatorSavetypeSram) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_SRAM, OnUpdateOptionsEmulatorSavetypeSram) - ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_FLASH, OnOptionsEmulatorSavetypeFlash) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_FLASH, OnUpdateOptionsEmulatorSavetypeFlash) - ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_EEPROMSENSOR, OnOptionsEmulatorSavetypeEepromsensor) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_EEPROMSENSOR, OnUpdateOptionsEmulatorSavetypeEepromsensor) - ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_NONE, OnOptionsEmulatorSavetypeNone) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_NONE, OnUpdateOptionsEmulatorSavetypeNone) - ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_FLASH512K, OnOptionsEmulatorSavetypeFlash512k) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_FLASH512K, OnUpdateOptionsEmulatorSavetypeFlash512k) - ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_FLASH1M, OnOptionsEmulatorSavetypeFlash1m) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_FLASH1M, OnUpdateOptionsEmulatorSavetypeFlash1m) - ON_COMMAND(ID_OPTIONS_EMULATOR_PNGFORMAT, OnOptionsEmulatorPngformat) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_PNGFORMAT, OnUpdateOptionsEmulatorPngformat) - ON_COMMAND(ID_OPTIONS_EMULATOR_BMPFORMAT, OnOptionsEmulatorBmpformat) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_BMPFORMAT, OnUpdateOptionsEmulatorBmpformat) - ON_COMMAND(ID_OPTIONS_SOUND_OFF, OnOptionsSoundOff) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_OFF, OnUpdateOptionsSoundOff) - ON_COMMAND(ID_OPTIONS_SOUND_MUTE, OnOptionsSoundMute) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_MUTE, OnUpdateOptionsSoundMute) - ON_COMMAND(ID_OPTIONS_SOUND_ON, OnOptionsSoundOn) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_ON, OnUpdateOptionsSoundOn) - ON_COMMAND(ID_OPTIONS_SOUND_ECHO, OnOptionsSoundEcho) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_ECHO, OnUpdateOptionsSoundEcho) - ON_COMMAND(ID_OPTIONS_SOUND_LOWPASSFILTER, OnOptionsSoundLowpassfilter) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_LOWPASSFILTER, OnUpdateOptionsSoundLowpassfilter) - ON_COMMAND(ID_OPTIONS_SOUND_REVERSESTEREO, OnOptionsSoundReversestereo) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_REVERSESTEREO, OnUpdateOptionsSoundReversestereo) - ON_COMMAND(ID_OPTIONS_SOUND_11KHZ, OnOptionsSound11khz) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_11KHZ, OnUpdateOptionsSound11khz) - ON_COMMAND(ID_OPTIONS_SOUND_22KHZ, OnOptionsSound22khz) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_22KHZ, OnUpdateOptionsSound22khz) - ON_COMMAND(ID_OPTIONS_SOUND_44KHZ, OnOptionsSound44khz) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_44KHZ, OnUpdateOptionsSound44khz) - ON_COMMAND(ID_OPTIONS_SOUND_CHANNEL1, OnOptionsSoundChannel1) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_CHANNEL1, OnUpdateOptionsSoundChannel1) - ON_COMMAND(ID_OPTIONS_SOUND_CHANNEL2, OnOptionsSoundChannel2) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_CHANNEL2, OnUpdateOptionsSoundChannel2) - ON_COMMAND(ID_OPTIONS_SOUND_CHANNEL3, OnOptionsSoundChannel3) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_CHANNEL3, OnUpdateOptionsSoundChannel3) - ON_COMMAND(ID_OPTIONS_SOUND_CHANNEL4, OnOptionsSoundChannel4) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_CHANNEL4, OnUpdateOptionsSoundChannel4) - ON_COMMAND(ID_OPTIONS_SOUND_DIRECTSOUNDA, OnOptionsSoundDirectsounda) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_DIRECTSOUNDA, OnUpdateOptionsSoundDirectsounda) - ON_COMMAND(ID_OPTIONS_SOUND_DIRECTSOUNDB, OnOptionsSoundDirectsoundb) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_DIRECTSOUNDB, OnUpdateOptionsSoundDirectsoundb) - ON_COMMAND(ID_OPTIONS_GAMEBOY_BORDER, OnOptionsGameboyBorder) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_BORDER, OnUpdateOptionsGameboyBorder) - ON_COMMAND(ID_OPTIONS_GAMEBOY_PRINTER, OnOptionsGameboyPrinter) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_PRINTER, OnUpdateOptionsGameboyPrinter) - ON_COMMAND(ID_OPTIONS_GAMEBOY_BORDERAUTOMATIC, OnOptionsGameboyBorderAutomatic) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_BORDERAUTOMATIC, OnUpdateOptionsGameboyBorderAutomatic) - ON_COMMAND(ID_OPTIONS_GAMEBOY_AUTOMATIC, OnOptionsGameboyAutomatic) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_AUTOMATIC, OnUpdateOptionsGameboyAutomatic) - ON_COMMAND(ID_OPTIONS_GAMEBOY_GBA, OnOptionsGameboyGba) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_GBA, OnUpdateOptionsGameboyGba) - ON_COMMAND(ID_OPTIONS_GAMEBOY_CGB, OnOptionsGameboyCgb) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_CGB, OnUpdateOptionsGameboyCgb) - ON_COMMAND(ID_OPTIONS_GAMEBOY_SGB, OnOptionsGameboySgb) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_SGB, OnUpdateOptionsGameboySgb) - ON_COMMAND(ID_OPTIONS_GAMEBOY_SGB2, OnOptionsGameboySgb2) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_SGB2, OnUpdateOptionsGameboySgb2) - ON_COMMAND(ID_OPTIONS_GAMEBOY_GB, OnOptionsGameboyGb) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_GB, OnUpdateOptionsGameboyGb) - ON_COMMAND(ID_OPTIONS_GAMEBOY_REALCOLORS, OnOptionsGameboyRealcolors) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_REALCOLORS, OnUpdateOptionsGameboyRealcolors) - ON_COMMAND(ID_OPTIONS_GAMEBOY_GAMEBOYCOLORS, OnOptionsGameboyGameboycolors) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_GAMEBOYCOLORS, OnUpdateOptionsGameboyGameboycolors) - ON_COMMAND(ID_OPTIONS_GAMEBOY_COLORS, OnOptionsGameboyColors) - ON_COMMAND(ID_OPTIONS_FILTER_DISABLEMMX, OnOptionsFilterDisablemmx) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FILTER_DISABLEMMX, OnUpdateOptionsFilterDisablemmx) - ON_COMMAND(ID_OPTIONS_LANGUAGE_SYSTEM, OnOptionsLanguageSystem) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_LANGUAGE_SYSTEM, OnUpdateOptionsLanguageSystem) - ON_COMMAND(ID_OPTIONS_LANGUAGE_ENGLISH, OnOptionsLanguageEnglish) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_LANGUAGE_ENGLISH, OnUpdateOptionsLanguageEnglish) - ON_COMMAND(ID_OPTIONS_LANGUAGE_OTHER, OnOptionsLanguageOther) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_LANGUAGE_OTHER, OnUpdateOptionsLanguageOther) - ON_COMMAND(ID_OPTIONS_JOYPAD_CONFIGURE_1, OnOptionsJoypadConfigure1) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_JOYPAD_CONFIGURE_1, OnUpdateOptionsJoypadConfigure1) - ON_COMMAND(ID_OPTIONS_JOYPAD_CONFIGURE_2, OnOptionsJoypadConfigure2) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_JOYPAD_CONFIGURE_2, OnUpdateOptionsJoypadConfigure2) - ON_COMMAND(ID_OPTIONS_JOYPAD_CONFIGURE_3, OnOptionsJoypadConfigure3) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_JOYPAD_CONFIGURE_3, OnUpdateOptionsJoypadConfigure3) - ON_COMMAND(ID_OPTIONS_JOYPAD_CONFIGURE_4, OnOptionsJoypadConfigure4) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_JOYPAD_CONFIGURE_4, OnUpdateOptionsJoypadConfigure4) - ON_COMMAND(ID_OPTIONS_JOYPAD_MOTIONCONFIGURE, OnOptionsJoypadMotionconfigure) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_JOYPAD_MOTIONCONFIGURE, OnUpdateOptionsJoypadMotionconfigure) - ON_COMMAND(ID_CHEATS_SEARCHFORCHEATS, OnCheatsSearchforcheats) - ON_UPDATE_COMMAND_UI(ID_CHEATS_SEARCHFORCHEATS, OnUpdateCheatsSearchforcheats) - ON_COMMAND(ID_CHEATS_CHEATLIST, OnCheatsCheatlist) - ON_UPDATE_COMMAND_UI(ID_CHEATS_CHEATLIST, OnUpdateCheatsCheatlist) - ON_COMMAND(ID_CHEATS_AUTOMATICSAVELOADCHEATS, OnCheatsAutomaticsaveloadcheats) - ON_COMMAND(ID_CHEATS_LOADCHEATLIST, OnCheatsLoadcheatlist) - ON_UPDATE_COMMAND_UI(ID_CHEATS_LOADCHEATLIST, OnUpdateCheatsLoadcheatlist) - ON_COMMAND(ID_CHEATS_SAVECHEATLIST, OnCheatsSavecheatlist) - ON_UPDATE_COMMAND_UI(ID_CHEATS_SAVECHEATLIST, OnUpdateCheatsSavecheatlist) - ON_COMMAND(ID_TOOLS_DISASSEMBLE, OnToolsDisassemble) - ON_UPDATE_COMMAND_UI(ID_TOOLS_DISASSEMBLE, OnUpdateToolsDisassemble) - ON_COMMAND(ID_TOOLS_LOGGING, OnToolsLogging) - ON_UPDATE_COMMAND_UI(ID_TOOLS_LOGGING, OnUpdateToolsLogging) - ON_COMMAND(ID_TOOLS_IOVIEWER, OnToolsIoviewer) - ON_UPDATE_COMMAND_UI(ID_TOOLS_IOVIEWER, OnUpdateToolsIoviewer) - ON_COMMAND(ID_TOOLS_MAPVIEW, OnToolsMapview) - ON_UPDATE_COMMAND_UI(ID_TOOLS_MAPVIEW, OnUpdateToolsMapview) - ON_COMMAND(ID_TOOLS_MEMORYVIEWER, OnToolsMemoryviewer) - ON_UPDATE_COMMAND_UI(ID_TOOLS_MEMORYVIEWER, OnUpdateToolsMemoryviewer) - ON_COMMAND(ID_TOOLS_OAMVIEWER, OnToolsOamviewer) - ON_UPDATE_COMMAND_UI(ID_TOOLS_OAMVIEWER, OnUpdateToolsOamviewer) - ON_COMMAND(ID_TOOLS_PALETTEVIEW, OnToolsPaletteview) - ON_UPDATE_COMMAND_UI(ID_TOOLS_PALETTEVIEW, OnUpdateToolsPaletteview) - ON_COMMAND(ID_TOOLS_TILEVIEWER, OnToolsTileviewer) - ON_UPDATE_COMMAND_UI(ID_TOOLS_TILEVIEWER, OnUpdateToolsTileviewer) - ON_COMMAND(ID_DEBUG_NEXTFRAME, OnDebugNextframe) - ON_UPDATE_COMMAND_UI(ID_CHEATS_AUTOMATICSAVELOADCHEATS, OnUpdateCheatsAutomaticsaveloadcheats) - ON_COMMAND(ID_TOOLS_DEBUG_GDB, OnToolsDebugGdb) - ON_UPDATE_COMMAND_UI(ID_TOOLS_DEBUG_GDB, OnUpdateToolsDebugGdb) - ON_COMMAND(ID_TOOLS_DEBUG_LOADANDWAIT, OnToolsDebugLoadandwait) - ON_UPDATE_COMMAND_UI(ID_TOOLS_DEBUG_LOADANDWAIT, OnUpdateToolsDebugLoadandwait) - ON_COMMAND(ID_TOOLS_DEBUG_BREAK, OnToolsDebugBreak) - ON_UPDATE_COMMAND_UI(ID_TOOLS_DEBUG_BREAK, OnUpdateToolsDebugBreak) - ON_COMMAND(ID_TOOLS_DEBUG_DISCONNECT, OnToolsDebugDisconnect) - ON_UPDATE_COMMAND_UI(ID_TOOLS_DEBUG_DISCONNECT, OnUpdateToolsDebugDisconnect) - ON_COMMAND(ID_OPTIONS_SOUND_STARTRECORDING, OnOptionsSoundStartrecording) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_STARTRECORDING, OnUpdateOptionsSoundStartrecording) - ON_COMMAND(ID_OPTIONS_SOUND_STOPRECORDING, OnOptionsSoundStoprecording) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_STOPRECORDING, OnUpdateOptionsSoundStoprecording) - ON_COMMAND(ID_TOOLS_RECORD_STARTAVIRECORDING, OnToolsRecordStartavirecording) - ON_UPDATE_COMMAND_UI(ID_TOOLS_RECORD_STARTAVIRECORDING, OnUpdateToolsRecordStartavirecording) - ON_COMMAND(ID_TOOLS_RECORD_STOPAVIRECORDING, OnToolsRecordStopavirecording) - ON_UPDATE_COMMAND_UI(ID_TOOLS_RECORD_STOPAVIRECORDING, OnUpdateToolsRecordStopavirecording) - ON_WM_PAINT() - ON_COMMAND(ID_TOOLS_RECORD_STARTMOVIERECORDING, OnToolsRecordStartmovierecording) - ON_UPDATE_COMMAND_UI(ID_TOOLS_RECORD_STARTMOVIERECORDING, OnUpdateToolsRecordStartmovierecording) - ON_COMMAND(ID_TOOLS_RECORD_STOPMOVIERECORDING, OnToolsRecordStopmovierecording) - ON_UPDATE_COMMAND_UI(ID_TOOLS_RECORD_STOPMOVIERECORDING, OnUpdateToolsRecordStopmovierecording) - ON_COMMAND(ID_TOOLS_PLAY_STARTMOVIEPLAYING, OnToolsPlayStartmovieplaying) - ON_UPDATE_COMMAND_UI(ID_TOOLS_PLAY_STARTMOVIEPLAYING, OnUpdateToolsPlayStartmovieplaying) - ON_COMMAND(ID_TOOLS_PLAY_STOPMOVIEPLAYING, OnToolsPlayStopmovieplaying) - ON_UPDATE_COMMAND_UI(ID_TOOLS_PLAY_STOPMOVIEPLAYING, OnUpdateToolsPlayStopmovieplaying) - ON_COMMAND(ID_TOOLS_REWIND, OnToolsRewind) - ON_UPDATE_COMMAND_UI(ID_TOOLS_REWIND, OnUpdateToolsRewind) - ON_COMMAND(ID_TOOLS_CUSTOMIZE, OnToolsCustomize) - ON_UPDATE_COMMAND_UI(ID_TOOLS_CUSTOMIZE, OnUpdateToolsCustomize) - ON_COMMAND(ID_HELP_BUGREPORT, OnHelpBugreport) - ON_WM_MOUSEMOVE() - ON_WM_INITMENU() - ON_WM_ACTIVATE() - ON_WM_DROPFILES() - ON_COMMAND(ID_FILE_SAVEGAME_OLDESTSLOT, OnFileSavegameOldestslot) - ON_UPDATE_COMMAND_UI(ID_FILE_SAVEGAME_OLDESTSLOT, OnUpdateFileSavegameOldestslot) - ON_COMMAND(ID_FILE_LOADGAME_MOSTRECENT, OnFileLoadgameMostrecent) - ON_UPDATE_COMMAND_UI(ID_FILE_LOADGAME_MOSTRECENT, OnUpdateFileLoadgameMostrecent) - ON_COMMAND(ID_FILE_LOADGAME_AUTOLOADMOSTRECENT, OnFileLoadgameAutoloadmostrecent) - ON_UPDATE_COMMAND_UI(ID_FILE_LOADGAME_AUTOLOADMOSTRECENT, OnUpdateFileLoadgameAutoloadmostrecent) - ON_COMMAND(ID_OPTIONS_SOUND_VOLUME_25X, OnOptionsSoundVolume25x) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_VOLUME_25X, OnUpdateOptionsSoundVolume25x) - ON_COMMAND(ID_OPTIONS_SOUND_VOLUME_5X, OnOptionsSoundVolume5x) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_VOLUME_5X, OnUpdateOptionsSoundVolume5x) - ON_COMMAND(ID_CHEATS_DISABLECHEATS, OnCheatsDisablecheats) - ON_UPDATE_COMMAND_UI(ID_CHEATS_DISABLECHEATS, OnUpdateCheatsDisablecheats) - ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREENMAXSCALE, OnOptionsVideoFullscreenmaxscale) - ON_COMMAND(ID_OPTIONS_EMULATOR_GAMEOVERRIDES, OnOptionsEmulatorGameoverrides) - ON_COMMAND(ID_OPTIONS_SELECT_PLUGIN, OnOptionsSelectPlugin) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_GAMEOVERRIDES, OnUpdateOptionsEmulatorGameoverrides) - ON_COMMAND(ID_HELP_GNUPUBLICLICENSE, OnHelpGnupubliclicense) - ON_COMMAND(ID_OPTIONS_LINK_OPTIONS, OnLinkOptions) - ON_COMMAND(ID_OPTIONS_LINK_LOG, OnOptionsLinkLog) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_LINK_LOG, OnUpdateOptionsLinkLog) - ON_COMMAND(ID_OPTIONS_LINK_WIRELESSADAPTER, OnOptionsLinkRFU) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_LINK_WIRELESSADAPTER, OnUpdateOptionsLinkRFU) - ON_COMMAND(ID_OPTIONS_LINK_ENABLE, OnOptionsLinkEnable) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_LINK_ENABLE, OnUpdateOptionsLinkEnable) - - //}}AFX_MSG_MAP - ON_COMMAND_EX_RANGE(ID_FILE_MRU_FILE1, ID_FILE_MRU_FILE10, OnFileRecentFile) - ON_COMMAND_EX_RANGE(ID_FILE_LOADGAME_SLOT1, ID_FILE_LOADGAME_SLOT10, OnFileLoadSlot) - ON_COMMAND_EX_RANGE(ID_FILE_SAVEGAME_SLOT1, ID_FILE_SAVEGAME_SLOT10, OnFileSaveSlot) - ON_UPDATE_COMMAND_UI_RANGE(ID_FILE_LOADGAME_SLOT1, ID_FILE_LOADGAME_SLOT10, OnUpdateFileLoadGameSlot) - ON_UPDATE_COMMAND_UI_RANGE(ID_FILE_SAVEGAME_SLOT1, ID_FILE_SAVEGAME_SLOT10, OnUpdateFileSaveGameSlot) - ON_COMMAND_EX_RANGE(ID_OPTIONS_VIDEO_FRAMESKIP_0, ID_OPTIONS_VIDEO_FRAMESKIP_5, OnOptionsFrameskip) - ON_COMMAND_EX_RANGE(ID_OPTIONS_VIDEO_FRAMESKIP_6, ID_OPTIONS_VIDEO_FRAMESKIP_9, OnOptionsFrameskip) - ON_COMMAND_EX_RANGE(ID_OPTIONS_VIDEO_X1, ID_OPTIONS_VIDEO_X4, OnOptionVideoSize) - ON_COMMAND_EX_RANGE(ID_OPTIONS_VIDEO_LAYERS_BG0, ID_OPTIONS_VIDEO_LAYERS_OBJWIN, OnVideoLayer) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_VIDEO_LAYERS_BG0, ID_OPTIONS_VIDEO_LAYERS_OBJWIN, OnUpdateVideoLayer) - ON_COMMAND(ID_SYSTEM_MINIMIZE, OnSystemMinimize) - ON_COMMAND_EX_RANGE(ID_OPTIONS_EMULATOR_SHOWSPEED_NONE, ID_OPTIONS_EMULATOR_SHOWSPEED_TRANSPARENT, OnOptionsEmulatorShowSpeed) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_EMULATOR_SHOWSPEED_NONE, ID_OPTIONS_EMULATOR_SHOWSPEED_TRANSPARENT, OnUpdateOptionsEmulatorShowSpeed) - ON_COMMAND_EX_RANGE(ID_OPTIONS_SOUND_VOLUME_1X, ID_OPTIONS_SOUND_VOLUME_4X, OnOptionsSoundVolume) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_SOUND_VOLUME_1X, ID_OPTIONS_SOUND_VOLUME_4X, OnUpdateOptionsSoundVolume) - ON_COMMAND_EX_RANGE(ID_OPTIONS_PRIORITY_HIGHEST, ID_OPTIONS_PRIORITY_BELOWNORMAL, OnOptionsPriority) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_PRIORITY_HIGHEST, ID_OPTIONS_PRIORITY_BELOWNORMAL, OnUpdateOptionsPriority) - ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER_NORMAL, ID_OPTIONS_FILTER_TVMODE, OnOptionsFilter) - ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER16BIT_PIXELATEEXPERIMENTAL, ID_OPTIONS_FILTER16BIT_MOTIONBLUREXPERIMENTAL, OnOptionsFilter) - ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER16BIT_ADVANCEMAMESCALE2X, ID_OPTIONS_FILTER16BIT_SIMPLE2X, OnOptionsFilter) - ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER_BILINEAR, ID_OPTIONS_FILTER_BILINEARPLUS, OnOptionsFilter) - ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER_SCANLINES, ID_OPTIONS_FILTER_SCANLINES, OnOptionsFilter) - ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER_HQ2X, ID_OPTIONS_FILTER_LQ2X, OnOptionsFilter) - ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER_PLUGIN, ID_OPTIONS_FILTER_PLUGIN, OnOptionsFilter) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER_PLUGIN, ID_OPTIONS_FILTER_PLUGIN, OnUpdateOptionsFilter) - ON_COMMAND_EX(ID_OPTIONS_FILTER_HQ3X, OnOptionsFilter) - ON_COMMAND_EX(ID_OPTIONS_FILTER_HQ4X, OnOptionsFilter) - ON_COMMAND_EX(ID_OPTIONS_FILTER_SIMPLE3X, OnOptionsFilter) - ON_COMMAND_EX(ID_OPTIONS_FILTER_SIMPLE4X, OnOptionsFilter) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER_NORMAL, ID_OPTIONS_FILTER_TVMODE, OnUpdateOptionsFilter) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER16BIT_PIXELATEEXPERIMENTAL, ID_OPTIONS_FILTER16BIT_MOTIONBLUREXPERIMENTAL, OnUpdateOptionsFilter) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER16BIT_ADVANCEMAMESCALE2X, ID_OPTIONS_FILTER16BIT_SIMPLE2X, OnUpdateOptionsFilter) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER_BILINEAR, ID_OPTIONS_FILTER_BILINEARPLUS, OnUpdateOptionsFilter) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER_SCANLINES, ID_OPTIONS_FILTER_SCANLINES, OnUpdateOptionsFilter) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER_HQ2X, ID_OPTIONS_FILTER_LQ2X, OnUpdateOptionsFilter) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FILTER_SIMPLE3X, OnUpdateOptionsFilter) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FILTER_SIMPLE4X, OnUpdateOptionsFilter) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FILTER_HQ3X, OnUpdateOptionsFilter) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FILTER_HQ4X, OnUpdateOptionsFilter) - ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER_INTERFRAMEBLENDING_NONE, ID_OPTIONS_FILTER_INTERFRAMEBLENDING_SMART, OnOptionsFilterIFB) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER_INTERFRAMEBLENDING_NONE, ID_OPTIONS_FILTER_INTERFRAMEBLENDING_SMART, OnUpdateOptionsFilterIFB) - ON_COMMAND_EX_RANGE(ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_1, ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_4, OnOptionsJoypadDefault) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_1, ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_4, OnUpdateOptionsJoypadDefault) - ON_COMMAND_EX_RANGE(ID_OPTIONS_JOYPAD_AUTOFIRE_A, ID_OPTIONS_JOYPAD_AUTOFIRE_R, OnOptionsJoypadAutofire) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_JOYPAD_AUTOFIRE_A, ID_OPTIONS_JOYPAD_AUTOFIRE_R, OnUpdateOptionsJoypadAutofire) - ON_MESSAGE(WM_SYSCOMMAND, OnMySysCommand) - ON_COMMAND(ID_OPTIONS_SOUND_HARDWAREACCELERATION, &MainWnd::OnOptionsSoundHardwareacceleration) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_HARDWAREACCELERATION, &MainWnd::OnUpdateOptionsSoundHardwareacceleration) - ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREEN1280X1024, OnOptionsVideoFullscreen1280x1024) - ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREEN1024X768, OnOptionsVideoFullscreen1024x768) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREEN1024X768, OnUpdateOptionsVideoFullscreen1024x768) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREEN1280X1024, OnUpdateOptionsVideoFullscreen1280x1024) - ON_COMMAND(ID_OPTIONS_FILTER_LCDCOLORS, OnOptionsFilterLcdcolors) - ON_UPDATE_COMMAND_UI(ID_OPTIONS_FILTER_LCDCOLORS, OnUpdateOptionsFilterLcdcolors) - ON_COMMAND_EX_RANGE(ID_OPTIONS_SOUND_PCMINTERPOLATION_NONE, ID_OPTIONS_SOUND_PCMINTERPOLATION_LIBRESAMPLE, OnOptionsSoundPcminterpolation) - ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_SOUND_PCMINTERPOLATION_NONE, ID_OPTIONS_SOUND_PCMINTERPOLATION_LIBRESAMPLE, OnUpdateOptionsSoundPcminterpolation) - ON_COMMAND(ID_OUTPUTAPI_DIRECTSOUND, &MainWnd::OnOutputapiDirectsound) - ON_UPDATE_COMMAND_UI(ID_OUTPUTAPI_DIRECTSOUND, &MainWnd::OnUpdateOutputapiDirectsound) - ON_COMMAND(ID_OUTPUTAPI_OPENAL, &MainWnd::OnOutputapiOpenal) - ON_UPDATE_COMMAND_UI(ID_OUTPUTAPI_OPENAL, &MainWnd::OnUpdateOutputapiOpenal) - ON_COMMAND(ID_OUTPUTAPI_OALCONFIGURATION, &MainWnd::OnOutputapiOalconfiguration) - ON_UPDATE_COMMAND_UI(ID_OUTPUTAPI_OALCONFIGURATION, &MainWnd::OnUpdateOutputapiOalconfiguration) - ON_COMMAND(ID_RENDERAPI_D3DMOTIONBLUR, &MainWnd::OnRenderapiD3dmotionblur) - ON_UPDATE_COMMAND_UI(ID_RENDERAPI_D3DMOTIONBLUR, &MainWnd::OnUpdateRenderapiD3dmotionblur) - ON_WM_NCLBUTTONDOWN() - ON_WM_WINDOWPOSCHANGING() - ON_COMMAND(ID_EMULATOR_BIOSFILES, &MainWnd::OnEmulatorBiosfiles) - ON_COMMAND(ID_FILE_OPEN_GBC, &MainWnd::OnFileOpenGbc) - END_MESSAGE_MAP() - - - ///////////////////////////////////////////////////////////////////////////// -// MainWnd message handlers - -void MainWnd::OnClose() -{ - emulating = false; - CWnd::OnClose(); - - delete this; -} - -bool MainWnd::FileRun() -{ - // save battery file before we change the filename... - if(rom != NULL || gbRom != NULL) { - if(theApp.autoSaveLoadCheatList) - winSaveCheatListDefault(); - writeBatteryFile(); - cheatSearchCleanup(&cheatSearchData); - theApp.emulator.emuCleanUp(); - remoteCleanUp(); - emulating = false; -#ifdef APU_LOGGER_H - end_apu_log(); -#endif - } - char tempName[2048]; - char file[2048]; - CString oldFile = theApp.filename; - - utilStripDoubleExtension(theApp.szFile, tempName); - - _fullpath(file, tempName, 2048); - theApp.filename = file; - - int index = theApp.filename.ReverseFind('.'); - if(index != -1) - theApp.filename = theApp.filename.Left(index); - - if( theApp.filename != oldFile ) { - // clear cheat list when another game is loaded - cheatsDeleteAll( false ); - gbCheatRemoveAll(); - } - - CString ipsname; - ipsname.Format("%s.ips", theApp.filename); - - if(!theApp.dir.GetLength()) { - int index = theApp.filename.ReverseFind('\\'); - if(index != -1) { - theApp.dir = theApp.filename.Left(index-1); - } - } - - IMAGE_TYPE type = utilFindType(theApp.szFile); - - if(type == IMAGE_UNKNOWN) { - systemMessage(IDS_UNSUPPORTED_FILE_TYPE, - "Unsupported file type: %s", theApp.szFile); - return false; - } - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - theApp.cartridgeType = type; - if(type == IMAGE_GB) { - genericflashcardEnable = theApp.winGenericflashcardEnable; - - - if(!gbLoadRom(theApp.szFile)) - return false; - - gbGetHardwareType(); - - // used for the handling of the gb Boot Rom - if (gbHardware & 5) - { - skipBios = theApp.skipBiosFile; - gbCPUInit(theApp.biosFileNameGB, theApp.useBiosFileGB); - } - - - - gbReset(); - theApp.emulator = GBSystem; - gbBorderOn = theApp.winGbBorderOn; - theApp.romSize = gbRomSize; - - - if(theApp.autoIPS) { - int size = gbRomSize; - utilApplyIPS(ipsname, &gbRom, &size); - if(size != gbRomSize) { - extern bool gbUpdateSizes(); - gbUpdateSizes(); - gbReset(); - theApp.romSize = size; - } - } - } else { - int size = CPULoadRom(theApp.szFile); - if(!size) - return false; - - theApp.romSize = size; - - flashSetSize(theApp.winFlashSize); - rtcEnable(theApp.winRtcEnable); - cpuSaveType = theApp.winSaveType; - - GetModuleFileName(NULL, tempName, 2048); - - char *p = strrchr(tempName, '\\'); - if(p) - *p = 0; - - char buffer[5]; - strncpy(buffer, (const char *)&rom[0xac], 4); - buffer[4] = 0; - - strcat(tempName, "\\vba-over.ini"); - - UINT i = GetPrivateProfileInt(buffer, - "rtcEnabled", - -1, - tempName); - if(i != (UINT)-1) - rtcEnable(i == 0 ? false : true); - - i = GetPrivateProfileInt(buffer, - "flashSize", - -1, - tempName); - if(i != (UINT)-1 && (i == 0x10000 || i == 0x20000)) - flashSetSize((int)i); - - i = GetPrivateProfileInt(buffer, - "saveType", - -1, - tempName); - if(i != (UINT)-1 && (i <= 5)) - cpuSaveType = (int)i; - i = GetPrivateProfileInt(buffer, - "mirroringEnabled", - -1, - tempName); - if(i != (UINT)-1) - doMirroring (i == 0 ? false : true); - - theApp.emulator = GBASystem; - /* disabled due to problems - if(theApp.removeIntros && rom != NULL) { - *((u32 *)rom)= 0xea00002e; - } - */ - - if(theApp.autoIPS) { - int size = 0x2000000; - utilApplyIPS(ipsname, &rom, &size); - if(size != 0x2000000) { - CPUReset(); - } - } - } - - if(theApp.soundInitialized) { - if(theApp.cartridgeType == 1) - gbSoundReset(); - else - soundReset(); - } else { - if(!soundOffFlag) - soundInit(); - theApp.soundInitialized = true; - } - -#ifdef APU_LOGGER_H - begin_apu_log("apu_log.txt"); -#endif - - if(type == IMAGE_GBA) { - skipBios = theApp.skipBiosFile; - CPUInit(theApp.biosFileNameGBA.GetString(), theApp.useBiosFileGBA); - CPUReset(); - } - - readBatteryFile(); - - if(theApp.autoSaveLoadCheatList) - winLoadCheatListDefault(); - - theApp.addRecentFile(theApp.szFile); - - theApp.updateWindowSize(theApp.videoOption); - - theApp.updateFrameSkip(); - - emulating = true; - - if(theApp.autoLoadMostRecent) - OnFileLoadgameMostrecent(); - - theApp.frameskipadjust = 0; - theApp.renderedFrames = 0; - theApp.autoFrameSkipLastTime = systemGetClock(); - - theApp.rewindCount = 0; - theApp.rewindCounter = 0; - theApp.rewindSaveNeeded = false; - - toolsClearLog(); - - return true; -} - -void MainWnd::OnInitMenuPopup(CMenu* pMenu, UINT nIndex, BOOL bSysMenu) -{ - ASSERT(pMenu != NULL); - - CCmdUI state; - state.m_pMenu = pMenu; - ASSERT(state.m_pOther == NULL); - ASSERT(state.m_pParentMenu == NULL); - - // determine if menu is popup in top-level menu and set m_pOther to - // it if so (m_pParentMenu == NULL indicates that it is secondary popup) - HMENU hParentMenu; - if (AfxGetThreadState()->m_hTrackingMenu == pMenu->m_hMenu) - state.m_pParentMenu = pMenu; // parent == child for tracking popup - else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL) { - CWnd* pParent = GetTopLevelParent(); - // child windows don't have menus -- need to go to the top! - if (pParent != NULL && - (hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL) { - int nIndexMax = ::GetMenuItemCount(hParentMenu); - for (int nIndex = 0; nIndex < nIndexMax; nIndex++) { - if (::GetSubMenu(hParentMenu, nIndex) == pMenu->m_hMenu) { - // when popup is found, m_pParentMenu is containing menu - state.m_pParentMenu = CMenu::FromHandle(hParentMenu); - break; - } - } - } - } - - state.m_nIndexMax = pMenu->GetMenuItemCount(); - for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; - state.m_nIndex++) { - state.m_nID = pMenu->GetMenuItemID(state.m_nIndex); - if (state.m_nID == 0) - continue; // menu separator or invalid cmd - ignore it - - ASSERT(state.m_pOther == NULL); - ASSERT(state.m_pMenu != NULL); - if (state.m_nID == (UINT)-1) { - // possibly a popup menu, route to first item of that popup - state.m_pSubMenu = pMenu->GetSubMenu(state.m_nIndex); - if (state.m_pSubMenu == NULL || - (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 || - state.m_nID == (UINT)-1) { - continue; // first item of popup can't be routed to - } - state.DoUpdate(this, FALSE); // popups are never auto disabled - } else { - // normal menu item - // Auto enable/disable if frame window has 'm_bAutoMenuEnable' - // set and command is _not_ a system command. - state.m_pSubMenu = NULL; - state.DoUpdate(this, state.m_nID < 0xF000); - } - - // adjust for menu deletions and additions - UINT nCount = pMenu->GetMenuItemCount(); - if (nCount < state.m_nIndexMax) { - state.m_nIndex -= (state.m_nIndexMax - nCount); - while (state.m_nIndex < nCount && - pMenu->GetMenuItemID(state.m_nIndex) == state.m_nID) { - state.m_nIndex++; - } - } - state.m_nIndexMax = nCount; - } -} - -void MainWnd::OnMoving(UINT fwSide, LPRECT pRect) -{ - CWnd::OnMoving(fwSide, pRect); - - if( emulating ) { - soundPause(); - } -} - -void MainWnd::OnMove(int x, int y) -{ - CWnd::OnMove(x, y); - - if(!theApp.changingVideoSize) { - if(this) { - if(!IsIconic()) { - RECT r; - - GetWindowRect(&r); - theApp.windowPositionX = r.left; - theApp.windowPositionY = r.top; - theApp.adjustDestRect(); - regSetDwordValue("windowX", theApp.windowPositionX); - regSetDwordValue("windowY", theApp.windowPositionY); - } - } - } -} - -void MainWnd::OnSizing(UINT fwSide, LPRECT pRect) -{ // the OnSizing event only occurs in windowed mode - CWnd::OnSizing(fwSide, pRect); - - // pause sound to prevent low sound buffers - if( emulating ) { - soundPause(); - } - - // maintain minimal window size - RECT size = { 0, 0, theApp.sizeX, theApp.sizeY }; - AdjustWindowRectEx( - &size, - WS_POPUP | WS_VISIBLE | WS_OVERLAPPEDWINDOW, - FALSE, - 0 ); - MENUBARINFO mbi; - mbi.cbSize = sizeof(MENUBARINFO); - this->GetMenuBarInfo( OBJID_MENU, 0, &mbi ); - const LONG menuHeight = mbi.rcBar.bottom - mbi.rcBar.top + 1; - // +1 because of that white line, wherever it comes from - const LONG width = size.right - size.left; - const LONG height = size.bottom - size.top + menuHeight; - if( ( pRect->right - pRect->left ) < width ) { - pRect->right = pRect->left + width; - } - if( ( pRect->bottom - pRect->top ) < height ) { - pRect->bottom = pRect->top + height; - } -} - -void MainWnd::OnSize(UINT nType, int cx, int cy) -{ - CWnd::OnSize(nType, cx, cy); - - bool redraw = ( ( cx < theApp.surfaceSizeX ) || ( cy < theApp.surfaceSizeY ) ); - - if(!theApp.changingVideoSize) { - if(this) { - if(!IsIconic()) { - if(theApp.iconic) { - if(emulating) { - soundResume(); - theApp.paused = false; - } - } - if(theApp.videoOption <= VIDEO_4X) { - theApp.surfaceSizeX = cx; - theApp.surfaceSizeY = cy; - theApp.adjustDestRect(); - if(theApp.display) - theApp.display->resize(theApp.dest.right-theApp.dest.left, theApp.dest.bottom-theApp.dest.top); - if( redraw && emulating ) { - theApp.painting = true; - systemDrawScreen(); - theApp.painting = false; - theApp.renderedFrames--; - } - } - } else { - if(emulating) { - if(!theApp.paused) { - theApp.paused = true; - soundPause(); - } - } - theApp.iconic = true; - } - } - } -} - -void MainWnd::winSaveCheatListDefault() -{ - CString name; - CString filename; - - int index = theApp.filename.ReverseFind('\\'); - - if(index != -1) - name = theApp.filename.Right(theApp.filename.GetLength()-index-1); - else - name = theApp.filename; - CString dir = regQueryStringValue("saveDir", NULL); - if( dir[0] == '.' ) { - // handle as relative path - char baseDir[MAX_PATH+1]; - GetModuleFileName( NULL, baseDir, MAX_PATH ); - baseDir[MAX_PATH] = '\0'; // for security reasons - PathRemoveFileSpec( baseDir ); // removes the trailing file name and backslash - strcat( baseDir, "\\" ); - strcat( baseDir, dir ); - dir = baseDir; - } - - if(!dir.GetLength()) - dir = getDirFromFile(filename); - - if(isDriveRoot(dir)) - filename.Format("%s%s.clt", dir, name); - else - filename.Format("%s\\%s.clt", dir, name); - - winSaveCheatList(filename); -} - -void MainWnd::winSaveCheatList(const char *name) -{ - if(theApp.cartridgeType == 0) - cheatsSaveCheatList(name); - else - gbCheatsSaveCheatList(name); -} - -void MainWnd::winLoadCheatListDefault() -{ - CString name; - CString filename; - - int index = theApp.filename.ReverseFind('\\'); - - if(index != -1) - name = theApp.filename.Right(theApp.filename.GetLength()-index-1); - else - name = theApp.filename; - CString dir = regQueryStringValue("saveDir", NULL); - if( dir[0] == '.' ) { - // handle as relative path - char baseDir[MAX_PATH+1]; - GetModuleFileName( NULL, baseDir, MAX_PATH ); - baseDir[MAX_PATH] = '\0'; // for security reasons - PathRemoveFileSpec( baseDir ); // removes the trailing file name and backslash - strcat( baseDir, "\\" ); - strcat( baseDir, dir ); - dir = baseDir; - } - - if(!dir.GetLength()) - dir = getDirFromFile(filename); - - if(isDriveRoot(dir)) - filename.Format("%s%s.clt", dir, name); - else - filename.Format("%s\\%s.clt", dir, name); - - winLoadCheatList(filename); -} - -void MainWnd::winLoadCheatList(const char *name) -{ - bool res = false; - - if(theApp.cartridgeType == 0) - res = cheatsLoadCheatList(name); - else - res = gbCheatsLoadCheatList(name); - - if(res) - systemScreenMessage(winResLoadString(IDS_LOADED_CHEATS)); -} - -CString MainWnd::getDirFromFile(CString& file) -{ - CString temp = file; - int index = temp.ReverseFind('\\'); - - if(index != -1) { - temp = temp.Left(index); - if(temp.GetLength() == 2 && temp[1] == ':') - temp += "\\"; - } else { - temp = ""; - } - return temp; -} - -bool MainWnd::isDriveRoot(CString& file) -{ - if(file.GetLength() == 3) { - if(file[1] == ':' && file[2] == '\\') - return true; - } - return false; -} - -void MainWnd::writeBatteryFile() -{ - CString buffer; - CString filename; - - int index = theApp.filename.ReverseFind('\\'); - - if(index != -1) - buffer = theApp.filename.Right(theApp.filename.GetLength()-index-1); - else - buffer = theApp.filename; - - CString saveDir = regQueryStringValue("batteryDir", NULL); - if( saveDir[0] == '.' ) { - // handle as relative path - char baseDir[MAX_PATH+1]; - GetModuleFileName( NULL, baseDir, MAX_PATH ); - baseDir[MAX_PATH] = '\0'; // for security reasons - PathRemoveFileSpec( baseDir ); // removes the trailing file name and backslash - strcat( baseDir, "\\" ); - strcat( baseDir, saveDir ); - saveDir = baseDir; - } - - if(saveDir.IsEmpty()) - saveDir = getDirFromFile(theApp.filename); - - if(isDriveRoot(saveDir)) - filename.Format("%s%s.sav", saveDir, buffer); - else - filename.Format("%s\\%s.sav", saveDir, buffer); - - if(theApp.emulator.emuWriteBattery) - theApp.emulator.emuWriteBattery(MakeInstanceFilename((const char *)filename)); -} - - -void MainWnd::readBatteryFile() -{ - CString buffer; - CString filename; - - int index = theApp.filename.ReverseFind('\\'); - - if(index != -1) - buffer = theApp.filename.Right(theApp.filename.GetLength()-index-1); - else - buffer = theApp.filename; - - CString saveDir = regQueryStringValue("batteryDir", NULL); - if( saveDir[0] == '.' ) { - // handle as relative path - char baseDir[MAX_PATH+1]; - GetModuleFileName( NULL, baseDir, MAX_PATH ); - baseDir[MAX_PATH] = '\0'; // for security reasons - PathRemoveFileSpec( baseDir ); // removes the trailing file name and backslash - strcat( baseDir, "\\" ); - strcat( baseDir, saveDir ); - saveDir = baseDir; - } - - if(saveDir.IsEmpty()) - saveDir = getDirFromFile(theApp.filename); - - if(isDriveRoot(saveDir)) - filename.Format("%s%s.sav", saveDir, buffer); - else - filename.Format("%s\\%s.sav", saveDir, buffer); - - bool res = false; - - if(theApp.emulator.emuReadBattery) - res = theApp.emulator.emuReadBattery(MakeInstanceFilename(filename)); - - if(res) - systemScreenMessage(winResLoadString(IDS_LOADED_BATTERY)); -} - -CString MainWnd::winLoadFilter(UINT id) -{ - CString res = winResLoadString(id); - res.Replace('_','|'); - - return res; -} - -bool MainWnd::loadSaveGame(const char *name) -{ - if(theApp.emulator.emuReadState) - return theApp.emulator.emuReadState(name); - return false; -} - -bool MainWnd::writeSaveGame(const char *name) -{ - if(theApp.emulator.emuWriteState) - return theApp.emulator.emuWriteState(name); - return false; -} - -void MainWnd::OnContextMenu(CWnd* pWnd, CPoint point) -{ - winMouseOn(); -} - -void MainWnd::OnSystemMinimize() -{ - ShowWindow(SW_SHOWMINIMIZED); -} - - -bool MainWnd::fileOpenSelect( int system ) -{ - theApp.dir = _T(""); - CString initialDir; - int selectedFilter = 0; - LPCTSTR exts[] = { _T(""), _T(""), _T(""), _T("") }; - CString filter; - CString title; - switch( system ) - { - case 0: - // GBA - initialDir = regQueryStringValue( _T("romdir"), _T(".") ); - selectedFilter = regQueryDwordValue( _T("selectedFilter"), 0); - if( (selectedFilter < 0) || (selectedFilter > 2) ) { - selectedFilter = 0; - } - filter = winLoadFilter( IDS_FILTER_ROM ); - break; - case 1: - // GBC - initialDir = regQueryStringValue( _T("gbcromdir"), _T(".") ); - // TODO: memorize selected filter for GBC as well - filter = winLoadFilter( IDS_FILTER_GBCROM ); - break; - case 2: - // GB - initialDir = regQueryStringValue( _T("gbromdir"), _T(".") ); - // TODO: memorize selected filter for GB as well - filter = winLoadFilter( IDS_FILTER_GBROM ); - break; - } - - title = winResLoadString( IDS_SELECT_ROM ); - - if( !initialDir.IsEmpty() ) { - theApp.dir = initialDir; - } - - if( initialDir[0] == '.' ) { - // handle as relative path - char baseDir[MAX_PATH+1]; - GetModuleFileName( NULL, baseDir, MAX_PATH ); - baseDir[MAX_PATH] = '\0'; // for security reasons - PathRemoveFileSpec( baseDir ); // removes the trailing file name and backslash - strcat( baseDir, "\\" ); - strcat( baseDir, initialDir ); - initialDir = baseDir; - } - - theApp.szFile = _T(""); - - - FileDlg dlg( this, _T(""), filter, selectedFilter, _T(""), exts, theApp.dir, title, false); - - if( dlg.DoModal() == IDOK ) { - if( system == 0 ) { - regSetDwordValue( _T("selectedFilter"), dlg.m_ofn.nFilterIndex ); - } - theApp.szFile = dlg.GetPathName(); - theApp.dir = theApp.szFile.Left( dlg.m_ofn.nFileOffset ); - if( (theApp.dir.GetLength() > 3) && (theApp.dir[theApp.dir.GetLength()-1] == _T('\\')) ) { - theApp.dir = theApp.dir.Left( theApp.dir.GetLength() - 1 ); - } - SetCurrentDirectory( theApp.dir ); - return true; - } - return false; -} - - -void MainWnd::OnPaint() -{ - CPaintDC dc(this); // device context for painting - - if(emulating) { - theApp.painting = true; - systemDrawScreen(); - theApp.painting = false; - theApp.renderedFrames--; - } -} - -BOOL MainWnd::PreTranslateMessage(MSG* pMsg) -{ - if (CWnd::PreTranslateMessage(pMsg)) - return TRUE; - - if(pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) { - return theApp.hAccel != NULL && ::TranslateAccelerator(m_hWnd, theApp.hAccel, pMsg); - } - - return FALSE; -} - -void MainWnd::screenCapture(int captureNumber) -{ - CString buffer; - - CString captureDir = regQueryStringValue("captureDir", ""); - if( captureDir[0] == '.' ) { - // handle as relative path - char baseDir[MAX_PATH+1]; - GetModuleFileName( NULL, baseDir, MAX_PATH ); - baseDir[MAX_PATH] = '\0'; // for security reasons - PathRemoveFileSpec( baseDir ); // removes the trailing file name and backslash - strcat( baseDir, "\\" ); - strcat( baseDir, captureDir ); - captureDir = baseDir; - } - int index = theApp.filename.ReverseFind('\\'); - - CString name; - if(index != -1) - name = theApp.filename.Right(theApp.filename.GetLength()-index-1); - else - name = theApp.filename; - - if(captureDir.IsEmpty()) - captureDir = getDirFromFile(theApp.filename); - - LPCTSTR ext = "png"; - if(theApp.captureFormat != 0) - ext = "bmp"; - - if(isDriveRoot(captureDir)) - buffer.Format("%s%s_%02d.%s", - captureDir, - name, - captureNumber, - ext); - else - buffer.Format("%s\\%s_%02d.%s", - captureDir, - name, - captureNumber, - ext); - - // check if file exists - DWORD dwAttr = GetFileAttributes( buffer ); - if( dwAttr != INVALID_FILE_ATTRIBUTES ) { - // screenshot file already exists - screenCapture(++captureNumber); - // this will recursively use the first non-existent screenshot number - return; - } - - if(theApp.captureFormat == 0) - theApp.emulator.emuWritePNG(buffer); - else - theApp.emulator.emuWriteBMP(buffer); - - CString msg = winResLoadString(IDS_SCREEN_CAPTURE); - systemScreenMessage(msg); -} - -void MainWnd::winMouseOn() -{ - SetCursor(arrow); - if(theApp.videoOption > VIDEO_4X) { - theApp.mouseCounter = 10; - } else - theApp.mouseCounter = 0; -} - -void MainWnd::OnMouseMove(UINT nFlags, CPoint point) -{ - winMouseOn(); - - CWnd::OnMouseMove(nFlags, point); -} - -void MainWnd::OnInitMenu(CMenu* pMenu) -{ - CWnd::OnInitMenu(pMenu); - - soundPause(); -} - -void MainWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) -{ - CWnd::OnActivate(nState, pWndOther, bMinimized); - - bool a = (nState == WA_ACTIVE) || (nState == WA_CLICKACTIVE); - - if(a && theApp.input) { - theApp.active = a; - theApp.input->activate(); - if(!theApp.paused && emulating) { - soundResume(); - } - } else { - theApp.wasPaused = true; - if(theApp.pauseWhenInactive) { - if(emulating) { - soundPause(); - } - theApp.active = a; - } - - memset(theApp.delta,255,sizeof(theApp.delta)); - } - - if(theApp.paused && emulating) - { - theApp.painting = true; - systemDrawScreen(); - theApp.painting = false; - theApp.renderedFrames--; - } -} - -void MainWnd::OnDropFiles(HDROP hDropInfo) -{ - char szFile[1024]; - - if(DragQueryFile(hDropInfo, - 0, - szFile, - 1024)) { - theApp.szFile = szFile; - if(FileRun()) { - SetForegroundWindow(); - emulating = TRUE; - } else { - emulating = FALSE; - soundPause(); - } - } - DragFinish(hDropInfo); -} - -LRESULT MainWnd::OnMySysCommand(WPARAM wParam, LPARAM lParam) -{ - if(emulating && !theApp.paused) { - if((wParam&0xFFF0) == SC_SCREENSAVE || (wParam&0xFFF0) == SC_MONITORPOWER) - return 0; - } - return Default(); -} - -void MainWnd::OnNcLButtonDown(UINT nHitTest, CPoint point) -{ - // pause sound before process is halted - if( emulating ) { - soundPause(); - } - - CWnd::OnNcLButtonDown(nHitTest, point); -} - -void MainWnd::OnWindowPosChanging(WINDOWPOS* lpwndpos) -{ - CWnd::OnWindowPosChanging(lpwndpos); - - // pause sound before changing window position/size - if( emulating ) { - soundPause(); - } -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +// MainWnd.cpp : implementation file +// + +#include "stdafx.h" +#include "VBA.h" +#include "MainWnd.h" + +#include +#include + +#include "FileDlg.h" +#include "Reg.h" +#include "WinResUtil.h" +#include "Logging.h" + +#include "../System.h" +#include "../AutoBuild.h" +#include "../cheatSearch.h" +#include "../agb/GBA.h" +#include "../Globals.h" +#include "../Flash.h" +#include "../Globals.h" +#include "../dmg/GB.h" +#include "../dmg/gbCheats.h" +#include "../dmg/gbGlobals.h" +#include "../RTC.h" +#include "../Sound.h" +#include "../Util.h" +#include "../agb/GBALink.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +extern void remoteCleanUp(); +extern int gbHardware; + +///////////////////////////////////////////////////////////////////////////// +// MainWnd + +MainWnd::MainWnd() +{ + m_hAccelTable = NULL; + arrow = LoadCursor(NULL, IDC_ARROW); +} + +MainWnd::~MainWnd() +{ +} + + +BEGIN_MESSAGE_MAP(MainWnd, CWnd) + //{{AFX_MSG_MAP(MainWnd) + ON_WM_CLOSE() + ON_COMMAND(ID_HELP_ABOUT, OnHelpAbout) + ON_COMMAND(ID_HELP_FAQ, OnHelpFaq) + ON_COMMAND(ID_FILE_OPEN, OnFileOpen) + ON_WM_INITMENUPOPUP() + ON_COMMAND(ID_FILE_PAUSE, OnFilePause) + ON_UPDATE_COMMAND_UI(ID_FILE_PAUSE, OnUpdateFilePause) + ON_COMMAND(ID_FILE_RESET, OnFileReset) + ON_UPDATE_COMMAND_UI(ID_FILE_RESET, OnUpdateFileReset) + ON_UPDATE_COMMAND_UI(ID_FILE_RECENT_FREEZE, OnUpdateFileRecentFreeze) + ON_COMMAND(ID_FILE_RECENT_RESET, OnFileRecentReset) + ON_COMMAND(ID_FILE_RECENT_FREEZE, OnFileRecentFreeze) + ON_COMMAND(ID_FILE_EXIT, OnFileExit) + ON_COMMAND(ID_FILE_CLOSE, OnFileClose) + ON_UPDATE_COMMAND_UI(ID_FILE_CLOSE, OnUpdateFileClose) + ON_COMMAND(ID_FILE_OPENGAMEBOY, OnFileOpengameboy) + ON_COMMAND(ID_FILE_LOAD, OnFileLoad) + ON_UPDATE_COMMAND_UI(ID_FILE_LOAD, OnUpdateFileLoad) + ON_COMMAND(ID_FILE_SAVE, OnFileSave) + ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave) + ON_COMMAND(ID_FILE_IMPORT_BATTERYFILE, OnFileImportBatteryfile) + ON_UPDATE_COMMAND_UI(ID_FILE_IMPORT_BATTERYFILE, OnUpdateFileImportBatteryfile) + ON_COMMAND(ID_FILE_IMPORT_GAMESHARKCODEFILE, OnFileImportGamesharkcodefile) + ON_UPDATE_COMMAND_UI(ID_FILE_IMPORT_GAMESHARKCODEFILE, OnUpdateFileImportGamesharkcodefile) + ON_COMMAND(ID_FILE_IMPORT_GAMESHARKSNAPSHOT, OnFileImportGamesharksnapshot) + ON_UPDATE_COMMAND_UI(ID_FILE_IMPORT_GAMESHARKSNAPSHOT, OnUpdateFileImportGamesharksnapshot) + ON_COMMAND(ID_FILE_EXPORT_BATTERYFILE, OnFileExportBatteryfile) + ON_UPDATE_COMMAND_UI(ID_FILE_EXPORT_BATTERYFILE, OnUpdateFileExportBatteryfile) + ON_COMMAND(ID_FILE_EXPORT_GAMESHARKSNAPSHOT, OnFileExportGamesharksnapshot) + ON_UPDATE_COMMAND_UI(ID_FILE_EXPORT_GAMESHARKSNAPSHOT, OnUpdateFileExportGamesharksnapshot) + ON_COMMAND(ID_FILE_SCREENCAPTURE, OnFileScreencapture) + ON_UPDATE_COMMAND_UI(ID_FILE_SCREENCAPTURE, OnUpdateFileScreencapture) + ON_COMMAND(ID_FILE_ROMINFORMATION, OnFileRominformation) + ON_UPDATE_COMMAND_UI(ID_FILE_ROMINFORMATION, OnUpdateFileRominformation) + ON_COMMAND(ID_FILE_TOGGLEMENU, OnFileTogglemenu) + ON_UPDATE_COMMAND_UI(ID_FILE_TOGGLEMENU, OnUpdateFileTogglemenu) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_NOTHROTTLE, OnUpdateOptionsFrameskipThrottleNothrottle) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_25, OnUpdateOptionsFrameskipThrottle25) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_50, OnUpdateOptionsFrameskipThrottle50) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_100, OnUpdateOptionsFrameskipThrottle100) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_150, OnUpdateOptionsFrameskipThrottle150) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_200, OnUpdateOptionsFrameskipThrottle200) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FRAMESKIP_THROTTLE_OTHER, OnUpdateOptionsFrameskipThrottleOther) + ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_NOTHROTTLE, OnOptionsFrameskipThrottleNothrottle) + ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_25, OnOptionsFrameskipThrottle25) + ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_50, OnOptionsFrameskipThrottle50) + ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_100, OnOptionsFrameskipThrottle100) + ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_150, OnOptionsFrameskipThrottle150) + ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_200, OnOptionsFrameskipThrottle200) + ON_COMMAND(ID_OPTIONS_FRAMESKIP_THROTTLE_OTHER, OnOptionsFrameskipThrottleOther) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_0, OnUpdateOptionsVideoFrameskip0) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_1, OnUpdateOptionsVideoFrameskip1) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_2, OnUpdateOptionsVideoFrameskip2) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_3, OnUpdateOptionsVideoFrameskip3) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_4, OnUpdateOptionsVideoFrameskip4) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_5, OnUpdateOptionsVideoFrameskip5) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_6, OnUpdateOptionsVideoFrameskip6) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_7, OnUpdateOptionsVideoFrameskip7) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_8, OnUpdateOptionsVideoFrameskip8) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FRAMESKIP_9, OnUpdateOptionsVideoFrameskip9) + ON_COMMAND(ID_OPTIONS_VIDEO_VSYNC, OnOptionsVideoVsync) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_VSYNC, OnUpdateOptionsVideoVsync) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_X1, OnUpdateOptionsVideoX1) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_X2, OnUpdateOptionsVideoX2) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_X3, OnUpdateOptionsVideoX3) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_X4, OnUpdateOptionsVideoX4) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREEN320X240, OnUpdateOptionsVideoFullscreen320x240) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREEN640X480, OnUpdateOptionsVideoFullscreen640x480) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREEN800X600, OnUpdateOptionsVideoFullscreen800x600) + ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREEN320X240, OnOptionsVideoFullscreen320x240) + ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREEN640X480, OnOptionsVideoFullscreen640x480) + ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREEN800X600, OnOptionsVideoFullscreen800x600) + ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREEN, OnOptionsVideoFullscreen) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREEN, OnUpdateOptionsVideoFullscreen) + ON_WM_MOVING() + ON_WM_MOVE() + ON_WM_SIZING() + ON_WM_SIZE() + ON_COMMAND(ID_OPTIONS_VIDEO_DISABLESFX, OnOptionsVideoDisablesfx) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_DISABLESFX, OnUpdateOptionsVideoDisablesfx) + ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREENSTRETCHTOFIT, OnOptionsVideoFullscreenstretchtofit) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREENSTRETCHTOFIT, OnUpdateOptionsVideoFullscreenstretchtofit) + ON_COMMAND(ID_OPTIONS_VIDEO_RENDERMETHOD_DIRECT3D, OnOptionsVideoRendermethodDirect3d) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDERMETHOD_DIRECT3D, OnUpdateOptionsVideoRendermethodDirect3d) + ON_COMMAND(ID_OPTIONS_VIDEO_RENDERMETHOD_OPENGL, OnOptionsVideoRendermethodOpengl) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDERMETHOD_OPENGL, OnUpdateOptionsVideoRendermethodOpengl) + ON_COMMAND(ID_OPTIONS_VIDEO_TRIPLEBUFFERING, OnOptionsVideoTriplebuffering) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_TRIPLEBUFFERING, OnUpdateOptionsVideoTriplebuffering) + ON_COMMAND(ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DNOFILTER, OnOptionsVideoRenderoptionsD3dnofilter) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DNOFILTER, OnUpdateOptionsVideoRenderoptionsD3dnofilter) + ON_COMMAND(ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DBILINEAR, OnOptionsVideoRenderoptionsD3dbilinear) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DBILINEAR, OnUpdateOptionsVideoRenderoptionsD3dbilinear) + ON_COMMAND(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLNEAREST, OnOptionsVideoRenderoptionsGlnearest) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLNEAREST, OnUpdateOptionsVideoRenderoptionsGlnearest) + ON_COMMAND(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLBILINEAR, OnOptionsVideoRenderoptionsGlbilinear) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLBILINEAR, OnUpdateOptionsVideoRenderoptionsGlbilinear) + + ON_WM_CONTEXTMENU() + ON_COMMAND(ID_OPTIONS_EMULATOR_ASSOCIATE, OnOptionsEmulatorAssociate) + ON_COMMAND(ID_OPTIONS_EMULATOR_DIRECTORIES, OnOptionsEmulatorDirectories) + ON_COMMAND(ID_OPTIONS_EMULATOR_DISABLESTATUSMESSAGES, OnOptionsEmulatorDisablestatusmessages) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_DISABLESTATUSMESSAGES, OnUpdateOptionsEmulatorDisablestatusmessages) + ON_COMMAND(ID_OPTIONS_EMULATOR_SYNCHRONIZE, OnOptionsEmulatorSynchronize) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SYNCHRONIZE, OnUpdateOptionsEmulatorSynchronize) + ON_COMMAND(ID_OPTIONS_EMULATOR_PAUSEWHENINACTIVE, OnOptionsEmulatorPausewheninactive) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_PAUSEWHENINACTIVE, OnUpdateOptionsEmulatorPausewheninactive) + ON_COMMAND(ID_OPTIONS_EMULATOR_SPEEDUPTOGGLE, OnOptionsEmulatorSpeeduptoggle) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SPEEDUPTOGGLE, OnUpdateOptionsEmulatorSpeeduptoggle) + ON_COMMAND(ID_OPTIONS_EMULATOR_AUTOMATICALLYIPSPATCH, OnOptionsEmulatorAutomaticallyipspatch) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_AUTOMATICALLYIPSPATCH, OnUpdateOptionsEmulatorAutomaticallyipspatch) + ON_COMMAND(ID_OPTIONS_EMULATOR_AGBPRINT, OnOptionsEmulatorAgbprint) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_AGBPRINT, OnUpdateOptionsEmulatorAgbprint) + ON_COMMAND(ID_OPTIONS_EMULATOR_REALTIMECLOCK, OnOptionsEmulatorRealtimeclock) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_REALTIMECLOCK, OnUpdateOptionsEmulatorRealtimeclock) + ON_COMMAND(ID_OPTIONS_EMULATOR_GENERICFLASHCARD, OnOptionsEmulatorGenericflashcard) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_GENERICFLASHCARD, OnUpdateOptionsEmulatorGenericflashcard) + ON_COMMAND(ID_OPTIONS_EMULATOR_REWINDINTERVAL, OnOptionsEmulatorRewindinterval) + ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_AUTOMATIC, OnOptionsEmulatorSavetypeAutomatic) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_AUTOMATIC, OnUpdateOptionsEmulatorSavetypeAutomatic) + ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_EEPROM, OnOptionsEmulatorSavetypeEeprom) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_EEPROM, OnUpdateOptionsEmulatorSavetypeEeprom) + ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_SRAM, OnOptionsEmulatorSavetypeSram) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_SRAM, OnUpdateOptionsEmulatorSavetypeSram) + ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_FLASH, OnOptionsEmulatorSavetypeFlash) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_FLASH, OnUpdateOptionsEmulatorSavetypeFlash) + ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_EEPROMSENSOR, OnOptionsEmulatorSavetypeEepromsensor) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_EEPROMSENSOR, OnUpdateOptionsEmulatorSavetypeEepromsensor) + ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_NONE, OnOptionsEmulatorSavetypeNone) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_NONE, OnUpdateOptionsEmulatorSavetypeNone) + ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_FLASH512K, OnOptionsEmulatorSavetypeFlash512k) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_FLASH512K, OnUpdateOptionsEmulatorSavetypeFlash512k) + ON_COMMAND(ID_OPTIONS_EMULATOR_SAVETYPE_FLASH1M, OnOptionsEmulatorSavetypeFlash1m) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_SAVETYPE_FLASH1M, OnUpdateOptionsEmulatorSavetypeFlash1m) + ON_COMMAND(ID_OPTIONS_EMULATOR_PNGFORMAT, OnOptionsEmulatorPngformat) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_PNGFORMAT, OnUpdateOptionsEmulatorPngformat) + ON_COMMAND(ID_OPTIONS_EMULATOR_BMPFORMAT, OnOptionsEmulatorBmpformat) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_BMPFORMAT, OnUpdateOptionsEmulatorBmpformat) + ON_COMMAND(ID_OPTIONS_SOUND_OFF, OnOptionsSoundOff) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_OFF, OnUpdateOptionsSoundOff) + ON_COMMAND(ID_OPTIONS_SOUND_MUTE, OnOptionsSoundMute) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_MUTE, OnUpdateOptionsSoundMute) + ON_COMMAND(ID_OPTIONS_SOUND_ON, OnOptionsSoundOn) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_ON, OnUpdateOptionsSoundOn) + ON_COMMAND(ID_OPTIONS_SOUND_ECHO, OnOptionsSoundEcho) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_ECHO, OnUpdateOptionsSoundEcho) + ON_COMMAND(ID_OPTIONS_SOUND_LOWPASSFILTER, OnOptionsSoundLowpassfilter) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_LOWPASSFILTER, OnUpdateOptionsSoundLowpassfilter) + ON_COMMAND(ID_OPTIONS_SOUND_REVERSESTEREO, OnOptionsSoundReversestereo) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_REVERSESTEREO, OnUpdateOptionsSoundReversestereo) + ON_COMMAND(ID_OPTIONS_SOUND_11KHZ, OnOptionsSound11khz) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_11KHZ, OnUpdateOptionsSound11khz) + ON_COMMAND(ID_OPTIONS_SOUND_22KHZ, OnOptionsSound22khz) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_22KHZ, OnUpdateOptionsSound22khz) + ON_COMMAND(ID_OPTIONS_SOUND_44KHZ, OnOptionsSound44khz) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_44KHZ, OnUpdateOptionsSound44khz) + ON_COMMAND(ID_OPTIONS_SOUND_CHANNEL1, OnOptionsSoundChannel1) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_CHANNEL1, OnUpdateOptionsSoundChannel1) + ON_COMMAND(ID_OPTIONS_SOUND_CHANNEL2, OnOptionsSoundChannel2) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_CHANNEL2, OnUpdateOptionsSoundChannel2) + ON_COMMAND(ID_OPTIONS_SOUND_CHANNEL3, OnOptionsSoundChannel3) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_CHANNEL3, OnUpdateOptionsSoundChannel3) + ON_COMMAND(ID_OPTIONS_SOUND_CHANNEL4, OnOptionsSoundChannel4) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_CHANNEL4, OnUpdateOptionsSoundChannel4) + ON_COMMAND(ID_OPTIONS_SOUND_DIRECTSOUNDA, OnOptionsSoundDirectsounda) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_DIRECTSOUNDA, OnUpdateOptionsSoundDirectsounda) + ON_COMMAND(ID_OPTIONS_SOUND_DIRECTSOUNDB, OnOptionsSoundDirectsoundb) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_DIRECTSOUNDB, OnUpdateOptionsSoundDirectsoundb) + ON_COMMAND(ID_OPTIONS_GAMEBOY_BORDER, OnOptionsGameboyBorder) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_BORDER, OnUpdateOptionsGameboyBorder) + ON_COMMAND(ID_OPTIONS_GAMEBOY_PRINTER, OnOptionsGameboyPrinter) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_PRINTER, OnUpdateOptionsGameboyPrinter) + ON_COMMAND(ID_OPTIONS_GAMEBOY_BORDERAUTOMATIC, OnOptionsGameboyBorderAutomatic) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_BORDERAUTOMATIC, OnUpdateOptionsGameboyBorderAutomatic) + ON_COMMAND(ID_OPTIONS_GAMEBOY_AUTOMATIC, OnOptionsGameboyAutomatic) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_AUTOMATIC, OnUpdateOptionsGameboyAutomatic) + ON_COMMAND(ID_OPTIONS_GAMEBOY_GBA, OnOptionsGameboyGba) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_GBA, OnUpdateOptionsGameboyGba) + ON_COMMAND(ID_OPTIONS_GAMEBOY_CGB, OnOptionsGameboyCgb) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_CGB, OnUpdateOptionsGameboyCgb) + ON_COMMAND(ID_OPTIONS_GAMEBOY_SGB, OnOptionsGameboySgb) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_SGB, OnUpdateOptionsGameboySgb) + ON_COMMAND(ID_OPTIONS_GAMEBOY_SGB2, OnOptionsGameboySgb2) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_SGB2, OnUpdateOptionsGameboySgb2) + ON_COMMAND(ID_OPTIONS_GAMEBOY_GB, OnOptionsGameboyGb) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_GB, OnUpdateOptionsGameboyGb) + ON_COMMAND(ID_OPTIONS_GAMEBOY_REALCOLORS, OnOptionsGameboyRealcolors) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_REALCOLORS, OnUpdateOptionsGameboyRealcolors) + ON_COMMAND(ID_OPTIONS_GAMEBOY_GAMEBOYCOLORS, OnOptionsGameboyGameboycolors) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_GAMEBOY_GAMEBOYCOLORS, OnUpdateOptionsGameboyGameboycolors) + ON_COMMAND(ID_OPTIONS_GAMEBOY_COLORS, OnOptionsGameboyColors) + ON_COMMAND(ID_OPTIONS_FILTER_DISABLEMMX, OnOptionsFilterDisablemmx) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FILTER_DISABLEMMX, OnUpdateOptionsFilterDisablemmx) + ON_COMMAND(ID_OPTIONS_LANGUAGE_SYSTEM, OnOptionsLanguageSystem) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_LANGUAGE_SYSTEM, OnUpdateOptionsLanguageSystem) + ON_COMMAND(ID_OPTIONS_LANGUAGE_ENGLISH, OnOptionsLanguageEnglish) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_LANGUAGE_ENGLISH, OnUpdateOptionsLanguageEnglish) + ON_COMMAND(ID_OPTIONS_LANGUAGE_OTHER, OnOptionsLanguageOther) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_LANGUAGE_OTHER, OnUpdateOptionsLanguageOther) + ON_COMMAND(ID_OPTIONS_JOYPAD_CONFIGURE_1, OnOptionsJoypadConfigure1) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_JOYPAD_CONFIGURE_1, OnUpdateOptionsJoypadConfigure1) + ON_COMMAND(ID_OPTIONS_JOYPAD_CONFIGURE_2, OnOptionsJoypadConfigure2) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_JOYPAD_CONFIGURE_2, OnUpdateOptionsJoypadConfigure2) + ON_COMMAND(ID_OPTIONS_JOYPAD_CONFIGURE_3, OnOptionsJoypadConfigure3) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_JOYPAD_CONFIGURE_3, OnUpdateOptionsJoypadConfigure3) + ON_COMMAND(ID_OPTIONS_JOYPAD_CONFIGURE_4, OnOptionsJoypadConfigure4) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_JOYPAD_CONFIGURE_4, OnUpdateOptionsJoypadConfigure4) + ON_COMMAND(ID_OPTIONS_JOYPAD_MOTIONCONFIGURE, OnOptionsJoypadMotionconfigure) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_JOYPAD_MOTIONCONFIGURE, OnUpdateOptionsJoypadMotionconfigure) + ON_COMMAND(ID_CHEATS_SEARCHFORCHEATS, OnCheatsSearchforcheats) + ON_UPDATE_COMMAND_UI(ID_CHEATS_SEARCHFORCHEATS, OnUpdateCheatsSearchforcheats) + ON_COMMAND(ID_CHEATS_CHEATLIST, OnCheatsCheatlist) + ON_UPDATE_COMMAND_UI(ID_CHEATS_CHEATLIST, OnUpdateCheatsCheatlist) + ON_COMMAND(ID_CHEATS_AUTOMATICSAVELOADCHEATS, OnCheatsAutomaticsaveloadcheats) + ON_COMMAND(ID_CHEATS_LOADCHEATLIST, OnCheatsLoadcheatlist) + ON_UPDATE_COMMAND_UI(ID_CHEATS_LOADCHEATLIST, OnUpdateCheatsLoadcheatlist) + ON_COMMAND(ID_CHEATS_SAVECHEATLIST, OnCheatsSavecheatlist) + ON_UPDATE_COMMAND_UI(ID_CHEATS_SAVECHEATLIST, OnUpdateCheatsSavecheatlist) + ON_COMMAND(ID_TOOLS_DISASSEMBLE, OnToolsDisassemble) + ON_UPDATE_COMMAND_UI(ID_TOOLS_DISASSEMBLE, OnUpdateToolsDisassemble) + ON_COMMAND(ID_TOOLS_LOGGING, OnToolsLogging) + ON_UPDATE_COMMAND_UI(ID_TOOLS_LOGGING, OnUpdateToolsLogging) + ON_COMMAND(ID_TOOLS_IOVIEWER, OnToolsIoviewer) + ON_UPDATE_COMMAND_UI(ID_TOOLS_IOVIEWER, OnUpdateToolsIoviewer) + ON_COMMAND(ID_TOOLS_MAPVIEW, OnToolsMapview) + ON_UPDATE_COMMAND_UI(ID_TOOLS_MAPVIEW, OnUpdateToolsMapview) + ON_COMMAND(ID_TOOLS_MEMORYVIEWER, OnToolsMemoryviewer) + ON_UPDATE_COMMAND_UI(ID_TOOLS_MEMORYVIEWER, OnUpdateToolsMemoryviewer) + ON_COMMAND(ID_TOOLS_OAMVIEWER, OnToolsOamviewer) + ON_UPDATE_COMMAND_UI(ID_TOOLS_OAMVIEWER, OnUpdateToolsOamviewer) + ON_COMMAND(ID_TOOLS_PALETTEVIEW, OnToolsPaletteview) + ON_UPDATE_COMMAND_UI(ID_TOOLS_PALETTEVIEW, OnUpdateToolsPaletteview) + ON_COMMAND(ID_TOOLS_TILEVIEWER, OnToolsTileviewer) + ON_UPDATE_COMMAND_UI(ID_TOOLS_TILEVIEWER, OnUpdateToolsTileviewer) + ON_COMMAND(ID_DEBUG_NEXTFRAME, OnDebugNextframe) + ON_UPDATE_COMMAND_UI(ID_CHEATS_AUTOMATICSAVELOADCHEATS, OnUpdateCheatsAutomaticsaveloadcheats) + ON_COMMAND(ID_TOOLS_DEBUG_GDB, OnToolsDebugGdb) + ON_UPDATE_COMMAND_UI(ID_TOOLS_DEBUG_GDB, OnUpdateToolsDebugGdb) + ON_COMMAND(ID_TOOLS_DEBUG_LOADANDWAIT, OnToolsDebugLoadandwait) + ON_UPDATE_COMMAND_UI(ID_TOOLS_DEBUG_LOADANDWAIT, OnUpdateToolsDebugLoadandwait) + ON_COMMAND(ID_TOOLS_DEBUG_BREAK, OnToolsDebugBreak) + ON_UPDATE_COMMAND_UI(ID_TOOLS_DEBUG_BREAK, OnUpdateToolsDebugBreak) + ON_COMMAND(ID_TOOLS_DEBUG_DISCONNECT, OnToolsDebugDisconnect) + ON_UPDATE_COMMAND_UI(ID_TOOLS_DEBUG_DISCONNECT, OnUpdateToolsDebugDisconnect) + ON_COMMAND(ID_OPTIONS_SOUND_STARTRECORDING, OnOptionsSoundStartrecording) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_STARTRECORDING, OnUpdateOptionsSoundStartrecording) + ON_COMMAND(ID_OPTIONS_SOUND_STOPRECORDING, OnOptionsSoundStoprecording) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_STOPRECORDING, OnUpdateOptionsSoundStoprecording) + ON_COMMAND(ID_TOOLS_RECORD_STARTAVIRECORDING, OnToolsRecordStartavirecording) + ON_UPDATE_COMMAND_UI(ID_TOOLS_RECORD_STARTAVIRECORDING, OnUpdateToolsRecordStartavirecording) + ON_COMMAND(ID_TOOLS_RECORD_STOPAVIRECORDING, OnToolsRecordStopavirecording) + ON_UPDATE_COMMAND_UI(ID_TOOLS_RECORD_STOPAVIRECORDING, OnUpdateToolsRecordStopavirecording) + ON_WM_PAINT() + ON_COMMAND(ID_TOOLS_RECORD_STARTMOVIERECORDING, OnToolsRecordStartmovierecording) + ON_UPDATE_COMMAND_UI(ID_TOOLS_RECORD_STARTMOVIERECORDING, OnUpdateToolsRecordStartmovierecording) + ON_COMMAND(ID_TOOLS_RECORD_STOPMOVIERECORDING, OnToolsRecordStopmovierecording) + ON_UPDATE_COMMAND_UI(ID_TOOLS_RECORD_STOPMOVIERECORDING, OnUpdateToolsRecordStopmovierecording) + ON_COMMAND(ID_TOOLS_PLAY_STARTMOVIEPLAYING, OnToolsPlayStartmovieplaying) + ON_UPDATE_COMMAND_UI(ID_TOOLS_PLAY_STARTMOVIEPLAYING, OnUpdateToolsPlayStartmovieplaying) + ON_COMMAND(ID_TOOLS_PLAY_STOPMOVIEPLAYING, OnToolsPlayStopmovieplaying) + ON_UPDATE_COMMAND_UI(ID_TOOLS_PLAY_STOPMOVIEPLAYING, OnUpdateToolsPlayStopmovieplaying) + ON_COMMAND(ID_TOOLS_REWIND, OnToolsRewind) + ON_UPDATE_COMMAND_UI(ID_TOOLS_REWIND, OnUpdateToolsRewind) + ON_COMMAND(ID_TOOLS_CUSTOMIZE, OnToolsCustomize) + ON_UPDATE_COMMAND_UI(ID_TOOLS_CUSTOMIZE, OnUpdateToolsCustomize) + ON_COMMAND(ID_HELP_BUGREPORT, OnHelpBugreport) + ON_WM_MOUSEMOVE() + ON_WM_INITMENU() + ON_WM_ACTIVATE() + ON_WM_DROPFILES() + ON_COMMAND(ID_FILE_SAVEGAME_OLDESTSLOT, OnFileSavegameOldestslot) + ON_UPDATE_COMMAND_UI(ID_FILE_SAVEGAME_OLDESTSLOT, OnUpdateFileSavegameOldestslot) + ON_COMMAND(ID_FILE_LOADGAME_MOSTRECENT, OnFileLoadgameMostrecent) + ON_UPDATE_COMMAND_UI(ID_FILE_LOADGAME_MOSTRECENT, OnUpdateFileLoadgameMostrecent) + ON_COMMAND(ID_FILE_LOADGAME_AUTOLOADMOSTRECENT, OnFileLoadgameAutoloadmostrecent) + ON_UPDATE_COMMAND_UI(ID_FILE_LOADGAME_AUTOLOADMOSTRECENT, OnUpdateFileLoadgameAutoloadmostrecent) + ON_COMMAND(ID_OPTIONS_SOUND_VOLUME_25X, OnOptionsSoundVolume25x) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_VOLUME_25X, OnUpdateOptionsSoundVolume25x) + ON_COMMAND(ID_OPTIONS_SOUND_VOLUME_5X, OnOptionsSoundVolume5x) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_VOLUME_5X, OnUpdateOptionsSoundVolume5x) + ON_COMMAND(ID_CHEATS_DISABLECHEATS, OnCheatsDisablecheats) + ON_UPDATE_COMMAND_UI(ID_CHEATS_DISABLECHEATS, OnUpdateCheatsDisablecheats) + ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREENMAXSCALE, OnOptionsVideoFullscreenmaxscale) + ON_COMMAND(ID_OPTIONS_EMULATOR_GAMEOVERRIDES, OnOptionsEmulatorGameoverrides) + ON_COMMAND(ID_OPTIONS_SELECT_PLUGIN, OnOptionsSelectPlugin) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_GAMEOVERRIDES, OnUpdateOptionsEmulatorGameoverrides) + ON_COMMAND(ID_HELP_GNUPUBLICLICENSE, OnHelpGnupubliclicense) + ON_COMMAND(ID_OPTIONS_LINK_OPTIONS, OnLinkOptions) + ON_COMMAND(ID_OPTIONS_LINK_LOG, OnOptionsLinkLog) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_LINK_LOG, OnUpdateOptionsLinkLog) + ON_COMMAND(ID_OPTIONS_LINK_WIRELESSADAPTER, OnOptionsLinkRFU) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_LINK_WIRELESSADAPTER, OnUpdateOptionsLinkRFU) + ON_COMMAND(ID_OPTIONS_LINK_ENABLE, OnOptionsLinkEnable) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_LINK_ENABLE, OnUpdateOptionsLinkEnable) + + //}}AFX_MSG_MAP + ON_COMMAND_EX_RANGE(ID_FILE_MRU_FILE1, ID_FILE_MRU_FILE10, OnFileRecentFile) + ON_COMMAND_EX_RANGE(ID_FILE_LOADGAME_SLOT1, ID_FILE_LOADGAME_SLOT10, OnFileLoadSlot) + ON_COMMAND_EX_RANGE(ID_FILE_SAVEGAME_SLOT1, ID_FILE_SAVEGAME_SLOT10, OnFileSaveSlot) + ON_UPDATE_COMMAND_UI_RANGE(ID_FILE_LOADGAME_SLOT1, ID_FILE_LOADGAME_SLOT10, OnUpdateFileLoadGameSlot) + ON_UPDATE_COMMAND_UI_RANGE(ID_FILE_SAVEGAME_SLOT1, ID_FILE_SAVEGAME_SLOT10, OnUpdateFileSaveGameSlot) + ON_COMMAND_EX_RANGE(ID_OPTIONS_VIDEO_FRAMESKIP_0, ID_OPTIONS_VIDEO_FRAMESKIP_5, OnOptionsFrameskip) + ON_COMMAND_EX_RANGE(ID_OPTIONS_VIDEO_FRAMESKIP_6, ID_OPTIONS_VIDEO_FRAMESKIP_9, OnOptionsFrameskip) + ON_COMMAND_EX_RANGE(ID_OPTIONS_VIDEO_X1, ID_OPTIONS_VIDEO_X4, OnOptionVideoSize) + ON_COMMAND_EX_RANGE(ID_OPTIONS_VIDEO_LAYERS_BG0, ID_OPTIONS_VIDEO_LAYERS_OBJWIN, OnVideoLayer) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_VIDEO_LAYERS_BG0, ID_OPTIONS_VIDEO_LAYERS_OBJWIN, OnUpdateVideoLayer) + ON_COMMAND(ID_SYSTEM_MINIMIZE, OnSystemMinimize) + ON_COMMAND_EX_RANGE(ID_OPTIONS_EMULATOR_SHOWSPEED_NONE, ID_OPTIONS_EMULATOR_SHOWSPEED_TRANSPARENT, OnOptionsEmulatorShowSpeed) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_EMULATOR_SHOWSPEED_NONE, ID_OPTIONS_EMULATOR_SHOWSPEED_TRANSPARENT, OnUpdateOptionsEmulatorShowSpeed) + ON_COMMAND_EX_RANGE(ID_OPTIONS_SOUND_VOLUME_1X, ID_OPTIONS_SOUND_VOLUME_4X, OnOptionsSoundVolume) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_SOUND_VOLUME_1X, ID_OPTIONS_SOUND_VOLUME_4X, OnUpdateOptionsSoundVolume) + ON_COMMAND_EX_RANGE(ID_OPTIONS_PRIORITY_HIGHEST, ID_OPTIONS_PRIORITY_BELOWNORMAL, OnOptionsPriority) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_PRIORITY_HIGHEST, ID_OPTIONS_PRIORITY_BELOWNORMAL, OnUpdateOptionsPriority) + ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER_NORMAL, ID_OPTIONS_FILTER_TVMODE, OnOptionsFilter) + ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER16BIT_PIXELATEEXPERIMENTAL, ID_OPTIONS_FILTER16BIT_MOTIONBLUREXPERIMENTAL, OnOptionsFilter) + ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER16BIT_ADVANCEMAMESCALE2X, ID_OPTIONS_FILTER16BIT_SIMPLE2X, OnOptionsFilter) + ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER_BILINEAR, ID_OPTIONS_FILTER_BILINEARPLUS, OnOptionsFilter) + ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER_SCANLINES, ID_OPTIONS_FILTER_SCANLINES, OnOptionsFilter) + ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER_HQ2X, ID_OPTIONS_FILTER_LQ2X, OnOptionsFilter) + ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER_PLUGIN, ID_OPTIONS_FILTER_PLUGIN, OnOptionsFilter) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER_PLUGIN, ID_OPTIONS_FILTER_PLUGIN, OnUpdateOptionsFilter) + ON_COMMAND_EX(ID_OPTIONS_FILTER_HQ3X, OnOptionsFilter) + ON_COMMAND_EX(ID_OPTIONS_FILTER_HQ4X, OnOptionsFilter) + ON_COMMAND_EX(ID_OPTIONS_FILTER_SIMPLE3X, OnOptionsFilter) + ON_COMMAND_EX(ID_OPTIONS_FILTER_SIMPLE4X, OnOptionsFilter) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER_NORMAL, ID_OPTIONS_FILTER_TVMODE, OnUpdateOptionsFilter) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER16BIT_PIXELATEEXPERIMENTAL, ID_OPTIONS_FILTER16BIT_MOTIONBLUREXPERIMENTAL, OnUpdateOptionsFilter) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER16BIT_ADVANCEMAMESCALE2X, ID_OPTIONS_FILTER16BIT_SIMPLE2X, OnUpdateOptionsFilter) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER_BILINEAR, ID_OPTIONS_FILTER_BILINEARPLUS, OnUpdateOptionsFilter) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER_SCANLINES, ID_OPTIONS_FILTER_SCANLINES, OnUpdateOptionsFilter) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER_HQ2X, ID_OPTIONS_FILTER_LQ2X, OnUpdateOptionsFilter) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FILTER_SIMPLE3X, OnUpdateOptionsFilter) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FILTER_SIMPLE4X, OnUpdateOptionsFilter) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FILTER_HQ3X, OnUpdateOptionsFilter) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FILTER_HQ4X, OnUpdateOptionsFilter) + ON_COMMAND_EX_RANGE(ID_OPTIONS_FILTER_INTERFRAMEBLENDING_NONE, ID_OPTIONS_FILTER_INTERFRAMEBLENDING_SMART, OnOptionsFilterIFB) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_FILTER_INTERFRAMEBLENDING_NONE, ID_OPTIONS_FILTER_INTERFRAMEBLENDING_SMART, OnUpdateOptionsFilterIFB) + ON_COMMAND_EX_RANGE(ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_1, ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_4, OnOptionsJoypadDefault) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_1, ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_4, OnUpdateOptionsJoypadDefault) + ON_COMMAND_EX_RANGE(ID_OPTIONS_JOYPAD_AUTOFIRE_A, ID_OPTIONS_JOYPAD_AUTOFIRE_R, OnOptionsJoypadAutofire) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_JOYPAD_AUTOFIRE_A, ID_OPTIONS_JOYPAD_AUTOFIRE_R, OnUpdateOptionsJoypadAutofire) + ON_MESSAGE(WM_SYSCOMMAND, OnMySysCommand) + ON_COMMAND(ID_OPTIONS_SOUND_HARDWAREACCELERATION, &MainWnd::OnOptionsSoundHardwareacceleration) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUND_HARDWAREACCELERATION, &MainWnd::OnUpdateOptionsSoundHardwareacceleration) + ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREEN1280X1024, OnOptionsVideoFullscreen1280x1024) + ON_COMMAND(ID_OPTIONS_VIDEO_FULLSCREEN1024X768, OnOptionsVideoFullscreen1024x768) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREEN1024X768, OnUpdateOptionsVideoFullscreen1024x768) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_FULLSCREEN1280X1024, OnUpdateOptionsVideoFullscreen1280x1024) + ON_COMMAND(ID_OPTIONS_FILTER_LCDCOLORS, OnOptionsFilterLcdcolors) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_FILTER_LCDCOLORS, OnUpdateOptionsFilterLcdcolors) + ON_COMMAND_EX_RANGE(ID_OPTIONS_SOUND_PCMINTERPOLATION_NONE, ID_OPTIONS_SOUND_PCMINTERPOLATION_LIBRESAMPLE, OnOptionsSoundPcminterpolation) + ON_UPDATE_COMMAND_UI_RANGE(ID_OPTIONS_SOUND_PCMINTERPOLATION_NONE, ID_OPTIONS_SOUND_PCMINTERPOLATION_LIBRESAMPLE, OnUpdateOptionsSoundPcminterpolation) + ON_COMMAND(ID_OUTPUTAPI_DIRECTSOUND, &MainWnd::OnOutputapiDirectsound) + ON_UPDATE_COMMAND_UI(ID_OUTPUTAPI_DIRECTSOUND, &MainWnd::OnUpdateOutputapiDirectsound) + ON_COMMAND(ID_OUTPUTAPI_OPENAL, &MainWnd::OnOutputapiOpenal) + ON_UPDATE_COMMAND_UI(ID_OUTPUTAPI_OPENAL, &MainWnd::OnUpdateOutputapiOpenal) + ON_COMMAND(ID_OUTPUTAPI_OALCONFIGURATION, &MainWnd::OnOutputapiOalconfiguration) + ON_UPDATE_COMMAND_UI(ID_OUTPUTAPI_OALCONFIGURATION, &MainWnd::OnUpdateOutputapiOalconfiguration) + ON_COMMAND(ID_RENDERAPI_D3DMOTIONBLUR, &MainWnd::OnRenderapiD3dmotionblur) + ON_UPDATE_COMMAND_UI(ID_RENDERAPI_D3DMOTIONBLUR, &MainWnd::OnUpdateRenderapiD3dmotionblur) + ON_WM_NCLBUTTONDOWN() + ON_WM_WINDOWPOSCHANGING() + ON_COMMAND(ID_EMULATOR_BIOSFILES, &MainWnd::OnEmulatorBiosfiles) + ON_COMMAND(ID_FILE_OPEN_GBC, &MainWnd::OnFileOpenGbc) + END_MESSAGE_MAP() + + + ///////////////////////////////////////////////////////////////////////////// +// MainWnd message handlers + +void MainWnd::OnClose() +{ + emulating = false; + CWnd::OnClose(); + + delete this; +} + +bool MainWnd::FileRun() +{ + // save battery file before we change the filename... + if(rom != NULL || gbRom != NULL) { + if(theApp.autoSaveLoadCheatList) + winSaveCheatListDefault(); + writeBatteryFile(); + cheatSearchCleanup(&cheatSearchData); + theApp.emulator.emuCleanUp(); + remoteCleanUp(); + emulating = false; +#ifdef APU_LOGGER_H + end_apu_log(); +#endif + } + char tempName[2048]; + char file[2048]; + CString oldFile = theApp.filename; + + utilStripDoubleExtension(theApp.szFile, tempName); + + _fullpath(file, tempName, 2048); + theApp.filename = file; + + int index = theApp.filename.ReverseFind('.'); + if(index != -1) + theApp.filename = theApp.filename.Left(index); + + if( theApp.filename != oldFile ) { + // clear cheat list when another game is loaded + cheatsDeleteAll( false ); + gbCheatRemoveAll(); + } + + CString ipsname; + ipsname.Format("%s.ips", theApp.filename); + + if(!theApp.dir.GetLength()) { + int index = theApp.filename.ReverseFind('\\'); + if(index != -1) { + theApp.dir = theApp.filename.Left(index-1); + } + } + + IMAGE_TYPE type = utilFindType(theApp.szFile); + + if(type == IMAGE_UNKNOWN) { + systemMessage(IDS_UNSUPPORTED_FILE_TYPE, + "Unsupported file type: %s", theApp.szFile); + return false; + } + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + theApp.cartridgeType = type; + if(type == IMAGE_GB) { + genericflashcardEnable = theApp.winGenericflashcardEnable; + + + if(!gbLoadRom(theApp.szFile)) + return false; + + gbGetHardwareType(); + + // used for the handling of the gb Boot Rom + if (gbHardware & 5) + { + skipBios = theApp.skipBiosFile; + gbCPUInit(theApp.biosFileNameGB, theApp.useBiosFileGB); + } + + + + gbReset(); + theApp.emulator = GBSystem; + gbBorderOn = theApp.winGbBorderOn; + theApp.romSize = gbRomSize; + + + if(theApp.autoIPS) { + int size = gbRomSize; + utilApplyIPS(ipsname, &gbRom, &size); + if(size != gbRomSize) { + extern bool gbUpdateSizes(); + gbUpdateSizes(); + gbReset(); + theApp.romSize = size; + } + } + } else { + int size = CPULoadRom(theApp.szFile); + if(!size) + return false; + + theApp.romSize = size; + + flashSetSize(theApp.winFlashSize); + rtcEnable(theApp.winRtcEnable); + cpuSaveType = theApp.winSaveType; + + GetModuleFileName(NULL, tempName, 2048); + + char *p = strrchr(tempName, '\\'); + if(p) + *p = 0; + + char buffer[5]; + strncpy(buffer, (const char *)&rom[0xac], 4); + buffer[4] = 0; + + strcat(tempName, "\\vba-over.ini"); + + UINT i = GetPrivateProfileInt(buffer, + "rtcEnabled", + -1, + tempName); + if(i != (UINT)-1) + rtcEnable(i == 0 ? false : true); + + i = GetPrivateProfileInt(buffer, + "flashSize", + -1, + tempName); + if(i != (UINT)-1 && (i == 0x10000 || i == 0x20000)) + flashSetSize((int)i); + + i = GetPrivateProfileInt(buffer, + "saveType", + -1, + tempName); + if(i != (UINT)-1 && (i <= 5)) + cpuSaveType = (int)i; + i = GetPrivateProfileInt(buffer, + "mirroringEnabled", + -1, + tempName); + if(i != (UINT)-1) + doMirroring (i == 0 ? false : true); + + theApp.emulator = GBASystem; + /* disabled due to problems + if(theApp.removeIntros && rom != NULL) { + *((u32 *)rom)= 0xea00002e; + } + */ + + if(theApp.autoIPS) { + int size = 0x2000000; + utilApplyIPS(ipsname, &rom, &size); + if(size != 0x2000000) { + CPUReset(); + } + } + } + + if(theApp.soundInitialized) { + if(theApp.cartridgeType == 1) + gbSoundReset(); + else + soundReset(); + } else { + if(!soundOffFlag) + soundInit(); + theApp.soundInitialized = true; + } + +#ifdef APU_LOGGER_H + begin_apu_log("apu_log.txt"); +#endif + + if(type == IMAGE_GBA) { + skipBios = theApp.skipBiosFile; + CPUInit(theApp.biosFileNameGBA.GetString(), theApp.useBiosFileGBA); + CPUReset(); + } + + readBatteryFile(); + + if(theApp.autoSaveLoadCheatList) + winLoadCheatListDefault(); + + theApp.addRecentFile(theApp.szFile); + + theApp.updateWindowSize(theApp.videoOption); + + theApp.updateFrameSkip(); + + emulating = true; + + if(theApp.autoLoadMostRecent) + OnFileLoadgameMostrecent(); + + theApp.frameskipadjust = 0; + theApp.renderedFrames = 0; + theApp.autoFrameSkipLastTime = systemGetClock(); + + theApp.rewindCount = 0; + theApp.rewindCounter = 0; + theApp.rewindSaveNeeded = false; + + toolsClearLog(); + + return true; +} + +void MainWnd::OnInitMenuPopup(CMenu* pMenu, UINT nIndex, BOOL bSysMenu) +{ + ASSERT(pMenu != NULL); + + CCmdUI state; + state.m_pMenu = pMenu; + ASSERT(state.m_pOther == NULL); + ASSERT(state.m_pParentMenu == NULL); + + // determine if menu is popup in top-level menu and set m_pOther to + // it if so (m_pParentMenu == NULL indicates that it is secondary popup) + HMENU hParentMenu; + if (AfxGetThreadState()->m_hTrackingMenu == pMenu->m_hMenu) + state.m_pParentMenu = pMenu; // parent == child for tracking popup + else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL) { + CWnd* pParent = GetTopLevelParent(); + // child windows don't have menus -- need to go to the top! + if (pParent != NULL && + (hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL) { + int nIndexMax = ::GetMenuItemCount(hParentMenu); + for (int nIndex = 0; nIndex < nIndexMax; nIndex++) { + if (::GetSubMenu(hParentMenu, nIndex) == pMenu->m_hMenu) { + // when popup is found, m_pParentMenu is containing menu + state.m_pParentMenu = CMenu::FromHandle(hParentMenu); + break; + } + } + } + } + + state.m_nIndexMax = pMenu->GetMenuItemCount(); + for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; + state.m_nIndex++) { + state.m_nID = pMenu->GetMenuItemID(state.m_nIndex); + if (state.m_nID == 0) + continue; // menu separator or invalid cmd - ignore it + + ASSERT(state.m_pOther == NULL); + ASSERT(state.m_pMenu != NULL); + if (state.m_nID == (UINT)-1) { + // possibly a popup menu, route to first item of that popup + state.m_pSubMenu = pMenu->GetSubMenu(state.m_nIndex); + if (state.m_pSubMenu == NULL || + (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 || + state.m_nID == (UINT)-1) { + continue; // first item of popup can't be routed to + } + state.DoUpdate(this, FALSE); // popups are never auto disabled + } else { + // normal menu item + // Auto enable/disable if frame window has 'm_bAutoMenuEnable' + // set and command is _not_ a system command. + state.m_pSubMenu = NULL; + state.DoUpdate(this, state.m_nID < 0xF000); + } + + // adjust for menu deletions and additions + UINT nCount = pMenu->GetMenuItemCount(); + if (nCount < state.m_nIndexMax) { + state.m_nIndex -= (state.m_nIndexMax - nCount); + while (state.m_nIndex < nCount && + pMenu->GetMenuItemID(state.m_nIndex) == state.m_nID) { + state.m_nIndex++; + } + } + state.m_nIndexMax = nCount; + } +} + +void MainWnd::OnMoving(UINT fwSide, LPRECT pRect) +{ + CWnd::OnMoving(fwSide, pRect); + + if( emulating ) { + soundPause(); + } +} + +void MainWnd::OnMove(int x, int y) +{ + CWnd::OnMove(x, y); + + if(!theApp.changingVideoSize) { + if(this) { + if(!IsIconic()) { + RECT r; + + GetWindowRect(&r); + theApp.windowPositionX = r.left; + theApp.windowPositionY = r.top; + theApp.adjustDestRect(); + regSetDwordValue("windowX", theApp.windowPositionX); + regSetDwordValue("windowY", theApp.windowPositionY); + } + } + } +} + +void MainWnd::OnSizing(UINT fwSide, LPRECT pRect) +{ // the OnSizing event only occurs in windowed mode + CWnd::OnSizing(fwSide, pRect); + + // pause sound to prevent low sound buffers + if( emulating ) { + soundPause(); + } + + // maintain minimal window size + RECT size = { 0, 0, theApp.sizeX, theApp.sizeY }; + AdjustWindowRectEx( + &size, + WS_POPUP | WS_VISIBLE | WS_OVERLAPPEDWINDOW, + FALSE, + 0 ); + MENUBARINFO mbi; + mbi.cbSize = sizeof(MENUBARINFO); + this->GetMenuBarInfo( OBJID_MENU, 0, &mbi ); + const LONG menuHeight = mbi.rcBar.bottom - mbi.rcBar.top + 1; + // +1 because of that white line, wherever it comes from + const LONG width = size.right - size.left; + const LONG height = size.bottom - size.top + menuHeight; + if( ( pRect->right - pRect->left ) < width ) { + pRect->right = pRect->left + width; + } + if( ( pRect->bottom - pRect->top ) < height ) { + pRect->bottom = pRect->top + height; + } +} + +void MainWnd::OnSize(UINT nType, int cx, int cy) +{ + CWnd::OnSize(nType, cx, cy); + + bool redraw = ( ( cx < theApp.surfaceSizeX ) || ( cy < theApp.surfaceSizeY ) ); + + if(!theApp.changingVideoSize) { + if(this) { + if(!IsIconic()) { + if(theApp.iconic) { + if(emulating) { + soundResume(); + theApp.paused = false; + } + } + if(theApp.videoOption <= VIDEO_4X) { + theApp.surfaceSizeX = cx; + theApp.surfaceSizeY = cy; + theApp.adjustDestRect(); + if(theApp.display) + theApp.display->resize(theApp.dest.right-theApp.dest.left, theApp.dest.bottom-theApp.dest.top); + if( redraw && emulating ) { + theApp.painting = true; + systemDrawScreen(); + theApp.painting = false; + theApp.renderedFrames--; + } + } + } else { + if(emulating) { + if(!theApp.paused) { + theApp.paused = true; + soundPause(); + } + } + theApp.iconic = true; + } + } + } +} + +void MainWnd::winSaveCheatListDefault() +{ + CString name; + CString filename; + + int index = theApp.filename.ReverseFind('\\'); + + if(index != -1) + name = theApp.filename.Right(theApp.filename.GetLength()-index-1); + else + name = theApp.filename; + CString dir = regQueryStringValue("saveDir", NULL); + if( dir[0] == '.' ) { + // handle as relative path + char baseDir[MAX_PATH+1]; + GetModuleFileName( NULL, baseDir, MAX_PATH ); + baseDir[MAX_PATH] = '\0'; // for security reasons + PathRemoveFileSpec( baseDir ); // removes the trailing file name and backslash + strcat( baseDir, "\\" ); + strcat( baseDir, dir ); + dir = baseDir; + } + + if(!dir.GetLength()) + dir = getDirFromFile(filename); + + if(isDriveRoot(dir)) + filename.Format("%s%s.clt", dir, name); + else + filename.Format("%s\\%s.clt", dir, name); + + winSaveCheatList(filename); +} + +void MainWnd::winSaveCheatList(const char *name) +{ + if(theApp.cartridgeType == 0) + cheatsSaveCheatList(name); + else + gbCheatsSaveCheatList(name); +} + +void MainWnd::winLoadCheatListDefault() +{ + CString name; + CString filename; + + int index = theApp.filename.ReverseFind('\\'); + + if(index != -1) + name = theApp.filename.Right(theApp.filename.GetLength()-index-1); + else + name = theApp.filename; + CString dir = regQueryStringValue("saveDir", NULL); + if( dir[0] == '.' ) { + // handle as relative path + char baseDir[MAX_PATH+1]; + GetModuleFileName( NULL, baseDir, MAX_PATH ); + baseDir[MAX_PATH] = '\0'; // for security reasons + PathRemoveFileSpec( baseDir ); // removes the trailing file name and backslash + strcat( baseDir, "\\" ); + strcat( baseDir, dir ); + dir = baseDir; + } + + if(!dir.GetLength()) + dir = getDirFromFile(filename); + + if(isDriveRoot(dir)) + filename.Format("%s%s.clt", dir, name); + else + filename.Format("%s\\%s.clt", dir, name); + + winLoadCheatList(filename); +} + +void MainWnd::winLoadCheatList(const char *name) +{ + bool res = false; + + if(theApp.cartridgeType == 0) + res = cheatsLoadCheatList(name); + else + res = gbCheatsLoadCheatList(name); + + if(res) + systemScreenMessage(winResLoadString(IDS_LOADED_CHEATS)); +} + +CString MainWnd::getDirFromFile(CString& file) +{ + CString temp = file; + int index = temp.ReverseFind('\\'); + + if(index != -1) { + temp = temp.Left(index); + if(temp.GetLength() == 2 && temp[1] == ':') + temp += "\\"; + } else { + temp = ""; + } + return temp; +} + +bool MainWnd::isDriveRoot(CString& file) +{ + if(file.GetLength() == 3) { + if(file[1] == ':' && file[2] == '\\') + return true; + } + return false; +} + +void MainWnd::writeBatteryFile() +{ + CString buffer; + CString filename; + + int index = theApp.filename.ReverseFind('\\'); + + if(index != -1) + buffer = theApp.filename.Right(theApp.filename.GetLength()-index-1); + else + buffer = theApp.filename; + + CString saveDir = regQueryStringValue("batteryDir", NULL); + if( saveDir[0] == '.' ) { + // handle as relative path + char baseDir[MAX_PATH+1]; + GetModuleFileName( NULL, baseDir, MAX_PATH ); + baseDir[MAX_PATH] = '\0'; // for security reasons + PathRemoveFileSpec( baseDir ); // removes the trailing file name and backslash + strcat( baseDir, "\\" ); + strcat( baseDir, saveDir ); + saveDir = baseDir; + } + + if(saveDir.IsEmpty()) + saveDir = getDirFromFile(theApp.filename); + + if(isDriveRoot(saveDir)) + filename.Format("%s%s.sav", saveDir, buffer); + else + filename.Format("%s\\%s.sav", saveDir, buffer); + + if(theApp.emulator.emuWriteBattery) + theApp.emulator.emuWriteBattery(MakeInstanceFilename((const char *)filename)); +} + + +void MainWnd::readBatteryFile() +{ + CString buffer; + CString filename; + + int index = theApp.filename.ReverseFind('\\'); + + if(index != -1) + buffer = theApp.filename.Right(theApp.filename.GetLength()-index-1); + else + buffer = theApp.filename; + + CString saveDir = regQueryStringValue("batteryDir", NULL); + if( saveDir[0] == '.' ) { + // handle as relative path + char baseDir[MAX_PATH+1]; + GetModuleFileName( NULL, baseDir, MAX_PATH ); + baseDir[MAX_PATH] = '\0'; // for security reasons + PathRemoveFileSpec( baseDir ); // removes the trailing file name and backslash + strcat( baseDir, "\\" ); + strcat( baseDir, saveDir ); + saveDir = baseDir; + } + + if(saveDir.IsEmpty()) + saveDir = getDirFromFile(theApp.filename); + + if(isDriveRoot(saveDir)) + filename.Format("%s%s.sav", saveDir, buffer); + else + filename.Format("%s\\%s.sav", saveDir, buffer); + + bool res = false; + + if(theApp.emulator.emuReadBattery) + res = theApp.emulator.emuReadBattery(MakeInstanceFilename(filename)); + + if(res) + systemScreenMessage(winResLoadString(IDS_LOADED_BATTERY)); +} + +CString MainWnd::winLoadFilter(UINT id) +{ + CString res = winResLoadString(id); + res.Replace('_','|'); + + return res; +} + +bool MainWnd::loadSaveGame(const char *name) +{ + if(theApp.emulator.emuReadState) + return theApp.emulator.emuReadState(name); + return false; +} + +bool MainWnd::writeSaveGame(const char *name) +{ + if(theApp.emulator.emuWriteState) + return theApp.emulator.emuWriteState(name); + return false; +} + +void MainWnd::OnContextMenu(CWnd* pWnd, CPoint point) +{ + winMouseOn(); +} + +void MainWnd::OnSystemMinimize() +{ + ShowWindow(SW_SHOWMINIMIZED); +} + + +bool MainWnd::fileOpenSelect( int system ) +{ + theApp.dir = _T(""); + CString initialDir; + int selectedFilter = 0; + LPCTSTR exts[] = { _T(""), _T(""), _T(""), _T("") }; + CString filter; + CString title; + switch( system ) + { + case 0: + // GBA + initialDir = regQueryStringValue( _T("romdir"), _T(".") ); + selectedFilter = regQueryDwordValue( _T("selectedFilter"), 0); + if( (selectedFilter < 0) || (selectedFilter > 2) ) { + selectedFilter = 0; + } + filter = winLoadFilter( IDS_FILTER_ROM ); + break; + case 1: + // GBC + initialDir = regQueryStringValue( _T("gbcromdir"), _T(".") ); + // TODO: memorize selected filter for GBC as well + filter = winLoadFilter( IDS_FILTER_GBCROM ); + break; + case 2: + // GB + initialDir = regQueryStringValue( _T("gbromdir"), _T(".") ); + // TODO: memorize selected filter for GB as well + filter = winLoadFilter( IDS_FILTER_GBROM ); + break; + } + + title = winResLoadString( IDS_SELECT_ROM ); + + if( !initialDir.IsEmpty() ) { + theApp.dir = initialDir; + } + + if( initialDir[0] == '.' ) { + // handle as relative path + char baseDir[MAX_PATH+1]; + GetModuleFileName( NULL, baseDir, MAX_PATH ); + baseDir[MAX_PATH] = '\0'; // for security reasons + PathRemoveFileSpec( baseDir ); // removes the trailing file name and backslash + strcat( baseDir, "\\" ); + strcat( baseDir, initialDir ); + initialDir = baseDir; + } + + theApp.szFile = _T(""); + + + FileDlg dlg( this, _T(""), filter, selectedFilter, _T(""), exts, theApp.dir, title, false); + + if( dlg.DoModal() == IDOK ) { + if( system == 0 ) { + regSetDwordValue( _T("selectedFilter"), dlg.m_ofn.nFilterIndex ); + } + theApp.szFile = dlg.GetPathName(); + theApp.dir = theApp.szFile.Left( dlg.m_ofn.nFileOffset ); + if( (theApp.dir.GetLength() > 3) && (theApp.dir[theApp.dir.GetLength()-1] == _T('\\')) ) { + theApp.dir = theApp.dir.Left( theApp.dir.GetLength() - 1 ); + } + SetCurrentDirectory( theApp.dir ); + return true; + } + return false; +} + + +void MainWnd::OnPaint() +{ + CPaintDC dc(this); // device context for painting + + if(emulating) { + theApp.painting = true; + systemDrawScreen(); + theApp.painting = false; + theApp.renderedFrames--; + } +} + +BOOL MainWnd::PreTranslateMessage(MSG* pMsg) +{ + if (CWnd::PreTranslateMessage(pMsg)) + return TRUE; + + if(pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) { + return theApp.hAccel != NULL && ::TranslateAccelerator(m_hWnd, theApp.hAccel, pMsg); + } + + return FALSE; +} + +void MainWnd::screenCapture(int captureNumber) +{ + CString buffer; + + CString captureDir = regQueryStringValue("captureDir", ""); + if( captureDir[0] == '.' ) { + // handle as relative path + char baseDir[MAX_PATH+1]; + GetModuleFileName( NULL, baseDir, MAX_PATH ); + baseDir[MAX_PATH] = '\0'; // for security reasons + PathRemoveFileSpec( baseDir ); // removes the trailing file name and backslash + strcat( baseDir, "\\" ); + strcat( baseDir, captureDir ); + captureDir = baseDir; + } + int index = theApp.filename.ReverseFind('\\'); + + CString name; + if(index != -1) + name = theApp.filename.Right(theApp.filename.GetLength()-index-1); + else + name = theApp.filename; + + if(captureDir.IsEmpty()) + captureDir = getDirFromFile(theApp.filename); + + LPCTSTR ext = "png"; + if(theApp.captureFormat != 0) + ext = "bmp"; + + if(isDriveRoot(captureDir)) + buffer.Format("%s%s_%02d.%s", + captureDir, + name, + captureNumber, + ext); + else + buffer.Format("%s\\%s_%02d.%s", + captureDir, + name, + captureNumber, + ext); + + // check if file exists + DWORD dwAttr = GetFileAttributes( buffer ); + if( dwAttr != INVALID_FILE_ATTRIBUTES ) { + // screenshot file already exists + screenCapture(++captureNumber); + // this will recursively use the first non-existent screenshot number + return; + } + + if(theApp.captureFormat == 0) + theApp.emulator.emuWritePNG(buffer); + else + theApp.emulator.emuWriteBMP(buffer); + + CString msg = winResLoadString(IDS_SCREEN_CAPTURE); + systemScreenMessage(msg); +} + +void MainWnd::winMouseOn() +{ + SetCursor(arrow); + if(theApp.videoOption > VIDEO_4X) { + theApp.mouseCounter = 10; + } else + theApp.mouseCounter = 0; +} + +void MainWnd::OnMouseMove(UINT nFlags, CPoint point) +{ + winMouseOn(); + + CWnd::OnMouseMove(nFlags, point); +} + +void MainWnd::OnInitMenu(CMenu* pMenu) +{ + CWnd::OnInitMenu(pMenu); + + soundPause(); +} + +void MainWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) +{ + CWnd::OnActivate(nState, pWndOther, bMinimized); + + bool a = (nState == WA_ACTIVE) || (nState == WA_CLICKACTIVE); + + if(a && theApp.input) { + theApp.active = a; + theApp.input->activate(); + if(!theApp.paused && emulating) { + soundResume(); + } + } else { + theApp.wasPaused = true; + if(theApp.pauseWhenInactive) { + if(emulating) { + soundPause(); + } + theApp.active = a; + } + + memset(theApp.delta,255,sizeof(theApp.delta)); + } + + if(theApp.paused && emulating) + { + theApp.painting = true; + systemDrawScreen(); + theApp.painting = false; + theApp.renderedFrames--; + } +} + +void MainWnd::OnDropFiles(HDROP hDropInfo) +{ + char szFile[1024]; + + if(DragQueryFile(hDropInfo, + 0, + szFile, + 1024)) { + theApp.szFile = szFile; + if(FileRun()) { + SetForegroundWindow(); + emulating = TRUE; + } else { + emulating = FALSE; + soundPause(); + } + } + DragFinish(hDropInfo); +} + +LRESULT MainWnd::OnMySysCommand(WPARAM wParam, LPARAM lParam) +{ + if(emulating && !theApp.paused) { + if((wParam&0xFFF0) == SC_SCREENSAVE || (wParam&0xFFF0) == SC_MONITORPOWER) + return 0; + } + return Default(); +} + +void MainWnd::OnNcLButtonDown(UINT nHitTest, CPoint point) +{ + // pause sound before process is halted + if( emulating ) { + soundPause(); + } + + CWnd::OnNcLButtonDown(nHitTest, point); +} + +void MainWnd::OnWindowPosChanging(WINDOWPOS* lpwndpos) +{ + CWnd::OnWindowPosChanging(lpwndpos); + + // pause sound before changing window position/size + if( emulating ) { + soundPause(); + } +} diff --git a/src/win32/OpenGL.cpp b/src/win32/OpenGL.cpp index 3f1e337b..abfe0892 100644 --- a/src/win32/OpenGL.cpp +++ b/src/win32/OpenGL.cpp @@ -1,764 +1,764 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team -// Copyright (C) 2005-2006 VBA development team -// Copyright (C) 2007-2008 VBA-M development team -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef NO_OGL - -//OpenGL library -#pragma comment( lib, "opengl32.lib" ) - -// MFC -#include "stdafx.h" - -//GUI -#include "MainWnd.h" -#include "FullscreenSettings.h" - -// Internals -#include "../System.h" -#include "../agb/GBA.h" -#include "../Globals.h" -#include "../Util.h" -#include "../dmg/gbGlobals.h" -#include "..\memgzio.h" - -//Math -#include -#include - -// OpenGL -#include // main include file -#include -#include "glFont.h" -#include -typedef BOOL (APIENTRY *PFNWGLSWAPINTERVALFARPROC)( int ); -extern int Init_2xSaI(u32); -extern void winlog(const char *,...); -extern int systemSpeed; - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -#ifdef MMX -extern "C" bool cpu_mmx; -extern bool detectMMX(); -#endif - - -class OpenGLDisplay : public IDisplay { -private: - HDC hDC; - HGLRC hRC; - GLuint texture; - int width,height; - float size; - u8 *filterData; - RECT destRect; - bool failed; - GLFONT font; - int pitch; - GLuint displaylist; - u8 *data; - GLhandleARB v,f,p,t; - DWORD currentAdapter; - - void initializeMatrices( int w, int h ); - bool initializeTexture( int w, int h ); - void updateFiltering( int value ); - void setVSync( int interval = 1 ); - void calculateDestRect( int w, int h ); - void initializeFont(); - void renderlist(); - -public: - OpenGLDisplay(); - virtual ~OpenGLDisplay(); - virtual DISPLAY_TYPE getType() { return OPENGL; }; - - virtual void EnableOpenGL(); - virtual void DisableOpenGL(); - virtual bool initialize(); - virtual void cleanup(); - virtual void clear(); - virtual void render(); - - virtual bool changeRenderSize( int w, int h ); - virtual void resize( int w, int h ); - virtual void setOption( const char *, int ); - virtual bool selectFullScreenMode( VIDEO_MODE &mode ); -}; - -#include "gzglfont.h" -//Load GL font -void OpenGLDisplay::initializeFont() -{ - int ret; - z_stream strm; - char *buf = (char *)malloc(GZGLFONT_SIZE); - - /* allocate inflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = 0; - strm.next_in = Z_NULL; - ret = inflateInit2(&strm, 16+MAX_WBITS); - if (ret != Z_OK) - return; - - strm.avail_in = sizeof(gzglfont); - strm.next_in = gzglfont; - strm.avail_out = GZGLFONT_SIZE; - strm.next_out = (Bytef *)buf; - ret = inflate(&strm, Z_NO_FLUSH); - if (ret==Z_STREAM_END) - { - glGenTextures( 1, &texture ); - glFontCreate(&font, (char *)buf, texture); - texture=0; - } - free(buf); - (void)inflateEnd(&strm); -} - -//OpenGL class constructor -OpenGLDisplay::OpenGLDisplay() -{ - hDC = NULL; - hRC = NULL; - texture = 0; - width = 0; - height = 0; - size = 0.0f; - failed = false; - filterData = NULL; - currentAdapter = 0; -} - -//OpenGL class destroyer -OpenGLDisplay::~OpenGLDisplay() -{ - cleanup(); -} - -//Set OpenGL PFD and contexts -void OpenGLDisplay::EnableOpenGL() -{ - PIXELFORMATDESCRIPTOR pfd; - // get the device context (DC) - hDC = GetDC( theApp.m_pMainWnd->GetSafeHwnd() ); - // set the pixel format for the DC - ZeroMemory( &pfd, sizeof( pfd ) ); - pfd.nSize = sizeof( pfd ); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 24; - pfd.cDepthBits = 16; - pfd.iLayerType = PFD_MAIN_PLANE; - SetPixelFormat (GetDC (theApp.m_pMainWnd->GetSafeHwnd()), ChoosePixelFormat ( GetDC (theApp.m_pMainWnd->GetSafeHwnd()), &pfd), &pfd); - wglMakeCurrent (GetDC (theApp.m_pMainWnd->GetSafeHwnd()), wglCreateContext(GetDC (theApp.m_pMainWnd->GetSafeHwnd()) ) ); -} -//Remove contexts -void OpenGLDisplay::DisableOpenGL() -{ - wglMakeCurrent( NULL, NULL ); - wglDeleteContext( hRC ); - ReleaseDC( theApp.m_pMainWnd->GetSafeHwnd(), hDC ); -} -//Remove resources used -void OpenGLDisplay::cleanup() -{ - if(texture != 0) { - glDeleteTextures(1, &texture); - texture = 0; - } - - if (displaylist) - { - glDeleteLists(displaylist, 1); - displaylist = 0; - } - - DisableOpenGL(); - if(filterData) { - free(filterData); - filterData = NULL; - } - width = 0; - height = 0; - size = 0.0f; - - DISPLAY_DEVICE dev; - ZeroMemory( &dev, sizeof(dev) ); - dev.cb = sizeof(dev); - EnumDisplayDevices( NULL, currentAdapter, &dev, 0 ); - // restore default video mode - ChangeDisplaySettingsEx( dev.DeviceName, NULL, NULL, 0, NULL ); -} - -//init renderer -bool OpenGLDisplay::initialize() -{ - switch( theApp.cartridgeType ) - { - case IMAGE_GBA: - theApp.sizeX = 240; - theApp.sizeY = 160; - break; - case IMAGE_GB: - if ( gbBorderOn ) - { - theApp.sizeX = 256; - theApp.sizeY = 224; - } - else - { - theApp.sizeX = 160; - theApp.sizeY = 144; - } - break; - } - - - switch(theApp.videoOption) - { - case VIDEO_1X: - theApp.surfaceSizeX = theApp.sizeX; - theApp.surfaceSizeY = theApp.sizeY; - break; - case VIDEO_2X: - theApp.surfaceSizeX = theApp.sizeX * 2; - theApp.surfaceSizeY = theApp.sizeY * 2; - break; - case VIDEO_3X: - theApp.surfaceSizeX = theApp.sizeX * 3; - theApp.surfaceSizeY = theApp.sizeY * 3; - break; - case VIDEO_4X: - theApp.surfaceSizeX = theApp.sizeX * 4; - theApp.surfaceSizeY = theApp.sizeY * 4; - break; - case VIDEO_320x240: - case VIDEO_640x480: - case VIDEO_800x600: - case VIDEO_1024x768: - case VIDEO_1280x960: - case VIDEO_OTHER: - { - if( theApp.fullScreenStretch ) { - theApp.surfaceSizeX = theApp.fsWidth; - theApp.surfaceSizeY = theApp.fsHeight; - } else { - float scaleX = (float)theApp.fsWidth / (float)theApp.sizeX; - float scaleY = (float)theApp.fsHeight / (float)theApp.sizeY; - float min = ( scaleX < scaleY ) ? scaleX : scaleY; - if( theApp.fsMaxScale ) - min = ( min > (float)theApp.fsMaxScale ) ? (float)theApp.fsMaxScale : min; - theApp.surfaceSizeX = (int)((float)theApp.sizeX * min); - theApp.surfaceSizeY = (int)((float)theApp.sizeY * min); - } - } - break; - } - - theApp.rect.left = 0; - theApp.rect.top = 0; - theApp.rect.right = theApp.sizeX; - theApp.rect.bottom = theApp.sizeY; - - theApp.dest.left = 0; - theApp.dest.top = 0; - theApp.dest.right = theApp.surfaceSizeX; - theApp.dest.bottom = theApp.surfaceSizeY; - - DWORD style = WS_POPUP | WS_VISIBLE; - DWORD styleEx = 0; - - if( theApp.videoOption <= VIDEO_4X ) - style |= WS_OVERLAPPEDWINDOW; - else - styleEx = 0; - - if( theApp.videoOption <= VIDEO_4X ) - AdjustWindowRectEx( &theApp.dest, style, TRUE, styleEx ); - else - AdjustWindowRectEx( &theApp.dest, style, FALSE, styleEx ); - - int winSizeX = theApp.dest.right - theApp.dest.left; - int winSizeY = theApp.dest.bottom - theApp.dest.top; - int x = 0, y = 0; - - if( theApp.videoOption <= VIDEO_4X ) { - x = theApp.windowPositionX; - y = theApp.windowPositionY; - } else { - winSizeX = theApp.fsWidth; - winSizeY = theApp.fsHeight; - } - - // Create a window - MainWnd *pWnd = new MainWnd; - theApp.m_pMainWnd = pWnd; - - pWnd->CreateEx( - styleEx, - theApp.wndClass, - "VisualBoyAdvance", - style, - x,y,winSizeX,winSizeY, - NULL, - 0 ); - - if (!(HWND)*pWnd) { - winlog("Error creating Window %08x\n", GetLastError()); - return FALSE; - } - - theApp.updateMenuBar(); - - theApp.adjustDestRect(); - theApp.mode320Available = FALSE; - theApp.mode640Available = FALSE; - theApp.mode800Available = FALSE; - theApp.mode1024Available = FALSE; - theApp.mode1280Available = FALSE; - - - currentAdapter = theApp.fsAdapter; - DISPLAY_DEVICE dev; - ZeroMemory( &dev, sizeof(dev) ); - dev.cb = sizeof(dev); - EnumDisplayDevices( NULL, currentAdapter, &dev, 0 ); - if( theApp.videoOption >= VIDEO_320x240 ) { - // enter full screen mode - DEVMODE mode; - ZeroMemory( &mode, sizeof(mode) ); - mode.dmSize = sizeof(mode); - mode.dmBitsPerPel = theApp.fsColorDepth; - mode.dmPelsWidth = theApp.fsWidth; - mode.dmPelsHeight = theApp.fsHeight; - mode.dmDisplayFrequency = theApp.fsFrequency; - mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; - LONG ret = ChangeDisplaySettingsEx( dev.DeviceName, &mode, NULL, CDS_FULLSCREEN, NULL ); - if( ret != DISP_CHANGE_SUCCESSFUL ) { - systemMessage( 0, "Can not change display mode!" ); - failed = true; - } - } else { - // restore default mode - ChangeDisplaySettingsEx( dev.DeviceName, NULL, NULL, 0, NULL ); - } - - EnableOpenGL(); - initializeFont(); - glPushAttrib( GL_ENABLE_BIT ); - glDisable( GL_DEPTH_TEST ); - glDisable( GL_CULL_FACE ); - glEnable( GL_TEXTURE_2D ); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - initializeMatrices( theApp.surfaceSizeX, theApp.surfaceSizeY ); - - setVSync( theApp.vsync ); - -#ifdef MMX - if(!theApp.disableMMX) - cpu_mmx = theApp.detectMMX(); - else - cpu_mmx = 0; -#endif - - systemRedShift = 3; - systemGreenShift = 11; - systemBlueShift = 19; - systemColorDepth = 32; - theApp.fsColorDepth = 32; - - Init_2xSaI(32); - - utilUpdateSystemColorMaps(); - theApp.updateFilter(); - theApp.updateIFB(); - pitch = theApp.filterWidth * (systemColorDepth>>3) + 4; - data = pix + ( theApp.sizeX + 1 ) * 4; - renderlist(); - - if(failed) - return false; - - return true; -} - -//clear colour buffer -void OpenGLDisplay::clear() -{ - glClearColor(0.0,0.0,0.0,1.0); - glClear( GL_COLOR_BUFFER_BIT ); -} - -//dlist -void OpenGLDisplay::renderlist() -{ - displaylist = glGenLists(1); //set the cube list to Generate a List - glNewList(displaylist,GL_COMPILE); //compile the new list - glBegin( GL_QUADS ); - - glTexCoord2f( 0.0f, 0.0f ); - glVertex3i( 0, 0, 0 ); - - glTexCoord2f( (float)(width) / size, 0.0f ); - glVertex3i( theApp.surfaceSizeX, 0, 0 ); - - glTexCoord2f( (float)(width) / size, (float)(height) / size ); - glVertex3i( theApp.surfaceSizeX, theApp.surfaceSizeY, 0 ); - - glTexCoord2f( 0.0f, (float)(height) / size ); - glVertex3i( 0, theApp.surfaceSizeY, 0 ); - glEnd(); - glEndList(); -} - -//main render func -void OpenGLDisplay::render() -{ - clear(); - - pitch = theApp.filterWidth * (systemColorDepth>>3) + 4; - data = pix + ( theApp.sizeX + 1 ) * 4; - - // apply pixel filter - if(theApp.filterFunction) { - data = filterData; - theApp.filterFunction( - pix + pitch, - pitch, - (u8*)theApp.delta, - (u8*)filterData, - width * 4 , - theApp.filterWidth, - theApp.filterHeight); - } - - // Texturemap complete texture to surface - // so we have free scaling and antialiasing - - if( theApp.filterFunction ) { - glPixelStorei( GL_UNPACK_ROW_LENGTH, width); - } else { - glPixelStorei( GL_UNPACK_ROW_LENGTH, theApp.sizeX + 1 ); - } - glTexSubImage2D(GL_TEXTURE_2D,0,0,0,width,height,GL_RGBA,GL_UNSIGNED_BYTE,data ); - - - glCallList(displaylist); - - - if( theApp.showSpeed ) { // && ( theApp.videoOption > VIDEO_4X ) ) { - char buffer[30]; - if( theApp.showSpeed == 1 ) { - sprintf( buffer, "%3d%%", systemSpeed ); - } else { - sprintf( buffer, "%3d%%(%d, %d fps)", systemSpeed, systemFrameSkip, theApp.showRenderedFrames ); - } - glFontBegin(&font); - glPushMatrix(); - float fontscale = (float)theApp.surfaceSizeX / 100.0f; - glScalef(fontscale, fontscale, fontscale); - glColor4f(1.0f, 0.25f, 0.25f, 1.0f); - glFontTextOut(buffer, (theApp.surfaceSizeX-(strlen(buffer)*11))/(fontscale*2), (theApp.surfaceSizeY-20)/fontscale, 0); - glPopMatrix(); - glFontEnd(); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glBindTexture( GL_TEXTURE_2D, texture ); - } - if( theApp.screenMessage ) { - if( ( ( GetTickCount() - theApp.screenMessageTime ) < 3000 ) && !theApp.disableStatusMessage ) { - glFontBegin(&font); - glPushMatrix(); - - float fontscale = (float)theApp.surfaceSizeX / 100.0f; - glScalef(fontscale, fontscale, fontscale); - glColor4f(1.0f, 0.25f, 0.25f, 1.0f); - glFontTextOut((char *)((const char *)theApp.screenMessageBuffer), (theApp.surfaceSizeX-(theApp.screenMessageBuffer.GetLength()*11))/(fontscale*2), (theApp.surfaceSizeY-40)/fontscale, 0); - glPopMatrix(); - glFontEnd(); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glBindTexture( GL_TEXTURE_2D, texture ); - } else { - theApp.screenMessage = false; - } - } - - glFlush(); - SwapBuffers( hDC ); - // since OpenGL draws on the back buffer, - // we have to swap it to the front buffer to see the content - -} - -//resize screen -void OpenGLDisplay::resize( int w, int h ) -{ - initializeMatrices( w, h ); - /* Display lists are not mutable, so we have to do this*/ - if (displaylist) - { - glDeleteLists(displaylist, 1); - displaylist = 0; - renderlist(); - } -} - -//update filtering methods -void OpenGLDisplay::updateFiltering( int value ) -{ - switch( value ) - { - case 0: - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - break; - case 1: - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - break; - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); -} - -//init projection matrixes and viewports -void OpenGLDisplay::initializeMatrices( int w, int h ) -{ - if( theApp.fullScreenStretch ) { - glViewport( 0, 0, w, h ); - } else { - calculateDestRect( w, h ); - glViewport( - destRect.left, - destRect.top, - destRect.right - destRect.left, - destRect.bottom - destRect.top ); - } - - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glOrtho( - /* left */ 1.0f, - /* right */ (GLdouble)(w - 1), - /* bottom */ (GLdouble)(h - 1), - /* top */ 1.0f, - 0.0f, - 1.0f ); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - if (displaylist) - { - glDeleteLists(displaylist, 1); - displaylist = 0; - renderlist(); - } -} - -//init font texture -bool OpenGLDisplay::initializeTexture( int w, int h ) -{ - // size = 2^n - // w = 24 > size = 256 = 2^8 - // w = 255 > size = 256 = 2^8 - // w = 256 > size = 512 = 2^9 - // w = 300 > size = 512 = 2^9 - // OpenGL textures have to be square and a power of 2 - // We could use methods that allow tex's to not be powers of two - // but that requires extra OGL extensions - - float n1 = log10( (float)w ) / log10( 2.0f ); - float n2 = log10( (float)h ) / log10( 2.0f ); - float n = ( n1 > n2 ) ? n1 : n2; - - if( ((float)((int)n)) != n ) { - // round up - n = ((float)((int)n)) + 1.0f; - } - - size = pow( 2.0f, n ); - - glGenTextures( 1, &texture ); - glBindTexture( GL_TEXTURE_2D, texture ); - updateFiltering( theApp.glFilter ); - - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_RGBA, - (GLsizei)size, - (GLsizei)size, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - NULL ); - - width = w; - height = h; - - //return ( glGetError() == GL_NO_ERROR) ? true : false; - // Workaround: We usually get GL_INVALID_VALUE, but somehow it works nevertheless - // In consequence, we must not treat it as an error or else the app behaves as if an error occured. - // This in the end results in theApp->input not being created = no input when switching from D3D to OGL - return true; -} - -//turn vsync on or off -void OpenGLDisplay::setVSync( int interval ) -{ - const char *extensions = (const char *)glGetString( GL_EXTENSIONS ); - - if( strstr( extensions, "WGL_EXT_swap_control" ) == 0 ) { - winlog( "Error: WGL_EXT_swap_control extension not supported on your computer.\n" ); - return; - } else { - PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = NULL; - wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" ); - if( wglSwapIntervalEXT ) { - wglSwapIntervalEXT( interval ); - } - } -} - -//change render size for fonts and filter data -bool OpenGLDisplay::changeRenderSize( int w, int h ) -{ - if( (width != w) || (height != h) ) { - if( texture != 0 ) { - glDeleteTextures( 1, &texture ); - texture = 0; - } - - if( !initializeTexture( w, h ) ) { - failed = true; - return false; - } - if (filterData) - free(filterData); - filterData = (u8 *)malloc(4*w*h); - } - if (displaylist) - { - glDeleteLists(displaylist, 1); - displaylist = 0; - renderlist(); - } - return true; -} - -//calculate RECTs -void OpenGLDisplay::calculateDestRect( int w, int h ) -{ - float scaleX = (float)w / (float)width; - float scaleY = (float)h / (float)height; - float min = (scaleX < scaleY) ? scaleX : scaleY; - if( theApp.fsMaxScale && (min > theApp.fsMaxScale) ) { - min = (float)theApp.fsMaxScale; - } - destRect.left = 0; - destRect.top = 0; - destRect.right = (LONG)(width * min); - destRect.bottom = (LONG)(height * min); - if( destRect.right != w ) { - LONG diff = (w - destRect.right) / 2; - destRect.left += diff; - destRect.right += diff; - } - if( destRect.bottom != h ) { - LONG diff = (h - destRect.bottom) / 2; - destRect.top += diff; - destRect.bottom += diff; - } - if (displaylist) - { - glDeleteLists(displaylist, 1); - displaylist = 0; - renderlist(); - } -} - -//config options -void OpenGLDisplay::setOption( const char *option, int value ) -{ - if( !_tcscmp( option, _T("vsync") ) ) { - setVSync( value ); - } - - if( !_tcscmp( option, _T("glFilter") ) ) { - updateFiltering( value ); - } - - if( !_tcscmp( option, _T("maxScale") ) ) { - initializeMatrices( theApp.dest.right, theApp.dest.bottom ); - } - - if( !_tcscmp( option, _T("fullScreenStretch") ) ) { - initializeMatrices( theApp.dest.right, theApp.dest.bottom ); - } -} - -//set fullscreen mode -bool OpenGLDisplay::selectFullScreenMode( VIDEO_MODE &mode ) -{ - FullscreenSettings dlg; - dlg.setAPI( this->getType() ); - INT_PTR ret = dlg.DoModal(); - if( ret == IDOK ) { - mode.adapter = dlg.m_device; - switch( dlg.m_colorDepth ) - { - case 30: - // TODO: support - return false; - break; - case 24: - mode.bitDepth = 32; - break; - case 16: - case 15: - mode.bitDepth = 16; - break; - } - mode.width = dlg.m_width; - mode.height = dlg.m_height; - mode.frequency = dlg.m_refreshRate; - return true; - } else { - return false; - } -} - - -IDisplay *newOpenGLDisplay() -{ - return new OpenGLDisplay(); -} - -#endif // #ifndef NO_OGL +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team +// Copyright (C) 2005-2006 VBA development team +// Copyright (C) 2007-2008 VBA-M development team +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef NO_OGL + +//OpenGL library +#pragma comment( lib, "opengl32.lib" ) + +// MFC +#include "stdafx.h" + +//GUI +#include "MainWnd.h" +#include "FullscreenSettings.h" + +// Internals +#include "../System.h" +#include "../agb/GBA.h" +#include "../Globals.h" +#include "../Util.h" +#include "../dmg/gbGlobals.h" +#include "..\memgzio.h" + +//Math +#include +#include + +// OpenGL +#include // main include file +#include +#include "glFont.h" +#include +typedef BOOL (APIENTRY *PFNWGLSWAPINTERVALFARPROC)( int ); +extern int Init_2xSaI(u32); +extern void winlog(const char *,...); +extern int systemSpeed; + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#ifdef MMX +extern "C" bool cpu_mmx; +extern bool detectMMX(); +#endif + + +class OpenGLDisplay : public IDisplay { +private: + HDC hDC; + HGLRC hRC; + GLuint texture; + int width,height; + float size; + u8 *filterData; + RECT destRect; + bool failed; + GLFONT font; + int pitch; + GLuint displaylist; + u8 *data; + GLhandleARB v,f,p,t; + DWORD currentAdapter; + + void initializeMatrices( int w, int h ); + bool initializeTexture( int w, int h ); + void updateFiltering( int value ); + void setVSync( int interval = 1 ); + void calculateDestRect( int w, int h ); + void initializeFont(); + void renderlist(); + +public: + OpenGLDisplay(); + virtual ~OpenGLDisplay(); + virtual DISPLAY_TYPE getType() { return OPENGL; }; + + virtual void EnableOpenGL(); + virtual void DisableOpenGL(); + virtual bool initialize(); + virtual void cleanup(); + virtual void clear(); + virtual void render(); + + virtual bool changeRenderSize( int w, int h ); + virtual void resize( int w, int h ); + virtual void setOption( const char *, int ); + virtual bool selectFullScreenMode( VIDEO_MODE &mode ); +}; + +#include "gzglfont.h" +//Load GL font +void OpenGLDisplay::initializeFont() +{ + int ret; + z_stream strm; + char *buf = (char *)malloc(GZGLFONT_SIZE); + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, 16+MAX_WBITS); + if (ret != Z_OK) + return; + + strm.avail_in = sizeof(gzglfont); + strm.next_in = gzglfont; + strm.avail_out = GZGLFONT_SIZE; + strm.next_out = (Bytef *)buf; + ret = inflate(&strm, Z_NO_FLUSH); + if (ret==Z_STREAM_END) + { + glGenTextures( 1, &texture ); + glFontCreate(&font, (char *)buf, texture); + texture=0; + } + free(buf); + (void)inflateEnd(&strm); +} + +//OpenGL class constructor +OpenGLDisplay::OpenGLDisplay() +{ + hDC = NULL; + hRC = NULL; + texture = 0; + width = 0; + height = 0; + size = 0.0f; + failed = false; + filterData = NULL; + currentAdapter = 0; +} + +//OpenGL class destroyer +OpenGLDisplay::~OpenGLDisplay() +{ + cleanup(); +} + +//Set OpenGL PFD and contexts +void OpenGLDisplay::EnableOpenGL() +{ + PIXELFORMATDESCRIPTOR pfd; + // get the device context (DC) + hDC = GetDC( theApp.m_pMainWnd->GetSafeHwnd() ); + // set the pixel format for the DC + ZeroMemory( &pfd, sizeof( pfd ) ); + pfd.nSize = sizeof( pfd ); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + pfd.cDepthBits = 16; + pfd.iLayerType = PFD_MAIN_PLANE; + SetPixelFormat (GetDC (theApp.m_pMainWnd->GetSafeHwnd()), ChoosePixelFormat ( GetDC (theApp.m_pMainWnd->GetSafeHwnd()), &pfd), &pfd); + wglMakeCurrent (GetDC (theApp.m_pMainWnd->GetSafeHwnd()), wglCreateContext(GetDC (theApp.m_pMainWnd->GetSafeHwnd()) ) ); +} +//Remove contexts +void OpenGLDisplay::DisableOpenGL() +{ + wglMakeCurrent( NULL, NULL ); + wglDeleteContext( hRC ); + ReleaseDC( theApp.m_pMainWnd->GetSafeHwnd(), hDC ); +} +//Remove resources used +void OpenGLDisplay::cleanup() +{ + if(texture != 0) { + glDeleteTextures(1, &texture); + texture = 0; + } + + if (displaylist) + { + glDeleteLists(displaylist, 1); + displaylist = 0; + } + + DisableOpenGL(); + if(filterData) { + free(filterData); + filterData = NULL; + } + width = 0; + height = 0; + size = 0.0f; + + DISPLAY_DEVICE dev; + ZeroMemory( &dev, sizeof(dev) ); + dev.cb = sizeof(dev); + EnumDisplayDevices( NULL, currentAdapter, &dev, 0 ); + // restore default video mode + ChangeDisplaySettingsEx( dev.DeviceName, NULL, NULL, 0, NULL ); +} + +//init renderer +bool OpenGLDisplay::initialize() +{ + switch( theApp.cartridgeType ) + { + case IMAGE_GBA: + theApp.sizeX = 240; + theApp.sizeY = 160; + break; + case IMAGE_GB: + if ( gbBorderOn ) + { + theApp.sizeX = 256; + theApp.sizeY = 224; + } + else + { + theApp.sizeX = 160; + theApp.sizeY = 144; + } + break; + } + + + switch(theApp.videoOption) + { + case VIDEO_1X: + theApp.surfaceSizeX = theApp.sizeX; + theApp.surfaceSizeY = theApp.sizeY; + break; + case VIDEO_2X: + theApp.surfaceSizeX = theApp.sizeX * 2; + theApp.surfaceSizeY = theApp.sizeY * 2; + break; + case VIDEO_3X: + theApp.surfaceSizeX = theApp.sizeX * 3; + theApp.surfaceSizeY = theApp.sizeY * 3; + break; + case VIDEO_4X: + theApp.surfaceSizeX = theApp.sizeX * 4; + theApp.surfaceSizeY = theApp.sizeY * 4; + break; + case VIDEO_320x240: + case VIDEO_640x480: + case VIDEO_800x600: + case VIDEO_1024x768: + case VIDEO_1280x960: + case VIDEO_OTHER: + { + if( theApp.fullScreenStretch ) { + theApp.surfaceSizeX = theApp.fsWidth; + theApp.surfaceSizeY = theApp.fsHeight; + } else { + float scaleX = (float)theApp.fsWidth / (float)theApp.sizeX; + float scaleY = (float)theApp.fsHeight / (float)theApp.sizeY; + float min = ( scaleX < scaleY ) ? scaleX : scaleY; + if( theApp.fsMaxScale ) + min = ( min > (float)theApp.fsMaxScale ) ? (float)theApp.fsMaxScale : min; + theApp.surfaceSizeX = (int)((float)theApp.sizeX * min); + theApp.surfaceSizeY = (int)((float)theApp.sizeY * min); + } + } + break; + } + + theApp.rect.left = 0; + theApp.rect.top = 0; + theApp.rect.right = theApp.sizeX; + theApp.rect.bottom = theApp.sizeY; + + theApp.dest.left = 0; + theApp.dest.top = 0; + theApp.dest.right = theApp.surfaceSizeX; + theApp.dest.bottom = theApp.surfaceSizeY; + + DWORD style = WS_POPUP | WS_VISIBLE; + DWORD styleEx = 0; + + if( theApp.videoOption <= VIDEO_4X ) + style |= WS_OVERLAPPEDWINDOW; + else + styleEx = 0; + + if( theApp.videoOption <= VIDEO_4X ) + AdjustWindowRectEx( &theApp.dest, style, TRUE, styleEx ); + else + AdjustWindowRectEx( &theApp.dest, style, FALSE, styleEx ); + + int winSizeX = theApp.dest.right - theApp.dest.left; + int winSizeY = theApp.dest.bottom - theApp.dest.top; + int x = 0, y = 0; + + if( theApp.videoOption <= VIDEO_4X ) { + x = theApp.windowPositionX; + y = theApp.windowPositionY; + } else { + winSizeX = theApp.fsWidth; + winSizeY = theApp.fsHeight; + } + + // Create a window + MainWnd *pWnd = new MainWnd; + theApp.m_pMainWnd = pWnd; + + pWnd->CreateEx( + styleEx, + theApp.wndClass, + "VisualBoyAdvance", + style, + x,y,winSizeX,winSizeY, + NULL, + 0 ); + + if (!(HWND)*pWnd) { + winlog("Error creating Window %08x\n", GetLastError()); + return FALSE; + } + + theApp.updateMenuBar(); + + theApp.adjustDestRect(); + theApp.mode320Available = FALSE; + theApp.mode640Available = FALSE; + theApp.mode800Available = FALSE; + theApp.mode1024Available = FALSE; + theApp.mode1280Available = FALSE; + + + currentAdapter = theApp.fsAdapter; + DISPLAY_DEVICE dev; + ZeroMemory( &dev, sizeof(dev) ); + dev.cb = sizeof(dev); + EnumDisplayDevices( NULL, currentAdapter, &dev, 0 ); + if( theApp.videoOption >= VIDEO_320x240 ) { + // enter full screen mode + DEVMODE mode; + ZeroMemory( &mode, sizeof(mode) ); + mode.dmSize = sizeof(mode); + mode.dmBitsPerPel = theApp.fsColorDepth; + mode.dmPelsWidth = theApp.fsWidth; + mode.dmPelsHeight = theApp.fsHeight; + mode.dmDisplayFrequency = theApp.fsFrequency; + mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; + LONG ret = ChangeDisplaySettingsEx( dev.DeviceName, &mode, NULL, CDS_FULLSCREEN, NULL ); + if( ret != DISP_CHANGE_SUCCESSFUL ) { + systemMessage( 0, "Can not change display mode!" ); + failed = true; + } + } else { + // restore default mode + ChangeDisplaySettingsEx( dev.DeviceName, NULL, NULL, 0, NULL ); + } + + EnableOpenGL(); + initializeFont(); + glPushAttrib( GL_ENABLE_BIT ); + glDisable( GL_DEPTH_TEST ); + glDisable( GL_CULL_FACE ); + glEnable( GL_TEXTURE_2D ); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + initializeMatrices( theApp.surfaceSizeX, theApp.surfaceSizeY ); + + setVSync( theApp.vsync ); + +#ifdef MMX + if(!theApp.disableMMX) + cpu_mmx = theApp.detectMMX(); + else + cpu_mmx = 0; +#endif + + systemRedShift = 3; + systemGreenShift = 11; + systemBlueShift = 19; + systemColorDepth = 32; + theApp.fsColorDepth = 32; + + Init_2xSaI(32); + + utilUpdateSystemColorMaps(); + theApp.updateFilter(); + theApp.updateIFB(); + pitch = theApp.filterWidth * (systemColorDepth>>3) + 4; + data = pix + ( theApp.sizeX + 1 ) * 4; + renderlist(); + + if(failed) + return false; + + return true; +} + +//clear colour buffer +void OpenGLDisplay::clear() +{ + glClearColor(0.0,0.0,0.0,1.0); + glClear( GL_COLOR_BUFFER_BIT ); +} + +//dlist +void OpenGLDisplay::renderlist() +{ + displaylist = glGenLists(1); //set the cube list to Generate a List + glNewList(displaylist,GL_COMPILE); //compile the new list + glBegin( GL_QUADS ); + + glTexCoord2f( 0.0f, 0.0f ); + glVertex3i( 0, 0, 0 ); + + glTexCoord2f( (float)(width) / size, 0.0f ); + glVertex3i( theApp.surfaceSizeX, 0, 0 ); + + glTexCoord2f( (float)(width) / size, (float)(height) / size ); + glVertex3i( theApp.surfaceSizeX, theApp.surfaceSizeY, 0 ); + + glTexCoord2f( 0.0f, (float)(height) / size ); + glVertex3i( 0, theApp.surfaceSizeY, 0 ); + glEnd(); + glEndList(); +} + +//main render func +void OpenGLDisplay::render() +{ + clear(); + + pitch = theApp.filterWidth * (systemColorDepth>>3) + 4; + data = pix + ( theApp.sizeX + 1 ) * 4; + + // apply pixel filter + if(theApp.filterFunction) { + data = filterData; + theApp.filterFunction( + pix + pitch, + pitch, + (u8*)theApp.delta, + (u8*)filterData, + width * 4 , + theApp.filterWidth, + theApp.filterHeight); + } + + // Texturemap complete texture to surface + // so we have free scaling and antialiasing + + if( theApp.filterFunction ) { + glPixelStorei( GL_UNPACK_ROW_LENGTH, width); + } else { + glPixelStorei( GL_UNPACK_ROW_LENGTH, theApp.sizeX + 1 ); + } + glTexSubImage2D(GL_TEXTURE_2D,0,0,0,width,height,GL_RGBA,GL_UNSIGNED_BYTE,data ); + + + glCallList(displaylist); + + + if( theApp.showSpeed ) { // && ( theApp.videoOption > VIDEO_4X ) ) { + char buffer[30]; + if( theApp.showSpeed == 1 ) { + sprintf( buffer, "%3d%%", systemSpeed ); + } else { + sprintf( buffer, "%3d%%(%d, %d fps)", systemSpeed, systemFrameSkip, theApp.showRenderedFrames ); + } + glFontBegin(&font); + glPushMatrix(); + float fontscale = (float)theApp.surfaceSizeX / 100.0f; + glScalef(fontscale, fontscale, fontscale); + glColor4f(1.0f, 0.25f, 0.25f, 1.0f); + glFontTextOut(buffer, (theApp.surfaceSizeX-(strlen(buffer)*11))/(fontscale*2), (theApp.surfaceSizeY-20)/fontscale, 0); + glPopMatrix(); + glFontEnd(); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBindTexture( GL_TEXTURE_2D, texture ); + } + if( theApp.screenMessage ) { + if( ( ( GetTickCount() - theApp.screenMessageTime ) < 3000 ) && !theApp.disableStatusMessage ) { + glFontBegin(&font); + glPushMatrix(); + + float fontscale = (float)theApp.surfaceSizeX / 100.0f; + glScalef(fontscale, fontscale, fontscale); + glColor4f(1.0f, 0.25f, 0.25f, 1.0f); + glFontTextOut((char *)((const char *)theApp.screenMessageBuffer), (theApp.surfaceSizeX-(theApp.screenMessageBuffer.GetLength()*11))/(fontscale*2), (theApp.surfaceSizeY-40)/fontscale, 0); + glPopMatrix(); + glFontEnd(); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBindTexture( GL_TEXTURE_2D, texture ); + } else { + theApp.screenMessage = false; + } + } + + glFlush(); + SwapBuffers( hDC ); + // since OpenGL draws on the back buffer, + // we have to swap it to the front buffer to see the content + +} + +//resize screen +void OpenGLDisplay::resize( int w, int h ) +{ + initializeMatrices( w, h ); + /* Display lists are not mutable, so we have to do this*/ + if (displaylist) + { + glDeleteLists(displaylist, 1); + displaylist = 0; + renderlist(); + } +} + +//update filtering methods +void OpenGLDisplay::updateFiltering( int value ) +{ + switch( value ) + { + case 0: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + break; + case 1: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); +} + +//init projection matrixes and viewports +void OpenGLDisplay::initializeMatrices( int w, int h ) +{ + if( theApp.fullScreenStretch ) { + glViewport( 0, 0, w, h ); + } else { + calculateDestRect( w, h ); + glViewport( + destRect.left, + destRect.top, + destRect.right - destRect.left, + destRect.bottom - destRect.top ); + } + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( + /* left */ 1.0f, + /* right */ (GLdouble)(w - 1), + /* bottom */ (GLdouble)(h - 1), + /* top */ 1.0f, + 0.0f, + 1.0f ); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + if (displaylist) + { + glDeleteLists(displaylist, 1); + displaylist = 0; + renderlist(); + } +} + +//init font texture +bool OpenGLDisplay::initializeTexture( int w, int h ) +{ + // size = 2^n + // w = 24 > size = 256 = 2^8 + // w = 255 > size = 256 = 2^8 + // w = 256 > size = 512 = 2^9 + // w = 300 > size = 512 = 2^9 + // OpenGL textures have to be square and a power of 2 + // We could use methods that allow tex's to not be powers of two + // but that requires extra OGL extensions + + float n1 = log10( (float)w ) / log10( 2.0f ); + float n2 = log10( (float)h ) / log10( 2.0f ); + float n = ( n1 > n2 ) ? n1 : n2; + + if( ((float)((int)n)) != n ) { + // round up + n = ((float)((int)n)) + 1.0f; + } + + size = pow( 2.0f, n ); + + glGenTextures( 1, &texture ); + glBindTexture( GL_TEXTURE_2D, texture ); + updateFiltering( theApp.glFilter ); + + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + (GLsizei)size, + (GLsizei)size, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + NULL ); + + width = w; + height = h; + + //return ( glGetError() == GL_NO_ERROR) ? true : false; + // Workaround: We usually get GL_INVALID_VALUE, but somehow it works nevertheless + // In consequence, we must not treat it as an error or else the app behaves as if an error occured. + // This in the end results in theApp->input not being created = no input when switching from D3D to OGL + return true; +} + +//turn vsync on or off +void OpenGLDisplay::setVSync( int interval ) +{ + const char *extensions = (const char *)glGetString( GL_EXTENSIONS ); + + if( strstr( extensions, "WGL_EXT_swap_control" ) == 0 ) { + winlog( "Error: WGL_EXT_swap_control extension not supported on your computer.\n" ); + return; + } else { + PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = NULL; + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" ); + if( wglSwapIntervalEXT ) { + wglSwapIntervalEXT( interval ); + } + } +} + +//change render size for fonts and filter data +bool OpenGLDisplay::changeRenderSize( int w, int h ) +{ + if( (width != w) || (height != h) ) { + if( texture != 0 ) { + glDeleteTextures( 1, &texture ); + texture = 0; + } + + if( !initializeTexture( w, h ) ) { + failed = true; + return false; + } + if (filterData) + free(filterData); + filterData = (u8 *)malloc(4*w*h); + } + if (displaylist) + { + glDeleteLists(displaylist, 1); + displaylist = 0; + renderlist(); + } + return true; +} + +//calculate RECTs +void OpenGLDisplay::calculateDestRect( int w, int h ) +{ + float scaleX = (float)w / (float)width; + float scaleY = (float)h / (float)height; + float min = (scaleX < scaleY) ? scaleX : scaleY; + if( theApp.fsMaxScale && (min > theApp.fsMaxScale) ) { + min = (float)theApp.fsMaxScale; + } + destRect.left = 0; + destRect.top = 0; + destRect.right = (LONG)(width * min); + destRect.bottom = (LONG)(height * min); + if( destRect.right != w ) { + LONG diff = (w - destRect.right) / 2; + destRect.left += diff; + destRect.right += diff; + } + if( destRect.bottom != h ) { + LONG diff = (h - destRect.bottom) / 2; + destRect.top += diff; + destRect.bottom += diff; + } + if (displaylist) + { + glDeleteLists(displaylist, 1); + displaylist = 0; + renderlist(); + } +} + +//config options +void OpenGLDisplay::setOption( const char *option, int value ) +{ + if( !_tcscmp( option, _T("vsync") ) ) { + setVSync( value ); + } + + if( !_tcscmp( option, _T("glFilter") ) ) { + updateFiltering( value ); + } + + if( !_tcscmp( option, _T("maxScale") ) ) { + initializeMatrices( theApp.dest.right, theApp.dest.bottom ); + } + + if( !_tcscmp( option, _T("fullScreenStretch") ) ) { + initializeMatrices( theApp.dest.right, theApp.dest.bottom ); + } +} + +//set fullscreen mode +bool OpenGLDisplay::selectFullScreenMode( VIDEO_MODE &mode ) +{ + FullscreenSettings dlg; + dlg.setAPI( this->getType() ); + INT_PTR ret = dlg.DoModal(); + if( ret == IDOK ) { + mode.adapter = dlg.m_device; + switch( dlg.m_colorDepth ) + { + case 30: + // TODO: support + return false; + break; + case 24: + mode.bitDepth = 32; + break; + case 16: + case 15: + mode.bitDepth = 16; + break; + } + mode.width = dlg.m_width; + mode.height = dlg.m_height; + mode.frequency = dlg.m_refreshRate; + return true; + } else { + return false; + } +} + + +IDisplay *newOpenGLDisplay() +{ + return new OpenGLDisplay(); +} + +#endif // #ifndef NO_OGL diff --git a/src/win32/VBA.cpp b/src/win32/VBA.cpp index 39b684c8..0b091217 100644 --- a/src/win32/VBA.cpp +++ b/src/win32/VBA.cpp @@ -1,2658 +1,2658 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005 Forgotten and the VBA development team -// Copyright (C) 2007-2008 VBA-M development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifdef NO_D3D -#ifdef NO_OGL -#error NO_D3D and NO_OGL must not be defined at the same time. -#endif -#endif - -#include "stdafx.h" - -#include "AVIWrite.h" -#include "LangSelect.h" -#include "MainWnd.h" -#include "Reg.h" -#include "resource.h" -#include "WavWriter.h" -#include "WinResUtil.h" -#include "Logging.h" -#include "rpi.h" - -#include "../System.h" -#include "../agb/agbprint.h" -#include "../cheatSearch.h" -#include "../agb/GBA.h" -#include "../Globals.h" -#include "../RTC.h" -#include "../Sound.h" -#include "../Util.h" -#include "../dmg/gbGlobals.h" -#include "../dmg/gbPrinter.h" - -/* Link ----------------------*/ -#include "../agb/GBALink.h" -/* ---------------- */ - -#include "../agb/gbafilter.h" - -#ifdef SDL -#pragma comment( lib, "SDL" ) -#pragma comment( lib, "SDLmain" ) -#endif - -extern void Pixelate(u8*,u32,u8*,u8*,u32,int,int); -extern void Pixelate32(u8*,u32,u8*,u8*,u32,int,int); -extern void _2xSaI(u8*,u32,u8*,u8*,u32,int,int); -extern void _2xSaI32(u8*,u32,u8*,u8*,u32,int,int); -extern void Super2xSaI(u8*,u32,u8*,u8*,u32,int,int); -extern void Super2xSaI32(u8*,u32,u8*,u8*,u32,int,int); -extern void SuperEagle(u8*,u32,u8*,u8*,u32,int,int); -extern void SuperEagle32(u8*,u32,u8*,u8*,u32,int,int); -extern void AdMame2x(u8*,u32,u8*,u8*,u32,int,int); -extern void AdMame2x32(u8*,u32,u8*,u8*,u32,int,int); -extern void Bilinear(u8*,u32,u8*,u8*,u32,int,int); -extern void Bilinear32(u8*,u32,u8*,u8*,u32,int,int); -extern void BilinearPlus(u8*,u32,u8*,u8*,u32,int,int); -extern void BilinearPlus32(u8*,u32,u8*,u8*,u32,int,int); -extern void Scanlines(u8*,u32,u8*,u8*,u32,int,int); -extern void Scanlines32(u8*,u32,u8*,u8*,u32,int,int); -extern void ScanlinesTV(u8*,u32,u8*,u8*,u32,int,int); -extern void ScanlinesTV32(u8*,u32,u8*,u8*,u32,int,int); -extern void hq2x(u8*,u32,u8*,u8*,u32,int,int); -extern void hq2x32(u8*,u32,u8*,u8*,u32,int,int); -extern void lq2x(u8*,u32,u8*,u8*,u32,int,int); -extern void lq2x32(u8*,u32,u8*,u8*,u32,int,int); -extern void Simple2x16(u8*,u32,u8*,u8*,u32,int,int); -extern void Simple2x32(u8*,u32,u8*,u8*,u32,int,int); -extern void Simple3x16(u8*,u32,u8*,u8*,u32,int,int); -extern void Simple3x32(u8*,u32,u8*,u8*,u32,int,int); -extern void Simple4x16(u8*,u32,u8*,u8*,u32,int,int); -extern void Simple4x32(u8*,u32,u8*,u8*,u32,int,int); -extern void hq3x16(u8*,u32,u8*,u8*,u32,int,int); -extern void hq4x16(u8*,u32,u8*,u8*,u32,int,int); -extern void hq3x32(u8*,u32,u8*,u8*,u32,int,int); -extern void hq4x32(u8*,u32,u8*,u8*,u32,int,int); - -extern void SmartIB(u8*,u32,int,int); -extern void SmartIB32(u8*,u32,int,int); -extern void MotionBlurIB(u8*,u32,int,int); -extern void MotionBlurIB32(u8*,u32,int,int); - -extern IDisplay *newGDIDisplay(); -extern IDisplay *newDirectDrawDisplay(); -#ifndef NO_OGL -extern IDisplay *newOpenGLDisplay(); -#endif -#ifndef NO_D3D -extern IDisplay *newDirect3DDisplay(); -#endif - -extern Input *newDirectInput(); - -extern ISound *newDirectSound(); -#ifndef NO_OAL -extern ISound *newOpenAL(); -#endif - -extern void remoteStubSignal(int, int); -extern void remoteOutput(char *, u32); -extern void remoteStubMain(); -extern void remoteSetProtocol(int); -extern void remoteCleanUp(); -extern int remoteSocket; - -extern void InterframeCleanup(); - -void winlog(const char *msg, ...); - -/* Link ----------------------*/ -extern int InitLink(void); -extern void CloseLink(void); -//extern int linkid; -extern char inifile[]; -extern FILE *linklogfile; -/* ------------------- */ -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -int emulating = 0; -bool debugger = false; -int RGB_LOW_BITS_MASK = 0; -bool b16to32Video = false; -int systemFrameSkip = 0; -int systemSpeed = 0; -bool systemSoundOn = false; -u32 systemColorMap32[0x10000]; -u16 systemColorMap16[0x10000]; -u16 systemGbPalette[24]; -int systemRedShift = 0; -int systemBlueShift = 0; -int systemGreenShift = 0; -int systemColorDepth = 16; -int realsystemRedShift = 0; -int realsystemBlueShift = 0; -int realsystemGreenShift = 0; -int realsystemColorDepth = 16; -int systemVerbose = 0; -int systemDebug = 0; -int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; -bool soundBufferLow = 0; -void winSignal(int,int); -void winOutput(const char *, u32); - -void (*dbgSignal)(int,int) = winSignal; -void (*dbgOutput)(const char *, u32) = winOutput; - -#ifdef MMX -extern "C" bool cpu_mmx; -#endif - -namespace Sm60FPS -{ - float K_fCpuSpeed = 100.0f; // was 98.0f before, but why? - float K_fTargetFps = 60.0f * K_fCpuSpeed / 100; - float K_fDT = 1000.0f / K_fTargetFps; - - u32 dwTimeElapse; - u32 dwTime0; - u32 dwTime1; - u32 nFrameCnt; - float fWantFPS; - float fCurFPS; - bool bLastSkip; - int nCurSpeed; - int bSaveMoreCPU; -}; - -#ifdef LOG_PERFORMANCE -#ifndef PERFORMANCE_INTERVAL -#define PERFORMANCE_INTERVAL 3600 -#endif -int systemSpeedTable[PERFORMANCE_INTERVAL]; -unsigned int systemSpeedCounter; -#endif - -void directXMessage(const char *msg) -{ - systemMessage(IDS_DIRECTX_7_REQUIRED, - "DirectX 7.0 or greater is required to run.\nDownload at http://www.microsoft.com/directx.\n\nError found at: %s", - msg); -} - -///////////////////////////////////////////////////////////////////////////// -// VBA - -BEGIN_MESSAGE_MAP(VBA, CWinApp) - //{{AFX_MSG_MAP(VBA) - // NOTE - the ClassWizard will add and remove mapping macros here. - // DO NOT EDIT what you see in these blocks of generated code! - //}}AFX_MSG_MAP - END_MESSAGE_MAP() - - ///////////////////////////////////////////////////////////////////////////// -// VBA construction - -VBA::VBA() -{ - mode320Available = false; - mode640Available = false; - mode800Available = false; - mode1024Available = false; - mode1280Available = false; - windowPositionX = 0; - windowPositionY = 0; - filterFunction = NULL; - ifbFunction = NULL; - ifbType = 0; - filterType = FILTER_NONE; - filterWidth = 0; - filterHeight = 0; - fsAdapter = 0; - fsWidth = 0; - fsHeight = 0; - fsColorDepth = 0; - fsFrequency = 0; - fsForceChange = false; - surfaceSizeX = 0; - surfaceSizeY = 0; - sizeX = 0; - sizeY = 0; - videoOption = 0; - fullScreenStretch = false; - disableStatusMessage = false; - showSpeed = 0; - showSpeedTransparent = true; - showRenderedFrames = 0; - screenMessage = false; - screenMessageTime = 0; - menuToggle = true; - display = NULL; - menu = NULL; - popup = NULL; - cartridgeType = IMAGE_GBA; - soundInitialized = false; - useBiosFileGBA = false; - useBiosFileGB = false; - skipBiosFile = false; - biosFileNameGBA = _T(""); - biosFileNameGB = _T(""); - active = true; - paused = false; - recentFreeze = false; - autoSaveLoadCheatList = false; - winout = NULL; - removeIntros = false; - autoIPS = true; - winGbBorderOn = 0; - winFlashSize = 0x20000; - winRtcEnable = false; - winGenericflashcardEnable = false; - winSaveType = 0; - rewindMemory = NULL; - rewindPos = 0; - rewindTopPos = 0; - rewindCounter = 0; - rewindCount = 0; - rewindSaveNeeded = false; - rewindTimer = 0; - captureFormat = 0; - tripleBuffering = true; - throttle = 0; - autoFrameSkipLastTime = 0; - autoFrameSkip = false; - vsync = false; - changingVideoSize = false; - renderMethod = DIRECT_3D; - audioAPI = DIRECTSOUND; -#ifndef NO_OAL - oalDevice = NULL; - oalBufferCount = 5; -#endif - iconic = false; -#ifndef NO_D3D - d3dFilter = 0; - d3dMotionBlur = false; -#endif - glFilter = 0; - regEnabled = false; - pauseWhenInactive = true; - speedupToggle = false; - winGbPrinterEnabled = false; - threadPriority = 2; - disableMMX = false; - languageOption = 0; - languageModule = NULL; - languageName = ""; - renderedFrames = 0; - input = NULL; - joypadDefault = 0; - autoFire = 0; - autoFireToggle = false; - winPauseNextFrame = false; - soundRecording = false; - soundRecorder = NULL; - dsoundDisableHardwareAcceleration = true; - sound = NULL; - aviRecording = false; - aviRecorder = NULL; - painting = false; - skipAudioFrames = 0; - movieRecording = false; - moviePlaying = false; - movieFrame = 0; - moviePlayFrame = 0; - movieFile = NULL; - movieLastJoypad = 0; - movieNextJoypad = 0; - sensorX = 2047; - sensorY = 2047; - mouseCounter = 0; - wasPaused = false; - frameskipadjust = 0; - autoLoadMostRecent = false; - fsMaxScale = 0; - romSize = 0; - lastWindowed = VIDEO_3X; - lastFullscreen = VIDEO_1024x768; - - updateCount = 0; - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - ZeroMemory(&emulator, sizeof(emulator)); - - hAccel = NULL; - - for(int i = 0; i < 24;) { - systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10); - systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10); - systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10); - systemGbPalette[i++] = 0; - } -} - -VBA::~VBA() -{ - rpiCleanup(); - InterframeCleanup(); - - char winBuffer[2048]; - - GetModuleFileName(NULL, winBuffer, 2048); - char *p = strrchr(winBuffer, '\\'); - if(p) - *p = 0; - - regInit(winBuffer); - - saveSettings(); - - if(moviePlaying) { - if(movieFile != NULL) { - fclose(movieFile); - movieFile = NULL; - } - moviePlaying = false; - movieLastJoypad = 0; - } - - if(movieRecording) { - if(movieFile != NULL) { - // record the last joypad change so that the correct time can be - // recorded - fwrite(&movieFrame, 1, sizeof(int), movieFile); - fwrite(&movieLastJoypad, 1, sizeof(u32), movieFile); - fclose(movieFile); - movieFile = NULL; - } - movieRecording = false; - moviePlaying = false; - movieLastJoypad = 0; - } - - soundPause(); - soundShutdown(); - - if(gbRom != NULL || rom != NULL) { - if(autoSaveLoadCheatList) - ((MainWnd *)m_pMainWnd)->winSaveCheatListDefault(); - ((MainWnd *)m_pMainWnd)->writeBatteryFile(); - cheatSearchCleanup(&cheatSearchData); - emulator.emuCleanUp(); - } - - if(input) - delete input; - - shutdownDisplay(); - - if(rewindMemory) - free(rewindMemory); - -#ifndef NO_OAL - if( oalDevice ) { - free( oalDevice ); - } -#endif -} - -///////////////////////////////////////////////////////////////////////////// -// The one and only VBA object - -VBA theApp; -///////////////////////////////////////////////////////////////////////////// -// VBA initialization - -// code from SDL_main.c for Windows -/* Parse a command line buffer into arguments */ -static int parseCommandLine(char *cmdline, char **argv) -{ - char *bufp; - int argc; - - argc = 0; - for ( bufp = cmdline; *bufp; ) { - /* Skip leading whitespace */ - while ( isspace(*bufp) ) { - ++bufp; - } - /* Skip over argument */ - if ( *bufp == '"' ) { - ++bufp; - if ( *bufp ) { - if ( argv ) { - argv[argc] = bufp; - } - ++argc; - } - /* Skip over word */ - while ( *bufp && (*bufp != '"') ) { - ++bufp; - } - } else { - if ( *bufp ) { - if ( argv ) { - argv[argc] = bufp; - } - ++argc; - } - /* Skip over word */ - while ( *bufp && ! isspace(*bufp) ) { - ++bufp; - } - } - if ( *bufp ) { - if ( argv ) { - *bufp = '\0'; - } - ++bufp; - } - } - if ( argv ) { - argv[argc] = NULL; - } - return(argc); -} - -BOOL VBA::InitInstance() -{ -#if _MSC_VER < 1400 -#ifdef _AFXDLL - Enable3dControls(); // Call this when using MFC in a shared DLL -#else - Enable3dControlsStatic(); // Call this when linking to MFC statically -#endif -#endif - - SetRegistryKey(_T("VBA")); - - remoteSetProtocol(0); - - systemVerbose = GetPrivateProfileInt("config", - "verbose", - 0, - MakeInstanceFilename("VBA.ini")); - - systemDebug = GetPrivateProfileInt("config", - "debug", - 0, - MakeInstanceFilename("VBA.ini")); - - wndClass = AfxRegisterWndClass(0, LoadCursor(IDC_ARROW), (HBRUSH)GetStockObject(BLACK_BRUSH), LoadIcon(IDI_MAINICON)); - - char winBuffer[2048]; - - GetModuleFileName(NULL, winBuffer, 2048); - char *p = strrchr(winBuffer, '\\'); - if(p) - *p = 0; - - if(!InitLink()) - return FALSE;; - - regInit(winBuffer); - - loadSettings(); - - if(!openLinkLog()) - return FALSE; - - if(!initInput()) - return FALSE; - - if(!initDisplay()) { - if(videoOption >= VIDEO_320x240) { - regSetDwordValue("video", VIDEO_1X); - } - return FALSE; - } - - hAccel = LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCELERATOR)); - - winAccelMgr.Connect((MainWnd *)m_pMainWnd); - - winAccelMgr.SetRegKey(HKEY_CURRENT_USER, "Software\\Emulators\\VisualBoyAdvance"); - - extern void winAccelAddCommands(CAcceleratorManager&); - - winAccelAddCommands(winAccelMgr); - - winAccelMgr.CreateDefaultTable(); - - winAccelMgr.Load(); - - winAccelMgr.UpdateWndTable(); - - winAccelMgr.UpdateMenu(menu); - - if (m_lpCmdLine[0]) - { - int argc = parseCommandLine(m_lpCmdLine, NULL); - char **argv = (char **)malloc((argc+1)*sizeof(char *)); - parseCommandLine(m_lpCmdLine, argv); - if(argc > 0) { - szFile = argv[0]; - filename = szFile; - } - int index = filename.ReverseFind('.'); - - if(index != -1) - filename = filename.Left(index); - - if(((MainWnd*)m_pMainWnd)->FileRun()) - emulating = true; - else - emulating = false; - free(argv); - } - - return TRUE; -} - -void VBA::adjustDestRect() -{ - POINT point; - - point.x = 0; - point.y = 0; - - m_pMainWnd->ClientToScreen(&point); - dest.top = point.y; - dest.left = point.x; - - point.x = surfaceSizeX; - point.y = surfaceSizeY; - - m_pMainWnd->ClientToScreen(&point); - dest.bottom = point.y; - dest.right = point.x; - - // make sure that dest rect lies in the monitor - if(videoOption >= VIDEO_320x240) { - dest.top -= windowPositionY; - dest.left -= windowPositionX; - dest.bottom-= windowPositionY; - dest.right -= windowPositionX; - } - - int menuSkip = 0; - - if(videoOption >= VIDEO_320x240 && menuToggle) { - int m = GetSystemMetrics(SM_CYMENU); - menuSkip = m; - dest.bottom -=m; - } - - if(videoOption > VIDEO_4X) { - int top = (fsHeight - surfaceSizeY) / 2; - int left = (fsWidth - surfaceSizeX) / 2; - dest.top += top; - dest.bottom += top; - dest.left += left; - dest.right += left; - if(fullScreenStretch) { - dest.top = 0+menuSkip; - dest.left = 0; - dest.right = fsWidth; - dest.bottom = fsHeight; - } - } -} - - -void VBA::updateIFB() -{ - if(systemColorDepth == 16) { - switch(ifbType) { - case 0: - default: - ifbFunction = NULL; - break; - case 1: - ifbFunction = MotionBlurIB; - break; - case 2: - ifbFunction = SmartIB; - break; - } - } else if(systemColorDepth == 32) { - switch(ifbType) { - case 0: - default: - ifbFunction = NULL; - break; - case 1: - ifbFunction = MotionBlurIB32; - break; - case 2: - ifbFunction = SmartIB32; - break; - } - } else - ifbFunction = NULL; -} - -void VBA::updateFilter() -{ - // BEGIN hacky ugly code - - // HQ3X asm wants 16 bit input. When we switch - // away from 16 bits we need to restore the driver values - - // This hack is also necessary for Kega Fusion filter plugins - - if ( b16to32Video ) - { - b16to32Video = false; - systemColorDepth = realsystemColorDepth; - systemRedShift = realsystemRedShift; - systemGreenShift = realsystemGreenShift; - systemBlueShift = realsystemBlueShift; - utilUpdateSystemColorMaps(); - } - // END hacky ugly code - - filterWidth = sizeX; - filterHeight = sizeY; - filterMagnification = 1; - - - if ( videoOption == VIDEO_1X || videoOption == VIDEO_320x240 ) - { - filterFunction = NULL; - filterMagnification = 1; - } - else - { - if ( systemColorDepth == 16 ) - { - switch(filterType) - { - default: - case FILTER_NONE: - filterFunction = NULL; - filterMagnification = 1; - break; - case FILTER_PLUGIN: - if( rpiInit( pluginName ) ) { - filterFunction = rpiFilter; - filterMagnification = rpiScaleFactor(); - } else { - filterType = FILTER_NONE; - updateFilter(); - return; - } - break; - case FILTER_TVMODE: - filterFunction = ScanlinesTV; - filterMagnification = 2; - break; - case FILTER_2XSAI: - filterFunction = _2xSaI; - filterMagnification = 2; - break; - case FILTER_SUPER2XSAI: - filterFunction = Super2xSaI; - filterMagnification = 2; - break; - case FILTER_SUPEREAGLE: - filterFunction = SuperEagle; - filterMagnification = 2; - break; - case FILTER_PIXELATE: - filterFunction = Pixelate; - filterMagnification = 2; - break; - case FILTER_MAMESCALE2X: - filterFunction = AdMame2x; - filterMagnification = 2; - break; - case FILTER_SIMPLE2X: - filterFunction = Simple2x16; - filterMagnification = 2; - break; - case FILTER_BILINEAR: - filterFunction = Bilinear; - filterMagnification = 2; - break; - case FILTER_BILINEARPLUS: - filterFunction = BilinearPlus; - filterMagnification = 2; - break; - case FILTER_SCANLINES: - filterFunction = Scanlines; - filterMagnification = 2; - break; - case FILTER_HQ2X: - filterFunction = hq2x; - filterMagnification = 2; - break; - case FILTER_LQ2X: - filterFunction = lq2x; - filterMagnification = 2; - break; - case FILTER_SIMPLE3X: - filterFunction = Simple3x16; - filterMagnification = 3; - break; - case FILTER_SIMPLE4X: - filterFunction = Simple4x16; - filterMagnification = 4; - break; - case FILTER_HQ3X: - filterFunction = hq3x16; - filterMagnification = 3; - break; - case FILTER_HQ4X: - filterFunction = hq4x16; - filterMagnification = 4; - break; - } - } - - if ( systemColorDepth == 32 ) - { - switch(filterType) - { - default: - case FILTER_NONE: - filterFunction = NULL; - filterMagnification = 1; - break; - case FILTER_PLUGIN: - if( rpiInit( pluginName ) ) { - filterFunction = rpiFilter; - filterMagnification = rpiScaleFactor(); - b16to32Video=true; - } else { - filterType = FILTER_NONE; - updateFilter(); - return; - } - break; - case FILTER_TVMODE: - filterFunction = ScanlinesTV32; - filterMagnification = 2; - break; - case FILTER_2XSAI: - filterFunction = _2xSaI32; - filterMagnification = 2; - break; - case FILTER_SUPER2XSAI: - filterFunction = Super2xSaI32; - filterMagnification = 2; - break; - case FILTER_SUPEREAGLE: - filterFunction = SuperEagle32; - filterMagnification = 2; - break; - case FILTER_PIXELATE: - filterFunction = Pixelate32; - filterMagnification = 2; - break; - case FILTER_MAMESCALE2X: - filterFunction = AdMame2x32; - filterMagnification = 2; - break; - case FILTER_SIMPLE2X: - filterFunction = Simple2x32; - filterMagnification = 2; - break; - case FILTER_BILINEAR: - filterFunction = Bilinear32; - filterMagnification = 2; - break; - case FILTER_BILINEARPLUS: - filterFunction = BilinearPlus32; - filterMagnification = 2; - break; - case FILTER_SCANLINES: - filterFunction = Scanlines32; - filterMagnification = 2; - break; - case FILTER_HQ2X: - filterFunction = hq2x32; - filterMagnification = 2; - break; - case FILTER_LQ2X: - filterFunction = lq2x32; - filterMagnification = 2; - break; - case FILTER_SIMPLE3X: - filterFunction = Simple3x32; - filterMagnification = 3; - break; - case FILTER_SIMPLE4X: - filterFunction = Simple4x32; - filterMagnification = 4; - break; - case FILTER_HQ3X: - filterFunction = hq3x32; - filterMagnification = 3; -#ifndef NO_ASM - b16to32Video=true; -#endif - break; - case FILTER_HQ4X: - filterFunction = hq4x32; - filterMagnification = 4; -#ifndef NO_ASM - b16to32Video=true; -#endif - break; - } - } - } - - rect.right = sizeX * filterMagnification; - rect.bottom = sizeY * filterMagnification; - - - if( filterType != FILTER_NONE ) - memset(delta, 0xFF, sizeof(delta)); - - if( display ) - display->changeRenderSize(rect.right, rect.bottom); - - if (b16to32Video && systemColorDepth!=16) - { - realsystemColorDepth = systemColorDepth; - systemColorDepth = 16; - realsystemRedShift = systemRedShift; - systemRedShift = 11; - realsystemGreenShift = systemGreenShift; - systemGreenShift = 6; - realsystemBlueShift = systemBlueShift; - systemBlueShift = 0; - utilUpdateSystemColorMaps(); - } - -#ifdef LOG_PERFORMANCE - memset( systemSpeedTable, 0x00, sizeof(systemSpeedTable) ); - systemSpeedCounter = 0; -#endif -} - - -void VBA::updateThrottle( unsigned short throttle ) -{ - this->throttle = throttle; - - if( throttle == 0 ) { - autoFrameSkip = false; - return; - } else { - Sm60FPS::K_fCpuSpeed = (float)throttle; - Sm60FPS::K_fTargetFps = 60.0f * Sm60FPS::K_fCpuSpeed / 100; - Sm60FPS::K_fDT = 1000.0f / Sm60FPS::K_fTargetFps; - autoFrameSkip = true; - frameSkip = 0; - systemFrameSkip = 0; - return; - } -} - - -void VBA::updateMenuBar() -{ - if(menu != NULL) { - if(m_pMainWnd) - m_pMainWnd->SetMenu(NULL); - m_menu.Detach(); - DestroyMenu(menu); - } - - if(popup != NULL) { - // force popup recreation if language changed - DestroyMenu(popup); - popup = NULL; - } - - if( ( videoOption >= VIDEO_320x240 ) ) { - return; - } - - m_menu.Attach(winResLoadMenu(MAKEINTRESOURCE(IDR_MENU))); - menu = (HMENU)m_menu; - - if(m_pMainWnd) - m_pMainWnd->SetMenu(&m_menu); -} - -void winlog(const char *msg, ...) -{ - CString buffer; - va_list valist; - - va_start(valist, msg); - buffer.FormatV(msg, valist); - - if(theApp.winout == NULL) { - theApp.winout = fopen("vba-trace.log","w"); - } - - fputs(buffer, theApp.winout); - - va_end(valist); -} - -void log(const char *msg, ...) -{ - CString buffer; - va_list valist; - - va_start(valist, msg); - buffer.FormatV(msg, valist); - - toolsLog(buffer); - - va_end(valist); -} - -bool systemReadJoypads() -{ - if(theApp.input) - return theApp.input->readDevices(); - return false; -} - -u32 systemReadJoypad(int which) -{ - if(theApp.input) - return theApp.input->readDevice(which); - return 0; -} - -void systemDrawScreen() -{ - if(theApp.display == NULL) - return; - - theApp.renderedFrames++; - - if(theApp.updateCount) { - POSITION pos = theApp.updateList.GetHeadPosition(); - while(pos) { - IUpdateListener *up = theApp.updateList.GetNext(pos); - up->update(); - } - } - - if (Sm60FPS_CanSkipFrame()) - return; - - if( theApp.aviRecording ) { - if( theApp.painting ) { - theApp.skipAudioFrames++; - } else { - unsigned char *bmp; - unsigned short srcPitch = theApp.sizeX * ( systemColorDepth >> 3 ) + 4; - switch( systemColorDepth ) - { - case 16: - bmp = new unsigned char[ theApp.sizeX * theApp.sizeY * 2 ]; - cpyImg16bmp( bmp, pix + srcPitch, srcPitch, theApp.sizeX, theApp.sizeY ); - break; - case 32: - // use 24 bit colors to reduce video size - bmp = new unsigned char[ theApp.sizeX * theApp.sizeY * 3 ]; - cpyImg32bmp( bmp, pix + srcPitch, srcPitch, theApp.sizeX, theApp.sizeY ); - break; - } - if( false == theApp.aviRecorder->AddVideoFrame( bmp ) ) { - systemMessage( IDS_AVI_CANNOT_WRITE_VIDEO, "Cannot write video frame to AVI file." ); - delete theApp.aviRecorder; - theApp.aviRecorder = NULL; - theApp.aviRecording = false; - } - delete bmp; - } - } - - if( theApp.ifbFunction ) { - theApp.ifbFunction( pix + (theApp.filterWidth * (systemColorDepth>>3)) + 4, - (theApp.filterWidth * (systemColorDepth>>3)) + 4, - theApp.filterWidth, theApp.filterHeight ); - } - - if(!soundBufferLow) - { - theApp.display->render(); - Sm60FPS_Sleep(); - } - else - soundBufferLow = false; - -} - -void systemScreenCapture(int captureNumber) -{ - if(theApp.m_pMainWnd) - ((MainWnd *)theApp.m_pMainWnd)->screenCapture(captureNumber); -} - -u32 systemGetClock() -{ - return GetTickCount(); -} - -void systemMessage(int number, const char *defaultMsg, ...) -{ - CString buffer; - va_list valist; - CString msg = defaultMsg; - if(number) - msg = winResLoadString(number); - - va_start(valist, defaultMsg); - buffer.FormatV(msg, valist); - - AfxGetApp()->m_pMainWnd->MessageBox(buffer, winResLoadString(IDS_ERROR), MB_OK|MB_ICONERROR); - - va_end(valist); -} - -void systemSetTitle(const char *title) -{ - if(theApp.m_pMainWnd != NULL) { - AfxGetApp()->m_pMainWnd->SetWindowText(title); - } -} - -void systemShowSpeed(int speed) -{ - systemSpeed = speed; - theApp.showRenderedFrames = theApp.renderedFrames; - theApp.renderedFrames = 0; - if(theApp.videoOption <= VIDEO_4X && theApp.showSpeed) { - CString buffer; - if(theApp.showSpeed == 1) - buffer.Format("VisualBoyAdvance-%3d%%", systemSpeed); - else - buffer.Format("VisualBoyAdvance-%3d%%(%d, %d fps)", systemSpeed, - systemFrameSkip, - theApp.showRenderedFrames); - - systemSetTitle(buffer); - } -} - - -void systemFrame() -{ - if( theApp.movieRecording || theApp.moviePlaying ) { - theApp.movieFrame++; - } - -#ifdef LOG_PERFORMANCE - systemSpeedTable[systemSpeedCounter++ % PERFORMANCE_INTERVAL] = systemSpeed; -#endif -} - - -void system10Frames(int rate) -{ - if( theApp.autoFrameSkip ) - { - u32 time = systemGetClock(); - u32 diff = time - theApp.autoFrameSkipLastTime; - theApp.autoFrameSkipLastTime = time; - if( diff ) { - // countermeasure against div/0 when debugging - Sm60FPS::nCurSpeed = (1000000/rate)/diff; - } else { - Sm60FPS::nCurSpeed = 100; - } - } - - - if(theApp.rewindMemory) { - if(++theApp.rewindCounter >= (theApp.rewindTimer)) { - theApp.rewindSaveNeeded = true; - theApp.rewindCounter = 0; - } - } - if(systemSaveUpdateCounter) { - if(--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) { - ((MainWnd *)theApp.m_pMainWnd)->writeBatteryFile(); - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - } - } - - theApp.wasPaused = false; - -#ifdef LOG_PERFORMANCE - if( systemSpeedCounter >= PERFORMANCE_INTERVAL ) { - // log performance every PERFORMANCE_INTERVAL frames - float a = 0.0f; - for( unsigned short i = 0 ; i < PERFORMANCE_INTERVAL ; i++ ) { - a += (float)systemSpeedTable[i]; - } - a /= (float)PERFORMANCE_INTERVAL; - log( _T("Speed: %f\n"), a ); - systemSpeedCounter = 0; - } -#endif -} - -void systemScreenMessage(const char *msg) -{ - theApp.screenMessage = true; - theApp.screenMessageTime = GetTickCount(); - theApp.screenMessageBuffer = msg; - - if(theApp.screenMessageBuffer.GetLength() > 40) - theApp.screenMessageBuffer = theApp.screenMessageBuffer.Left(40); -} - -void systemUpdateMotionSensor() -{ - if(theApp.input) - theApp.input->checkMotionKeys(); -} - -int systemGetSensorX() -{ - return theApp.sensorX; -} - -int systemGetSensorY() -{ - return theApp.sensorY; -} - - -bool systemSoundInit() -{ - systemSoundShutdown(); - - switch( theApp.audioAPI ) - { - case DIRECTSOUND: - theApp.sound = newDirectSound(); - break; -#ifndef NO_OAL - case OPENAL_SOUND: - theApp.sound = newOpenAL(); - break; -#endif - } - - return theApp.sound->init(); -} - - -void systemSoundShutdown() -{ - if( theApp.aviRecorder ) { - delete theApp.aviRecorder; - theApp.aviRecorder = NULL; - } - theApp.aviRecording = false; - - - if( theApp.soundRecorder ) { - delete theApp.soundRecorder; - theApp.soundRecorder = NULL; - } - theApp.soundRecording = false; - - - if( theApp.sound ) { - delete theApp.sound; - theApp.sound = NULL; - } -} - - -void systemSoundPause() -{ - if(theApp.sound) - theApp.sound->pause(); -} - -void systemSoundReset() -{ - if(theApp.sound) - theApp.sound->reset(); -} - -void systemSoundResume() -{ - if(theApp.sound) - theApp.sound->resume(); -} - -void systemWriteDataToSoundBuffer() -{ - if( theApp.soundRecording ) { - if( theApp.soundRecorder ) { - theApp.soundRecorder->AddSound( (const u8 *)soundFinalWave, soundBufferLen ); - } else { - WAVEFORMATEX format; - format.cbSize = 0; - format.wFormatTag = WAVE_FORMAT_PCM; - format.nChannels = 2; - format.nSamplesPerSec = 44100 / soundQuality; - format.wBitsPerSample = 16; - format.nBlockAlign = format.nChannels * ( format.wBitsPerSample >> 3 ); - format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; - theApp.soundRecorder = new WavWriter; - if( theApp.soundRecorder->Open( theApp.soundRecordName ) ) { - theApp.soundRecorder->SetFormat( &format ); - } - } - } - - if( theApp.aviRecording && theApp.aviRecorder && !soundOffFlag ) { - if( theApp.skipAudioFrames ) { - theApp.skipAudioFrames--; - } else { - if( false == theApp.aviRecorder->AddAudioFrame( soundFinalWave ) ) { - systemMessage( IDS_AVI_CANNOT_WRITE_AUDIO, "Cannot write audio frame to AVI file." ); - delete theApp.aviRecorder; - theApp.aviRecorder = NULL; - theApp.aviRecording = false; - } - } - } - - if( theApp.sound ) { - theApp.sound->write(); - } -} - -bool systemCanChangeSoundQuality() -{ - return true; -} - -bool systemPauseOnFrame() -{ - if(theApp.winPauseNextFrame) { - theApp.paused = true; - theApp.winPauseNextFrame = false; - return true; - } - return false; -} - -void systemGbBorderOn() -{ - if(emulating && theApp.cartridgeType == IMAGE_GB && gbBorderOn) { - theApp.updateWindowSize(theApp.videoOption); - } -} - -BOOL VBA::OnIdle(LONG lCount) -{ - if(emulating && debugger) { - MSG msg; - remoteStubMain(); - if(debugger) - return TRUE; // continue loop - return !::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE); - } else if(emulating && active && !paused) { - for(int i = 0; i < 2; i++) { - emulator.emuMain(emulator.emuCount); - if(lanlink.connected&&linkid&&lc.numtransfers==0) lc.CheckConn(); - - if(rewindSaveNeeded && rewindMemory && emulator.emuWriteMemState) { - rewindCount++; - if(rewindCount > 8) - rewindCount = 8; - if(emulator.emuWriteMemState(&rewindMemory[rewindPos*REWIND_SIZE], - REWIND_SIZE)) { - rewindPos = ++rewindPos & 7; - if(rewindCount == 8) - rewindTopPos = ++rewindTopPos & 7; - } - } - - rewindSaveNeeded = false; - } - - if(mouseCounter) { - if(--mouseCounter == 0) { - SetCursor(NULL); - } - } - return TRUE; - } - return FALSE; - - // return CWinApp::OnIdle(lCount); -} - -void VBA::addRecentFile(CString file) -{ - // Do not change recent list if frozen - if(recentFreeze) - return; - int i = 0; - for(i = 0; i < 10; i++) { - if(recentFiles[i].GetLength() == 0) - break; - - if(recentFiles[i].Compare(file) == 0) { - if(i == 0) - return; - CString p = recentFiles[i]; - for(int j = i; j > 0; j--) { - recentFiles[j] = recentFiles[j-1]; - } - recentFiles[0] = p; - return; - } - } - int num = 0; - for(i = 0; i < 10; i++) { - if(recentFiles[i].GetLength() != 0) - num++; - } - if(num == 10) { - num--; - } - - for(i = num; i >= 1; i--) { - recentFiles[i] = recentFiles[i-1]; - } - recentFiles[0] = file; -} - -void VBA::loadSettings() -{ - CString buffer; - - lastFullscreen = (VIDEO_SIZE)regQueryDwordValue("lastFullscreen", VIDEO_1024x768); - - languageOption = regQueryDwordValue("language", 1); - if(languageOption < 0 || languageOption > 2) - languageOption = 1; - - buffer = regQueryStringValue("languageName", ""); - if(!buffer.IsEmpty()) { - languageName = buffer.Left(3); - } else - languageName = ""; - - winSetLanguageOption(languageOption, true); - - frameSkip = regQueryDwordValue("frameSkip", 0); - if(frameSkip < 0 || frameSkip > 9) - frameSkip = 0; - - gbFrameSkip = regQueryDwordValue("gbFrameSkip", 0); - if(gbFrameSkip < 0 || gbFrameSkip > 9) - gbFrameSkip = 0; - - vsync = regQueryDwordValue("vsync", false) ? true : false ; - synchronize = regQueryDwordValue("synchronize", 1) ? true : false; - fullScreenStretch = regQueryDwordValue("stretch", 0) ? true : false; - - videoOption = regQueryDwordValue("video", VIDEO_3X); - - strcpy(pluginName, regQueryStringValue("pluginName", "Scale2x.rpi")); - - if(videoOption < VIDEO_1X || videoOption > VIDEO_OTHER) - videoOption = VIDEO_3X; - - fsAdapter = regQueryDwordValue("fsAdapter", 0); - fsWidth = regQueryDwordValue("fsWidth", 800); - fsHeight = regQueryDwordValue("fsHeight", 600); - fsColorDepth = regQueryDwordValue("fsColorDepth", 32); - fsFrequency = regQueryDwordValue("fsFrequency", 60); - - if(videoOption == VIDEO_OTHER) { - if(fsWidth < 0 || fsWidth > 4095 || fsHeight < 0 || fsHeight > 4095) - videoOption = 0; - if(fsColorDepth != 16 && fsColorDepth != 24 && fsColorDepth != 32) - videoOption = 0; - } - - renderMethod = (DISPLAY_TYPE)regQueryDwordValue("renderMethod", DIRECT_3D); -#ifdef NO_OGL - if( renderMethod == OPENGL ) { - renderMethod = DIRECT_3D; - } -#endif -#ifdef NO_D3D - if( renderMethod == DIRECT_3D ) { - renderMethod = OPENGL; - } -#endif - - audioAPI = (AUDIO_API)regQueryDwordValue( "audioAPI", DIRECTSOUND ); - if( ( audioAPI != DIRECTSOUND ) -#ifndef NO_OAL - && ( audioAPI != OPENAL_SOUND ) -#endif - ) { - audioAPI = DIRECTSOUND; - } - - windowPositionX = regQueryDwordValue("windowX", 0); - if(windowPositionX < 0) - windowPositionX = 0; - windowPositionY = regQueryDwordValue("windowY", 0); - if(windowPositionY < 0) - windowPositionY = 0; - - useBiosFileGBA = ( regQueryDwordValue("useBiosGBA", 0) == 1 ) ? true : false; - - useBiosFileGB = ( regQueryDwordValue("useBiosGB", 0) == 1 ) ? true : false; - - skipBiosFile = regQueryDwordValue("skipBios", 0) ? true : false; - - buffer = regQueryStringValue("biosFileGBA", ""); - - if(!buffer.IsEmpty()) { - biosFileNameGBA = buffer; - } - - buffer = regQueryStringValue("biosFileGB", ""); - - if(!buffer.IsEmpty()) { - biosFileNameGB = buffer; - } - - int res = regQueryDwordValue("soundEnable", 0x30f); - - soundEnable(res); - soundDisable(~res); - - soundOffFlag = (regQueryDwordValue("soundOff", 0)) ? true : false; - - soundQuality = regQueryDwordValue("soundQuality", 1); - - soundEcho = regQueryDwordValue("soundEcho", 0) ? true : false; - - soundLowPass = regQueryDwordValue("soundLowPass", 0) ? true : false; - - soundReverse = regQueryDwordValue("soundReverse", 0) ? true : false; - - soundVolume = regQueryDwordValue("soundVolume", 0); - if(soundVolume < 0 || soundVolume > 5) - soundVolume = 0; - - soundInterpolation = regQueryDwordValue("soundInterpolation", 0); - if(soundInterpolation < 0 || soundInterpolation > 1) - soundInterpolation = 0; - - tripleBuffering = regQueryDwordValue("tripleBuffering", false) ? true : false; - -#ifndef NO_D3D - d3dFilter = regQueryDwordValue("d3dFilter", 1); - if(d3dFilter < 0 || d3dFilter > 1) - d3dFilter = 1; - - d3dMotionBlur = ( regQueryDwordValue("d3dMotionBlur", 0) == 1 ) ? true : false; -#endif - - glFilter = regQueryDwordValue("glFilter", 1); - if(glFilter < 0 || glFilter > 1) - glFilter = 1; - - - filterType = regQueryDwordValue("filter", 0); - if(filterType < 0 || filterType > 17) - filterType = 0; - - disableMMX = regQueryDwordValue("disableMMX", false) ? true: false; - - disableStatusMessage = regQueryDwordValue("disableStatus", 0) ? true : false; - - showSpeed = regQueryDwordValue("showSpeed", 0); - if(showSpeed < 0 || showSpeed > 2) - showSpeed = 0; - - showSpeedTransparent = regQueryDwordValue("showSpeedTransparent", TRUE) ? - TRUE : FALSE; - - winGbPrinterEnabled = regQueryDwordValue("gbPrinter", false) ? true : false; - - if(winGbPrinterEnabled) - gbSerialFunction = gbPrinterSend; - else - gbSerialFunction = NULL; - - pauseWhenInactive = regQueryDwordValue("pauseWhenInactive", 1) ? - true : false; - - captureFormat = regQueryDwordValue("captureFormat", 0); - - removeIntros = regQueryDwordValue("removeIntros", false) ? true : false; - - recentFreeze = regQueryDwordValue("recentFreeze", false) ? true : false; - - autoIPS = regQueryDwordValue("autoIPS", true) ? true : false; - - cpuDisableSfx = regQueryDwordValue("disableSfx", 0) ? true : false; - - winSaveType = regQueryDwordValue("saveType", 0); - if(winSaveType < 0 || winSaveType > 5) - winSaveType = 0; - - ifbType = regQueryDwordValue("ifbType", 0); - if(ifbType < 0 || ifbType > 2) - ifbType = 0; - - winFlashSize = regQueryDwordValue("flashSize", 0x10000); - if(winFlashSize != 0x10000 && winFlashSize != 0x20000) - winFlashSize = 0x10000; - flashSize = winFlashSize; - - agbPrintEnable(regQueryDwordValue("agbPrint", 0) ? true : false); - - winRtcEnable = regQueryDwordValue("rtcEnabled", 0) ? true : false; - rtcEnable(winRtcEnable); - - switch(videoOption) { - case VIDEO_320x240: - fsWidth = 320; - fsHeight = 240; - fsColorDepth = 16; - fsFrequency = 60; - break; - case VIDEO_640x480: - fsWidth = 640; - fsHeight = 480; - fsColorDepth = 16; - fsFrequency = 60; - break; - case VIDEO_800x600: - fsWidth = 800; - fsHeight = 600; - fsColorDepth = 16; - fsFrequency = 60; - break; - case VIDEO_1024x768: - fsWidth = 1024; - fsHeight = 768; - fsColorDepth = 16; - fsFrequency = 60; - break; - case VIDEO_1280x1024: - fsWidth = 1280; - fsHeight = 1024; - fsColorDepth = 16; - fsFrequency = 60; - break; - } - - winGbBorderOn = regQueryDwordValue("borderOn", 0); - gbBorderAutomatic = regQueryDwordValue("borderAutomatic", 0); - gbEmulatorType = regQueryDwordValue("emulatorType", 1); - if(gbEmulatorType < 0 || gbEmulatorType > 5) - gbEmulatorType = 1; - gbColorOption = regQueryDwordValue("colorOption", 0); - - threadPriority = regQueryDwordValue("priority", 2); - - if(threadPriority < 0 || threadPriority >3) - threadPriority = 2; - updatePriority(); - - autoSaveLoadCheatList = regQueryDwordValue("autoSaveCheatList", 0) ? - true : false; - - gbPaletteOption = regQueryDwordValue("gbPaletteOption", 0); - if(gbPaletteOption < 0) - gbPaletteOption = 0; - if(gbPaletteOption > 2) - gbPaletteOption = 2; - - regQueryBinaryValue("gbPalette", (char *)systemGbPalette, - 24*sizeof(u16)); - - rewindTimer = regQueryDwordValue("rewindTimer", 0); - - if(rewindTimer < 0 || rewindTimer > 600) - rewindTimer = 0; - - rewindTimer *= 6; // convert to 10 frames multiple - - if(rewindTimer != 0) - rewindMemory = (char *)malloc(8*REWIND_SIZE); - - for(int i = 0; i < 10; i++) { - buffer.Format("recent%d", i); - char *s = regQueryStringValue(buffer, NULL); - if(s == NULL) - break; - recentFiles[i] = s; - } - - joypadDefault = regQueryDwordValue("joypadDefault", 0); - if(joypadDefault < 0 || joypadDefault > 3) - joypadDefault = 0; - - autoLoadMostRecent = regQueryDwordValue("autoLoadMostRecent", false) ? true : - false; - - cheatsEnabled = regQueryDwordValue("cheatsEnabled", false) ? true : false; - - fsMaxScale = regQueryDwordValue("fsMaxScale", 0); - - updateThrottle( (unsigned short)regQueryDwordValue( "throttle", 0 ) ); - - linktimeout = regQueryDwordValue("LinkTimeout", 1000); - - linklog = regQueryDwordValue("Linklog", false) ? true : false; - if(linklog) - openLinkLog(); - - adapter = regQueryDwordValue("RFU", false) ? true : false; - linkenable = regQueryDwordValue("linkEnabled", false) ? true : false; - - lanlink.active = regQueryDwordValue("LAN", 0) ? true : false; - - Sm60FPS::bSaveMoreCPU = regQueryDwordValue("saveMoreCPU", 0); - -#ifndef NO_OAL - buffer = regQueryStringValue( "oalDevice", "Generic Software" ); - if( oalDevice ) { - free( oalDevice ); - } - oalDevice = (TCHAR*)malloc( ( buffer.GetLength() + 1 ) * sizeof( TCHAR ) ); - _tcscpy( oalDevice, buffer.GetBuffer() ); - - oalBufferCount = regQueryDwordValue( "oalBufferCount", 5 ); -#endif -} - -void VBA::updateFrameSkip() -{ - switch(cartridgeType) { - case 0: - systemFrameSkip = frameSkip; - break; - case 1: - systemFrameSkip = gbFrameSkip; - break; - } -} - -void VBA::updateVideoSize(UINT id) -{ - int value = 0; - - switch(id) { - case ID_OPTIONS_VIDEO_X1: - value = VIDEO_1X; - break; - case ID_OPTIONS_VIDEO_X2: - value = VIDEO_2X; - break; - case ID_OPTIONS_VIDEO_X3: - value = VIDEO_3X; - break; - case ID_OPTIONS_VIDEO_X4: - value = VIDEO_4X; - break; - case ID_OPTIONS_VIDEO_FULLSCREEN320X240: - value = VIDEO_320x240; - fsWidth = 320; - fsHeight = 240; - fsColorDepth = 16; - break; - case ID_OPTIONS_VIDEO_FULLSCREEN640X480: - value = VIDEO_640x480; - fsWidth = 640; - fsHeight = 480; - fsColorDepth = 16; - break; - case ID_OPTIONS_VIDEO_FULLSCREEN800X600: - value = VIDEO_800x600; - fsWidth = 800; - fsHeight = 600; - fsColorDepth = 16; - break; - case ID_OPTIONS_VIDEO_FULLSCREEN1024X768: - value = VIDEO_1024x768; - fsWidth = 1024; - fsHeight = 768; - fsColorDepth = 32; - break; - case ID_OPTIONS_VIDEO_FULLSCREEN1280X1024: - value = VIDEO_1280x1024; - fsWidth = 1280; - fsHeight = 1024; - fsColorDepth = 32; - break; - case ID_OPTIONS_VIDEO_FULLSCREEN: - value = VIDEO_OTHER; - break; - } - - updateWindowSize(value); -} - - -void VBA::updateWindowSize(int value) -{ - regSetDwordValue("video", value); - - if(value == VIDEO_OTHER) { - regSetDwordValue("fsWidth", fsWidth); - regSetDwordValue("fsHeight", fsHeight); - regSetDwordValue("fsColorDepth", fsColorDepth); - } - - if(((value >= VIDEO_320x240) && - (videoOption != value)) || - (videoOption >= VIDEO_320x240 && - value <= VIDEO_4X) || - fsForceChange) { - fsForceChange = false; - changingVideoSize = true; - if( videoOption <= VIDEO_4X ) { - lastWindowed = (VIDEO_SIZE)videoOption; // save for when leaving full screen - } else { - lastFullscreen = (VIDEO_SIZE)videoOption; // save for when using quick switch to fullscreen - } - shutdownDisplay(); - if(input) { - delete input; - input = NULL; - } - m_pMainWnd->DragAcceptFiles(FALSE); - CWnd *pWnd = m_pMainWnd; - m_pMainWnd = NULL; - pWnd->DestroyWindow(); - delete pWnd; - videoOption = value; - if(!initDisplay()) { - if(videoOption == VIDEO_320x240 || - videoOption == VIDEO_640x480 || - videoOption == VIDEO_800x600 || - videoOption == VIDEO_1024x768 || - videoOption == VIDEO_1280x1024 || - videoOption == VIDEO_OTHER) { - regSetDwordValue("video", VIDEO_1X); - } - changingVideoSize = false; - AfxPostQuitMessage(0); - return; - } - if(!initInput()) { - changingVideoSize = false; - AfxPostQuitMessage(0); - return; - } - input->checkKeys(); - - - changingVideoSize = FALSE; - updateWindowSize(videoOption); - return; - } - - sizeX = 240; - sizeY = 160; - - videoOption = value; - - if(cartridgeType == IMAGE_GB) { - if(gbBorderOn) { - sizeX = 256; - sizeY = 224; - gbBorderLineSkip = 256; - gbBorderColumnSkip = 48; - gbBorderRowSkip = 40; - } else { - sizeX = 160; - sizeY = 144; - gbBorderLineSkip = 160; - gbBorderColumnSkip = 0; - gbBorderRowSkip = 0; - } - } - - surfaceSizeX = sizeX; - surfaceSizeY = sizeY; - - switch(videoOption) { - case VIDEO_1X: - surfaceSizeX = sizeX; - surfaceSizeY = sizeY; - break; - case VIDEO_2X: - surfaceSizeX = sizeX * 2; - surfaceSizeY = sizeY * 2; - break; - case VIDEO_3X: - surfaceSizeX = sizeX * 3; - surfaceSizeY = sizeY * 3; - break; - case VIDEO_4X: - surfaceSizeX = sizeX * 4; - surfaceSizeY = sizeY * 4; - break; - case VIDEO_320x240: - case VIDEO_640x480: - case VIDEO_800x600: - case VIDEO_1024x768: - case VIDEO_1280x1024: - case VIDEO_OTHER: - { - int scaleX = 1; - int scaleY = 1; - scaleX = (fsWidth / sizeX); - scaleY = (fsHeight / sizeY); - int min = scaleX < scaleY ? scaleX : scaleY; - if(fsMaxScale) - min = min > fsMaxScale ? fsMaxScale : min; - surfaceSizeX = min * sizeX; - surfaceSizeY = min * sizeY; - if((fullScreenStretch && (display != NULL && - (display->getType() != DIRECT_3D))) - || (display != NULL && display->getType() >= DIRECT_3D)) { - surfaceSizeX = fsWidth; - surfaceSizeY = fsHeight; - } - } - break; - } - - rect.right = sizeX; - rect.bottom = sizeY; - - int winSizeX = sizeX; - int winSizeY = sizeY; - - if(videoOption <= VIDEO_4X) { - dest.left = 0; - dest.top = 0; - dest.right = surfaceSizeX; - dest.bottom = surfaceSizeY; - - DWORD style = WS_POPUP | WS_VISIBLE; - - style |= WS_OVERLAPPEDWINDOW; - - menuToggle = TRUE; - AdjustWindowRectEx(&dest, style, TRUE, 0); //WS_EX_TOPMOST); - - winSizeX = dest.right-dest.left; - winSizeY = dest.bottom-dest.top; - - m_pMainWnd->SetWindowPos(0, //HWND_TOPMOST, - windowPositionX, - windowPositionY, - winSizeX, - winSizeY, - SWP_NOMOVE | SWP_SHOWWINDOW); - - // content of old seperate 'winCheckMenuBarInfo' function: - MENUBARINFO info; - info.cbSize = sizeof(MENUBARINFO); - theApp.m_pMainWnd->GetMenuBarInfo(OBJID_MENU, 0, &info); - int menuHeight = GetSystemMetrics(SM_CYMENU); // includes white line - if((info.rcBar.bottom - info.rcBar.top) > menuHeight) - { - winSizeY += (info.rcBar.bottom - info.rcBar.top) - menuHeight + 1; - m_pMainWnd->SetWindowPos( - 0, //HWND_TOPMOST, - theApp.windowPositionX, - theApp.windowPositionY, - winSizeX, - winSizeY, - SWP_NOMOVE | SWP_SHOWWINDOW); - } - } - - adjustDestRect(); - - updateIFB(); - updateFilter(); - - if(display) - display->resize(theApp.dest.right-theApp.dest.left, theApp.dest.bottom-theApp.dest.top); - - m_pMainWnd->RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN); -} - - -bool VBA::initDisplay() -{ - return updateRenderMethod(false); -} - - -bool VBA::preInitialize() -{ - switch( cartridgeType ) - { - case IMAGE_GBA: - sizeX = 240; - sizeY = 160; - break; - case IMAGE_GB: - if( gbBorderOn ) { - sizeX = 256; - sizeY = 224; - } else { - sizeX = 160; - sizeY = 144; - } - break; - } - - switch( videoOption ) - { - case VIDEO_1X: - surfaceSizeX = sizeX; - surfaceSizeY = sizeY; - break; - case VIDEO_2X: - surfaceSizeX = sizeX * 2; - surfaceSizeY = sizeY * 2; - break; - case VIDEO_3X: - surfaceSizeX = sizeX * 3; - surfaceSizeY = sizeY * 3; - break; - case VIDEO_4X: - surfaceSizeX = sizeX * 4; - surfaceSizeY = sizeY * 4; - break; - case VIDEO_320x240: - case VIDEO_640x480: - case VIDEO_800x600: - case VIDEO_1024x768: - case VIDEO_1280x1024: - case VIDEO_OTHER: - float scaleX = (float)fsWidth / sizeX; - float scaleY = (float)fsHeight / sizeY; - float min = ( scaleX < scaleY ) ? scaleX : scaleY; - if( fullScreenStretch ) { - surfaceSizeX = fsWidth; - surfaceSizeY = fsHeight; - } else { - surfaceSizeX = (int)( sizeX * min ); - surfaceSizeY = (int)( sizeY * min ); - } - break; - } - - rect.left = 0; - rect.top = 0; - rect.right = sizeX; - rect.bottom = sizeY; - - dest.left = 0; - dest.top = 0; - dest.right = surfaceSizeX; - dest.bottom = surfaceSizeY; - - - DWORD style = WS_POPUP | WS_VISIBLE; - DWORD styleEx = 0; - - if( videoOption <= VIDEO_4X ) { - style |= WS_OVERLAPPEDWINDOW; - } else { - styleEx = 0; - } - - if( videoOption <= VIDEO_4X ) { - AdjustWindowRectEx( &dest, style, TRUE, styleEx ); - } else { - AdjustWindowRectEx( &dest, style, FALSE, styleEx ); - } - - int winSizeX = dest.right-dest.left; - int winSizeY = dest.bottom-dest.top; - - if( videoOption > VIDEO_4X ) { - winSizeX = fsWidth; - winSizeY = fsHeight; - } - - int x = 0, y = 0; - - if( videoOption <= VIDEO_4X ) { - x = windowPositionX; - y = windowPositionY; - } - - - // Create a window - MainWnd *pWnd = new MainWnd; - m_pMainWnd = pWnd; - - pWnd->CreateEx( - styleEx, - wndClass, - _T("VisualBoyAdvance"), - style, - x, y, - winSizeX, winSizeY, - NULL, - 0 - ); - - if( !((HWND)*pWnd) ) { - winlog( "Error creating Window %08x\n", GetLastError() ); - return false; - } - pWnd->DragAcceptFiles( TRUE ); - updateMenuBar(); - adjustDestRect(); - - return true; -} - - -bool VBA::updateRenderMethod(bool force) -{ - bool ret = true; - - Sm60FPS_Init(); - - if( !updateRenderMethod0( force ) ) { - // fall back to safe configuration - renderMethod = DIRECT_3D; - fsAdapter = 0; - videoOption = VIDEO_1X; - ret = updateRenderMethod( true ); - } - - return ret; -} - - -bool VBA::updateRenderMethod0(bool force) -{ - bool initInput = false; - b16to32Video = false; - - if(display) { - if(display->getType() != renderMethod || force) { - initInput = true; - changingVideoSize = true; - shutdownDisplay(); - if(input) { - delete input; - input = NULL; - } - CWnd *pWnd = m_pMainWnd; - - m_pMainWnd = NULL; - pWnd->DragAcceptFiles(FALSE); - pWnd->DestroyWindow(); - delete pWnd; - - display = NULL; - regSetDwordValue("renderMethod", renderMethod); - } - } - if(display == NULL) { - switch(renderMethod) { -#ifndef NO_OGL - case OPENGL: - display = newOpenGLDisplay(); - break; -#endif -#ifndef NO_D3D - case DIRECT_3D: - display = newDirect3DDisplay(); - break; -#endif - } - - if( preInitialize() ) { - if( display->initialize() ) { - if( initInput ) { - if( !this->initInput() ) { - changingVideoSize = false; - AfxPostQuitMessage(0); - return false; - } - input->checkKeys(); - updateMenuBar(); - changingVideoSize = false; - updateWindowSize(videoOption); - - m_pMainWnd->ShowWindow(SW_SHOW); - m_pMainWnd->UpdateWindow(); - m_pMainWnd->SetFocus(); - - return true; - } else { - changingVideoSize = false; - return true; - } - } - } - changingVideoSize = false; - } - return true; -} - - -void VBA::shutdownDisplay() -{ - if(display != NULL) { - display->cleanup(); - delete display; - display = NULL; - } -} - -void VBA::directXMessage(const char *msg) -{ - systemMessage(IDS_DIRECTX_7_REQUIRED, - "DirectX 7.0 or greater is required to run.\nDownload at http://www.microsoft.com/directx.\n\nError found at: %s", - msg); -} - -void VBA::updatePriority() -{ - switch(threadPriority) { - case 0: - SetThreadPriority(THREAD_PRIORITY_HIGHEST); - break; - case 1: - SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL); - break; - case 3: - SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); - break; - default: - SetThreadPriority(THREAD_PRIORITY_NORMAL); - } -} - -#ifdef MMX -bool VBA::detectMMX() -{ - bool support = false; - char brand[13]; - - // check for Intel chip - __try { - __asm { - mov eax, 0; - cpuid; - mov [dword ptr brand+0], ebx; - mov [dword ptr brand+4], edx; - mov [dword ptr brand+8], ecx; - } - } - __except(EXCEPTION_EXECUTE_HANDLER) { - if(_exception_code() == STATUS_ILLEGAL_INSTRUCTION) { - return false; - } - return false; - } - // Check for Intel or AMD CPUs - if(strncmp(brand, "GenuineIntel", 12)) { - if(strncmp(brand, "AuthenticAMD", 12)) { - return false; - } - } - - __asm { - mov eax, 1; - cpuid; - test edx, 00800000h; - jz NotFound; - mov [support], 1; - NotFound: - } - return support; -} -#endif - -void VBA::winSetLanguageOption(int option, bool force) -{ - if(((option == languageOption) && option != 2) && !force) - return; - switch(option) { - case 0: - { - char lbuffer[10]; - - if(GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SABBREVLANGNAME, - lbuffer, 10)) { - HINSTANCE l = winLoadLanguage(lbuffer); - if(l == NULL) { - LCID locIdBase = MAKELCID( MAKELANGID( PRIMARYLANGID( GetSystemDefaultLangID() ), SUBLANG_NEUTRAL ), SORT_DEFAULT ); - if(GetLocaleInfo(locIdBase, LOCALE_SABBREVLANGNAME, - lbuffer, 10)) { - l = winLoadLanguage(lbuffer); - if(l == NULL) { - systemMessage(IDS_FAILED_TO_LOAD_LIBRARY, - "Failed to load library %s", - lbuffer); - return; - } - } - } - AfxSetResourceHandle(l); - if(languageModule != NULL) -#ifdef _AFXDLL - AfxFreeLibrary( languageModule ); -#else - FreeLibrary( languageModule ); -#endif - languageModule = l; - } else { - systemMessage(IDS_FAILED_TO_GET_LOCINFO, - "Failed to get locale information"); - return; - } - } - break; - case 1: - if(languageModule != NULL) -#ifdef _AFXDLL - AfxFreeLibrary( languageModule ); -#else - FreeLibrary( languageModule ); -#endif - languageModule = NULL; - AfxSetResourceHandle(AfxGetInstanceHandle()); - break; - case 2: - { - if(!force) { - LangSelect dlg; - if(dlg.DoModal()) { - HINSTANCE l = winLoadLanguage(languageName); - if(l == NULL) { - systemMessage(IDS_FAILED_TO_LOAD_LIBRARY, - "Failed to load library %s", - languageName); - return; - } - AfxSetResourceHandle(l); - if(languageModule != NULL) - { -#ifdef _AFXDLL - AfxFreeLibrary( languageModule ); -#else - FreeLibrary( languageModule ); -#endif - } - languageModule = l; - } - } else { - if(languageName.IsEmpty()) - return; - HINSTANCE l = winLoadLanguage(languageName); - if(l == NULL) { - systemMessage(IDS_FAILED_TO_LOAD_LIBRARY, - "Failed to load library %s", - languageName); - return; - } - AfxSetResourceHandle(l); - if(languageModule != NULL) - FreeLibrary(languageModule); - languageModule = l; - } - } - break; - } - languageOption = option; - updateMenuBar(); -} - -HINSTANCE VBA::winLoadLanguage(const char *name) -{ - CString buffer; - - buffer.Format( _T("vba_%s.dll"), name); - -#ifdef _AFXDLL - HINSTANCE l = AfxLoadLibrary( buffer ); -#else - HMODULE l = LoadLibrary( buffer ); -#endif - - if(l == NULL) { - if(strlen(name) == 3) { - char buffer2[3]; - buffer2[0] = name[0]; - buffer2[1] = name[1]; - buffer2[2] = 0; - buffer.Format("vba_%s.dll", buffer2); - -#ifdef _AFXDLL - return AfxLoadLibrary( buffer ); -#else - return LoadLibrary( buffer ); -#endif - } - } - return l; -} - - -bool VBA::initInput() -{ - if(input) - delete input; - input = newDirectInput(); - if(input->initialize()) { - input->loadSettings(); - input->checkKeys(); - return true; - } - delete input; - return false; -} - -void VBA::winAddUpdateListener(IUpdateListener *l) -{ - updateList.AddTail(l); - updateCount++; -} - -void VBA::winRemoveUpdateListener(IUpdateListener *l) -{ - POSITION pos = updateList.Find(l); - if(pos) { - updateList.RemoveAt(pos); - updateCount--; - if(updateCount < 0) - updateCount = 0; - } -} - -CString VBA::winLoadFilter(UINT id) -{ - CString res = winResLoadString(id); - res.Replace('_','|'); - - return res; -} - -void VBA::movieReadNext() -{ - if(movieFile) { - bool movieEnd = false; - - if(fread(&moviePlayFrame, 1, sizeof(int), movieFile) == sizeof(int)) { - if(fread(&movieNextJoypad, 1, sizeof(u32), movieFile) == sizeof(int)) { - // make sure we don't have spurious entries on the movie that can - // cause us to play it forever - if(moviePlayFrame <= movieFrame) - movieEnd = true; - } else - movieEnd = true; - } else - movieEnd = true; - if(movieEnd) { - CString string = winResLoadString(IDS_END_OF_MOVIE); - systemScreenMessage(string); - moviePlaying = false; - fclose(movieFile); - movieFile = NULL; - return; - } - } else - moviePlaying = false; -} - -void VBA::saveSettings() -{ - regSetDwordValue("language", languageOption); - - regSetStringValue("languageName", languageName); - - regSetDwordValue("frameSkip", frameSkip); - - regSetDwordValue("gbFrameSkip", gbFrameSkip); - - regSetDwordValue("vsync", vsync); - regSetDwordValue("synchronize", synchronize); - regSetDwordValue("stretch", fullScreenStretch); - - regSetDwordValue("video", videoOption); - - regSetDwordValue("fsAdapter", fsAdapter); - regSetDwordValue("fsWidth", fsWidth); - regSetDwordValue("fsHeight", fsHeight); - regSetDwordValue("fsColorDepth", fsColorDepth); - regSetDwordValue("fsFrequency", fsFrequency); - - regSetDwordValue("renderMethod", renderMethod); - regSetDwordValue( "audioAPI", audioAPI ); - - regSetDwordValue("windowX", windowPositionX); - regSetDwordValue("windowY", windowPositionY); - - regSetDwordValue("useBiosGBA", useBiosFileGBA); - - regSetDwordValue("useBiosGB", useBiosFileGB); - - regSetDwordValue("skipBios", skipBiosFile); - - if(!biosFileNameGBA.IsEmpty()) - regSetStringValue("biosFileGBA", biosFileNameGBA); - - if(!biosFileNameGB.IsEmpty()) - regSetStringValue("biosFileGB", biosFileNameGB); - - regSetDwordValue("soundEnable", soundGetEnable() & 0x30f); - - regSetDwordValue("soundOff", soundOffFlag); - - regSetDwordValue("soundQuality", soundQuality); - - regSetDwordValue("soundEcho", soundEcho); - - regSetDwordValue("soundLowPass", soundLowPass); - - regSetDwordValue("soundReverse", soundReverse); - - regSetDwordValue("soundVolume", soundVolume); - - regSetDwordValue("soundInterpolation", soundInterpolation); - regSetDwordValue("tripleBuffering", tripleBuffering); - -#ifndef NO_D3D - regSetDwordValue("d3dFilter", d3dFilter); - regSetDwordValue("d3dMotionBlur", d3dMotionBlur ? 1 : 0); -#endif - - regSetDwordValue("glFilter", glFilter); - - regSetDwordValue("filter", filterType); - - regSetDwordValue("LCDFilter", filterLCD); - - regSetDwordValue("disableMMX", disableMMX); - - regSetDwordValue("disableStatus", disableStatusMessage); - - regSetDwordValue("showSpeed", showSpeed); - - regSetDwordValue("showSpeedTransparent", showSpeedTransparent); - - regSetDwordValue("gbPrinter", winGbPrinterEnabled); - - regSetDwordValue("pauseWhenInactive", pauseWhenInactive); - - regSetDwordValue("captureFormat", captureFormat); - - regSetDwordValue("removeIntros", removeIntros); - - regSetDwordValue("recentFreeze", recentFreeze); - - regSetDwordValue("autoIPS", autoIPS); - - regSetDwordValue("disableSfx", cpuDisableSfx); - - regSetDwordValue("saveType", winSaveType); - - regSetDwordValue("ifbType", ifbType); - - regSetDwordValue("flashSize", winFlashSize); - - regSetDwordValue("agbPrint", agbPrintIsEnabled()); - - regSetDwordValue("rtcEnabled", winRtcEnable); - - regSetDwordValue("borderOn", winGbBorderOn); - regSetDwordValue("borderAutomatic", gbBorderAutomatic); - regSetDwordValue("emulatorType", gbEmulatorType); - regSetDwordValue("colorOption", gbColorOption); - - regSetDwordValue("priority", threadPriority); - - regSetDwordValue("autoSaveCheatList", autoSaveLoadCheatList); - - regSetDwordValue("gbPaletteOption", gbPaletteOption); - - regSetBinaryValue("gbPalette", (char *)systemGbPalette, - 24*sizeof(u16)); - - regSetDwordValue("rewindTimer", rewindTimer/6); - - CString buffer; - for(int i = 0; i < 10; i++) { - buffer.Format("recent%d", i); - regSetStringValue(buffer, recentFiles[i]); - } - - regSetDwordValue("joypadDefault", joypadDefault); - regSetDwordValue("autoLoadMostRecent", autoLoadMostRecent); - regSetDwordValue("cheatsEnabled", cheatsEnabled); - regSetDwordValue("fsMaxScale", fsMaxScale); - regSetDwordValue("throttle", throttle); - regSetStringValue("pluginName", pluginName); - regSetDwordValue("saveMoreCPU", Sm60FPS::bSaveMoreCPU); - regSetDwordValue("LinkTimeout", linktimeout); - regSetDwordValue("Linklog", linklog); - regSetDwordValue("RFU", adapter); - regSetDwordValue("linkEnabled", linkenable); - regSetDwordValue("lastFullscreen", lastFullscreen); - -#ifndef NO_OAL - regSetStringValue( "oalDevice", oalDevice ); - regSetDwordValue( "oalBufferCount", oalBufferCount ); -#endif -} - -void winSignal(int, int) -{ -} - -#define CPUReadByteQuick(addr) \ - map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] - -void winOutput(const char *s, u32 addr) -{ - if(s) { - toolsLog(s); - } else { - CString str; - char c; - - c = CPUReadByteQuick(addr); - addr++; - while(c) { - str += c; - c = CPUReadByteQuick(addr); - addr++; - } - toolsLog(str); - } -} - - -void Sm60FPS_Init() -{ - Sm60FPS::dwTimeElapse = 0; - Sm60FPS::fWantFPS = 60.f; - Sm60FPS::fCurFPS = 0.f; - Sm60FPS::nFrameCnt = 0; - Sm60FPS::bLastSkip = false; - Sm60FPS::nCurSpeed = 100; -} - - -bool Sm60FPS_CanSkipFrame() -{ - if( theApp.autoFrameSkip ) { - if( Sm60FPS::nFrameCnt == 0 ) { - Sm60FPS::nFrameCnt = 0; - Sm60FPS::dwTimeElapse = 0; - Sm60FPS::dwTime0 = timeGetTime(); - } else { - if( Sm60FPS::nFrameCnt >= 10 ) { - Sm60FPS::nFrameCnt = 0; - Sm60FPS::dwTimeElapse = 0; - - if( Sm60FPS::nCurSpeed > Sm60FPS::K_fCpuSpeed ) { - Sm60FPS::fWantFPS += 1; - if( Sm60FPS::fWantFPS > Sm60FPS::K_fTargetFps ){ - Sm60FPS::fWantFPS = Sm60FPS::K_fTargetFps; - } - } else { - if( Sm60FPS::nCurSpeed < (Sm60FPS::K_fCpuSpeed - 5) ) { - Sm60FPS::fWantFPS -= 1; - if( Sm60FPS::fWantFPS < 30.f ) { - Sm60FPS::fWantFPS = 30.f; - } - } - } - } else { // between frame 1-10 - Sm60FPS::dwTime1 = timeGetTime(); - Sm60FPS::dwTimeElapse += (Sm60FPS::dwTime1 - Sm60FPS::dwTime0); - Sm60FPS::dwTime0 = Sm60FPS::dwTime1; - if( !Sm60FPS::bLastSkip && - ( (Sm60FPS::fWantFPS < Sm60FPS::K_fTargetFps) || Sm60FPS::bSaveMoreCPU) ) { - Sm60FPS::fCurFPS = (float)Sm60FPS::nFrameCnt * 1000 / Sm60FPS::dwTimeElapse; - if( (Sm60FPS::fCurFPS < Sm60FPS::K_fTargetFps) || Sm60FPS::bSaveMoreCPU ) { - Sm60FPS::bLastSkip = true; - Sm60FPS::nFrameCnt++; - return true; - } - } - } - } - Sm60FPS::bLastSkip = false; - Sm60FPS::nFrameCnt++; - } - return false; -} - - -void Sm60FPS_Sleep() -{ - if( theApp.autoFrameSkip ) { - u32 dwTimePass = Sm60FPS::dwTimeElapse + (timeGetTime() - Sm60FPS::dwTime0); - u32 dwTimeShould = (u32)(Sm60FPS::nFrameCnt * Sm60FPS::K_fDT); - if( dwTimeShould > dwTimePass ) { - Sleep(dwTimeShould - dwTimePass); - } - } -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 Forgotten and the VBA development team +// Copyright (C) 2007-2008 VBA-M development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifdef NO_D3D +#ifdef NO_OGL +#error NO_D3D and NO_OGL must not be defined at the same time. +#endif +#endif + +#include "stdafx.h" + +#include "AVIWrite.h" +#include "LangSelect.h" +#include "MainWnd.h" +#include "Reg.h" +#include "resource.h" +#include "WavWriter.h" +#include "WinResUtil.h" +#include "Logging.h" +#include "rpi.h" + +#include "../System.h" +#include "../agb/agbprint.h" +#include "../cheatSearch.h" +#include "../agb/GBA.h" +#include "../Globals.h" +#include "../RTC.h" +#include "../Sound.h" +#include "../Util.h" +#include "../dmg/gbGlobals.h" +#include "../dmg/gbPrinter.h" + +/* Link +---------------------*/ +#include "../agb/GBALink.h" +/* ---------------- */ + +#include "../agb/gbafilter.h" + +#ifdef SDL +#pragma comment( lib, "SDL" ) +#pragma comment( lib, "SDLmain" ) +#endif + +extern void Pixelate(u8*,u32,u8*,u8*,u32,int,int); +extern void Pixelate32(u8*,u32,u8*,u8*,u32,int,int); +extern void _2xSaI(u8*,u32,u8*,u8*,u32,int,int); +extern void _2xSaI32(u8*,u32,u8*,u8*,u32,int,int); +extern void Super2xSaI(u8*,u32,u8*,u8*,u32,int,int); +extern void Super2xSaI32(u8*,u32,u8*,u8*,u32,int,int); +extern void SuperEagle(u8*,u32,u8*,u8*,u32,int,int); +extern void SuperEagle32(u8*,u32,u8*,u8*,u32,int,int); +extern void AdMame2x(u8*,u32,u8*,u8*,u32,int,int); +extern void AdMame2x32(u8*,u32,u8*,u8*,u32,int,int); +extern void Bilinear(u8*,u32,u8*,u8*,u32,int,int); +extern void Bilinear32(u8*,u32,u8*,u8*,u32,int,int); +extern void BilinearPlus(u8*,u32,u8*,u8*,u32,int,int); +extern void BilinearPlus32(u8*,u32,u8*,u8*,u32,int,int); +extern void Scanlines(u8*,u32,u8*,u8*,u32,int,int); +extern void Scanlines32(u8*,u32,u8*,u8*,u32,int,int); +extern void ScanlinesTV(u8*,u32,u8*,u8*,u32,int,int); +extern void ScanlinesTV32(u8*,u32,u8*,u8*,u32,int,int); +extern void hq2x(u8*,u32,u8*,u8*,u32,int,int); +extern void hq2x32(u8*,u32,u8*,u8*,u32,int,int); +extern void lq2x(u8*,u32,u8*,u8*,u32,int,int); +extern void lq2x32(u8*,u32,u8*,u8*,u32,int,int); +extern void Simple2x16(u8*,u32,u8*,u8*,u32,int,int); +extern void Simple2x32(u8*,u32,u8*,u8*,u32,int,int); +extern void Simple3x16(u8*,u32,u8*,u8*,u32,int,int); +extern void Simple3x32(u8*,u32,u8*,u8*,u32,int,int); +extern void Simple4x16(u8*,u32,u8*,u8*,u32,int,int); +extern void Simple4x32(u8*,u32,u8*,u8*,u32,int,int); +extern void hq3x16(u8*,u32,u8*,u8*,u32,int,int); +extern void hq4x16(u8*,u32,u8*,u8*,u32,int,int); +extern void hq3x32(u8*,u32,u8*,u8*,u32,int,int); +extern void hq4x32(u8*,u32,u8*,u8*,u32,int,int); + +extern void SmartIB(u8*,u32,int,int); +extern void SmartIB32(u8*,u32,int,int); +extern void MotionBlurIB(u8*,u32,int,int); +extern void MotionBlurIB32(u8*,u32,int,int); + +extern IDisplay *newGDIDisplay(); +extern IDisplay *newDirectDrawDisplay(); +#ifndef NO_OGL +extern IDisplay *newOpenGLDisplay(); +#endif +#ifndef NO_D3D +extern IDisplay *newDirect3DDisplay(); +#endif + +extern Input *newDirectInput(); + +extern ISound *newDirectSound(); +#ifndef NO_OAL +extern ISound *newOpenAL(); +#endif + +extern void remoteStubSignal(int, int); +extern void remoteOutput(char *, u32); +extern void remoteStubMain(); +extern void remoteSetProtocol(int); +extern void remoteCleanUp(); +extern int remoteSocket; + +extern void InterframeCleanup(); + +void winlog(const char *msg, ...); + +/* Link +---------------------*/ +extern int InitLink(void); +extern void CloseLink(void); +//extern int linkid; +extern char inifile[]; +extern FILE *linklogfile; +/* ------------------- */ +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +int emulating = 0; +bool debugger = false; +int RGB_LOW_BITS_MASK = 0; +bool b16to32Video = false; +int systemFrameSkip = 0; +int systemSpeed = 0; +bool systemSoundOn = false; +u32 systemColorMap32[0x10000]; +u16 systemColorMap16[0x10000]; +u16 systemGbPalette[24]; +int systemRedShift = 0; +int systemBlueShift = 0; +int systemGreenShift = 0; +int systemColorDepth = 16; +int realsystemRedShift = 0; +int realsystemBlueShift = 0; +int realsystemGreenShift = 0; +int realsystemColorDepth = 16; +int systemVerbose = 0; +int systemDebug = 0; +int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; +bool soundBufferLow = 0; +void winSignal(int,int); +void winOutput(const char *, u32); + +void (*dbgSignal)(int,int) = winSignal; +void (*dbgOutput)(const char *, u32) = winOutput; + +#ifdef MMX +extern "C" bool cpu_mmx; +#endif + +namespace Sm60FPS +{ + float K_fCpuSpeed = 100.0f; // was 98.0f before, but why? + float K_fTargetFps = 60.0f * K_fCpuSpeed / 100; + float K_fDT = 1000.0f / K_fTargetFps; + + u32 dwTimeElapse; + u32 dwTime0; + u32 dwTime1; + u32 nFrameCnt; + float fWantFPS; + float fCurFPS; + bool bLastSkip; + int nCurSpeed; + int bSaveMoreCPU; +}; + +#ifdef LOG_PERFORMANCE +#ifndef PERFORMANCE_INTERVAL +#define PERFORMANCE_INTERVAL 3600 +#endif +int systemSpeedTable[PERFORMANCE_INTERVAL]; +unsigned int systemSpeedCounter; +#endif + +void directXMessage(const char *msg) +{ + systemMessage(IDS_DIRECTX_7_REQUIRED, + "DirectX 7.0 or greater is required to run.\nDownload at http://www.microsoft.com/directx.\n\nError found at: %s", + msg); +} + +///////////////////////////////////////////////////////////////////////////// +// VBA + +BEGIN_MESSAGE_MAP(VBA, CWinApp) + //{{AFX_MSG_MAP(VBA) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG_MAP + END_MESSAGE_MAP() + + ///////////////////////////////////////////////////////////////////////////// +// VBA construction + +VBA::VBA() +{ + mode320Available = false; + mode640Available = false; + mode800Available = false; + mode1024Available = false; + mode1280Available = false; + windowPositionX = 0; + windowPositionY = 0; + filterFunction = NULL; + ifbFunction = NULL; + ifbType = 0; + filterType = FILTER_NONE; + filterWidth = 0; + filterHeight = 0; + fsAdapter = 0; + fsWidth = 0; + fsHeight = 0; + fsColorDepth = 0; + fsFrequency = 0; + fsForceChange = false; + surfaceSizeX = 0; + surfaceSizeY = 0; + sizeX = 0; + sizeY = 0; + videoOption = 0; + fullScreenStretch = false; + disableStatusMessage = false; + showSpeed = 0; + showSpeedTransparent = true; + showRenderedFrames = 0; + screenMessage = false; + screenMessageTime = 0; + menuToggle = true; + display = NULL; + menu = NULL; + popup = NULL; + cartridgeType = IMAGE_GBA; + soundInitialized = false; + useBiosFileGBA = false; + useBiosFileGB = false; + skipBiosFile = false; + biosFileNameGBA = _T(""); + biosFileNameGB = _T(""); + active = true; + paused = false; + recentFreeze = false; + autoSaveLoadCheatList = false; + winout = NULL; + removeIntros = false; + autoIPS = true; + winGbBorderOn = 0; + winFlashSize = 0x20000; + winRtcEnable = false; + winGenericflashcardEnable = false; + winSaveType = 0; + rewindMemory = NULL; + rewindPos = 0; + rewindTopPos = 0; + rewindCounter = 0; + rewindCount = 0; + rewindSaveNeeded = false; + rewindTimer = 0; + captureFormat = 0; + tripleBuffering = true; + throttle = 0; + autoFrameSkipLastTime = 0; + autoFrameSkip = false; + vsync = false; + changingVideoSize = false; + renderMethod = DIRECT_3D; + audioAPI = DIRECTSOUND; +#ifndef NO_OAL + oalDevice = NULL; + oalBufferCount = 5; +#endif + iconic = false; +#ifndef NO_D3D + d3dFilter = 0; + d3dMotionBlur = false; +#endif + glFilter = 0; + regEnabled = false; + pauseWhenInactive = true; + speedupToggle = false; + winGbPrinterEnabled = false; + threadPriority = 2; + disableMMX = false; + languageOption = 0; + languageModule = NULL; + languageName = ""; + renderedFrames = 0; + input = NULL; + joypadDefault = 0; + autoFire = 0; + autoFireToggle = false; + winPauseNextFrame = false; + soundRecording = false; + soundRecorder = NULL; + dsoundDisableHardwareAcceleration = true; + sound = NULL; + aviRecording = false; + aviRecorder = NULL; + painting = false; + skipAudioFrames = 0; + movieRecording = false; + moviePlaying = false; + movieFrame = 0; + moviePlayFrame = 0; + movieFile = NULL; + movieLastJoypad = 0; + movieNextJoypad = 0; + sensorX = 2047; + sensorY = 2047; + mouseCounter = 0; + wasPaused = false; + frameskipadjust = 0; + autoLoadMostRecent = false; + fsMaxScale = 0; + romSize = 0; + lastWindowed = VIDEO_3X; + lastFullscreen = VIDEO_1024x768; + + updateCount = 0; + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + ZeroMemory(&emulator, sizeof(emulator)); + + hAccel = NULL; + + for(int i = 0; i < 24;) { + systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10); + systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10); + systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10); + systemGbPalette[i++] = 0; + } +} + +VBA::~VBA() +{ + rpiCleanup(); + InterframeCleanup(); + + char winBuffer[2048]; + + GetModuleFileName(NULL, winBuffer, 2048); + char *p = strrchr(winBuffer, '\\'); + if(p) + *p = 0; + + regInit(winBuffer); + + saveSettings(); + + if(moviePlaying) { + if(movieFile != NULL) { + fclose(movieFile); + movieFile = NULL; + } + moviePlaying = false; + movieLastJoypad = 0; + } + + if(movieRecording) { + if(movieFile != NULL) { + // record the last joypad change so that the correct time can be + // recorded + fwrite(&movieFrame, 1, sizeof(int), movieFile); + fwrite(&movieLastJoypad, 1, sizeof(u32), movieFile); + fclose(movieFile); + movieFile = NULL; + } + movieRecording = false; + moviePlaying = false; + movieLastJoypad = 0; + } + + soundPause(); + soundShutdown(); + + if(gbRom != NULL || rom != NULL) { + if(autoSaveLoadCheatList) + ((MainWnd *)m_pMainWnd)->winSaveCheatListDefault(); + ((MainWnd *)m_pMainWnd)->writeBatteryFile(); + cheatSearchCleanup(&cheatSearchData); + emulator.emuCleanUp(); + } + + if(input) + delete input; + + shutdownDisplay(); + + if(rewindMemory) + free(rewindMemory); + +#ifndef NO_OAL + if( oalDevice ) { + free( oalDevice ); + } +#endif +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only VBA object + +VBA theApp; +///////////////////////////////////////////////////////////////////////////// +// VBA initialization + +// code from SDL_main.c for Windows +/* Parse a command line buffer into arguments */ +static int parseCommandLine(char *cmdline, char **argv) +{ + char *bufp; + int argc; + + argc = 0; + for ( bufp = cmdline; *bufp; ) { + /* Skip leading whitespace */ + while ( isspace(*bufp) ) { + ++bufp; + } + /* Skip over argument */ + if ( *bufp == '"' ) { + ++bufp; + if ( *bufp ) { + if ( argv ) { + argv[argc] = bufp; + } + ++argc; + } + /* Skip over word */ + while ( *bufp && (*bufp != '"') ) { + ++bufp; + } + } else { + if ( *bufp ) { + if ( argv ) { + argv[argc] = bufp; + } + ++argc; + } + /* Skip over word */ + while ( *bufp && ! isspace(*bufp) ) { + ++bufp; + } + } + if ( *bufp ) { + if ( argv ) { + *bufp = '\0'; + } + ++bufp; + } + } + if ( argv ) { + argv[argc] = NULL; + } + return(argc); +} + +BOOL VBA::InitInstance() +{ +#if _MSC_VER < 1400 +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +#endif + + SetRegistryKey(_T("VBA")); + + remoteSetProtocol(0); + + systemVerbose = GetPrivateProfileInt("config", + "verbose", + 0, + MakeInstanceFilename("VBA.ini")); + + systemDebug = GetPrivateProfileInt("config", + "debug", + 0, + MakeInstanceFilename("VBA.ini")); + + wndClass = AfxRegisterWndClass(0, LoadCursor(IDC_ARROW), (HBRUSH)GetStockObject(BLACK_BRUSH), LoadIcon(IDI_MAINICON)); + + char winBuffer[2048]; + + GetModuleFileName(NULL, winBuffer, 2048); + char *p = strrchr(winBuffer, '\\'); + if(p) + *p = 0; + + if(!InitLink()) + return FALSE;; + + regInit(winBuffer); + + loadSettings(); + + if(!openLinkLog()) + return FALSE; + + if(!initInput()) + return FALSE; + + if(!initDisplay()) { + if(videoOption >= VIDEO_320x240) { + regSetDwordValue("video", VIDEO_1X); + } + return FALSE; + } + + hAccel = LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCELERATOR)); + + winAccelMgr.Connect((MainWnd *)m_pMainWnd); + + winAccelMgr.SetRegKey(HKEY_CURRENT_USER, "Software\\Emulators\\VisualBoyAdvance"); + + extern void winAccelAddCommands(CAcceleratorManager&); + + winAccelAddCommands(winAccelMgr); + + winAccelMgr.CreateDefaultTable(); + + winAccelMgr.Load(); + + winAccelMgr.UpdateWndTable(); + + winAccelMgr.UpdateMenu(menu); + + if (m_lpCmdLine[0]) + { + int argc = parseCommandLine(m_lpCmdLine, NULL); + char **argv = (char **)malloc((argc+1)*sizeof(char *)); + parseCommandLine(m_lpCmdLine, argv); + if(argc > 0) { + szFile = argv[0]; + filename = szFile; + } + int index = filename.ReverseFind('.'); + + if(index != -1) + filename = filename.Left(index); + + if(((MainWnd*)m_pMainWnd)->FileRun()) + emulating = true; + else + emulating = false; + free(argv); + } + + return TRUE; +} + +void VBA::adjustDestRect() +{ + POINT point; + + point.x = 0; + point.y = 0; + + m_pMainWnd->ClientToScreen(&point); + dest.top = point.y; + dest.left = point.x; + + point.x = surfaceSizeX; + point.y = surfaceSizeY; + + m_pMainWnd->ClientToScreen(&point); + dest.bottom = point.y; + dest.right = point.x; + + // make sure that dest rect lies in the monitor + if(videoOption >= VIDEO_320x240) { + dest.top -= windowPositionY; + dest.left -= windowPositionX; + dest.bottom-= windowPositionY; + dest.right -= windowPositionX; + } + + int menuSkip = 0; + + if(videoOption >= VIDEO_320x240 && menuToggle) { + int m = GetSystemMetrics(SM_CYMENU); + menuSkip = m; + dest.bottom -=m; + } + + if(videoOption > VIDEO_4X) { + int top = (fsHeight - surfaceSizeY) / 2; + int left = (fsWidth - surfaceSizeX) / 2; + dest.top += top; + dest.bottom += top; + dest.left += left; + dest.right += left; + if(fullScreenStretch) { + dest.top = 0+menuSkip; + dest.left = 0; + dest.right = fsWidth; + dest.bottom = fsHeight; + } + } +} + + +void VBA::updateIFB() +{ + if(systemColorDepth == 16) { + switch(ifbType) { + case 0: + default: + ifbFunction = NULL; + break; + case 1: + ifbFunction = MotionBlurIB; + break; + case 2: + ifbFunction = SmartIB; + break; + } + } else if(systemColorDepth == 32) { + switch(ifbType) { + case 0: + default: + ifbFunction = NULL; + break; + case 1: + ifbFunction = MotionBlurIB32; + break; + case 2: + ifbFunction = SmartIB32; + break; + } + } else + ifbFunction = NULL; +} + +void VBA::updateFilter() +{ + // BEGIN hacky ugly code + + // HQ3X asm wants 16 bit input. When we switch + // away from 16 bits we need to restore the driver values + + // This hack is also necessary for Kega Fusion filter plugins + + if ( b16to32Video ) + { + b16to32Video = false; + systemColorDepth = realsystemColorDepth; + systemRedShift = realsystemRedShift; + systemGreenShift = realsystemGreenShift; + systemBlueShift = realsystemBlueShift; + utilUpdateSystemColorMaps(); + } + // END hacky ugly code + + filterWidth = sizeX; + filterHeight = sizeY; + filterMagnification = 1; + + + if ( videoOption == VIDEO_1X || videoOption == VIDEO_320x240 ) + { + filterFunction = NULL; + filterMagnification = 1; + } + else + { + if ( systemColorDepth == 16 ) + { + switch(filterType) + { + default: + case FILTER_NONE: + filterFunction = NULL; + filterMagnification = 1; + break; + case FILTER_PLUGIN: + if( rpiInit( pluginName ) ) { + filterFunction = rpiFilter; + filterMagnification = rpiScaleFactor(); + } else { + filterType = FILTER_NONE; + updateFilter(); + return; + } + break; + case FILTER_TVMODE: + filterFunction = ScanlinesTV; + filterMagnification = 2; + break; + case FILTER_2XSAI: + filterFunction = _2xSaI; + filterMagnification = 2; + break; + case FILTER_SUPER2XSAI: + filterFunction = Super2xSaI; + filterMagnification = 2; + break; + case FILTER_SUPEREAGLE: + filterFunction = SuperEagle; + filterMagnification = 2; + break; + case FILTER_PIXELATE: + filterFunction = Pixelate; + filterMagnification = 2; + break; + case FILTER_MAMESCALE2X: + filterFunction = AdMame2x; + filterMagnification = 2; + break; + case FILTER_SIMPLE2X: + filterFunction = Simple2x16; + filterMagnification = 2; + break; + case FILTER_BILINEAR: + filterFunction = Bilinear; + filterMagnification = 2; + break; + case FILTER_BILINEARPLUS: + filterFunction = BilinearPlus; + filterMagnification = 2; + break; + case FILTER_SCANLINES: + filterFunction = Scanlines; + filterMagnification = 2; + break; + case FILTER_HQ2X: + filterFunction = hq2x; + filterMagnification = 2; + break; + case FILTER_LQ2X: + filterFunction = lq2x; + filterMagnification = 2; + break; + case FILTER_SIMPLE3X: + filterFunction = Simple3x16; + filterMagnification = 3; + break; + case FILTER_SIMPLE4X: + filterFunction = Simple4x16; + filterMagnification = 4; + break; + case FILTER_HQ3X: + filterFunction = hq3x16; + filterMagnification = 3; + break; + case FILTER_HQ4X: + filterFunction = hq4x16; + filterMagnification = 4; + break; + } + } + + if ( systemColorDepth == 32 ) + { + switch(filterType) + { + default: + case FILTER_NONE: + filterFunction = NULL; + filterMagnification = 1; + break; + case FILTER_PLUGIN: + if( rpiInit( pluginName ) ) { + filterFunction = rpiFilter; + filterMagnification = rpiScaleFactor(); + b16to32Video=true; + } else { + filterType = FILTER_NONE; + updateFilter(); + return; + } + break; + case FILTER_TVMODE: + filterFunction = ScanlinesTV32; + filterMagnification = 2; + break; + case FILTER_2XSAI: + filterFunction = _2xSaI32; + filterMagnification = 2; + break; + case FILTER_SUPER2XSAI: + filterFunction = Super2xSaI32; + filterMagnification = 2; + break; + case FILTER_SUPEREAGLE: + filterFunction = SuperEagle32; + filterMagnification = 2; + break; + case FILTER_PIXELATE: + filterFunction = Pixelate32; + filterMagnification = 2; + break; + case FILTER_MAMESCALE2X: + filterFunction = AdMame2x32; + filterMagnification = 2; + break; + case FILTER_SIMPLE2X: + filterFunction = Simple2x32; + filterMagnification = 2; + break; + case FILTER_BILINEAR: + filterFunction = Bilinear32; + filterMagnification = 2; + break; + case FILTER_BILINEARPLUS: + filterFunction = BilinearPlus32; + filterMagnification = 2; + break; + case FILTER_SCANLINES: + filterFunction = Scanlines32; + filterMagnification = 2; + break; + case FILTER_HQ2X: + filterFunction = hq2x32; + filterMagnification = 2; + break; + case FILTER_LQ2X: + filterFunction = lq2x32; + filterMagnification = 2; + break; + case FILTER_SIMPLE3X: + filterFunction = Simple3x32; + filterMagnification = 3; + break; + case FILTER_SIMPLE4X: + filterFunction = Simple4x32; + filterMagnification = 4; + break; + case FILTER_HQ3X: + filterFunction = hq3x32; + filterMagnification = 3; +#ifndef NO_ASM + b16to32Video=true; +#endif + break; + case FILTER_HQ4X: + filterFunction = hq4x32; + filterMagnification = 4; +#ifndef NO_ASM + b16to32Video=true; +#endif + break; + } + } + } + + rect.right = sizeX * filterMagnification; + rect.bottom = sizeY * filterMagnification; + + + if( filterType != FILTER_NONE ) + memset(delta, 0xFF, sizeof(delta)); + + if( display ) + display->changeRenderSize(rect.right, rect.bottom); + + if (b16to32Video && systemColorDepth!=16) + { + realsystemColorDepth = systemColorDepth; + systemColorDepth = 16; + realsystemRedShift = systemRedShift; + systemRedShift = 11; + realsystemGreenShift = systemGreenShift; + systemGreenShift = 6; + realsystemBlueShift = systemBlueShift; + systemBlueShift = 0; + utilUpdateSystemColorMaps(); + } + +#ifdef LOG_PERFORMANCE + memset( systemSpeedTable, 0x00, sizeof(systemSpeedTable) ); + systemSpeedCounter = 0; +#endif +} + + +void VBA::updateThrottle( unsigned short throttle ) +{ + this->throttle = throttle; + + if( throttle == 0 ) { + autoFrameSkip = false; + return; + } else { + Sm60FPS::K_fCpuSpeed = (float)throttle; + Sm60FPS::K_fTargetFps = 60.0f * Sm60FPS::K_fCpuSpeed / 100; + Sm60FPS::K_fDT = 1000.0f / Sm60FPS::K_fTargetFps; + autoFrameSkip = true; + frameSkip = 0; + systemFrameSkip = 0; + return; + } +} + + +void VBA::updateMenuBar() +{ + if(menu != NULL) { + if(m_pMainWnd) + m_pMainWnd->SetMenu(NULL); + m_menu.Detach(); + DestroyMenu(menu); + } + + if(popup != NULL) { + // force popup recreation if language changed + DestroyMenu(popup); + popup = NULL; + } + + if( ( videoOption >= VIDEO_320x240 ) ) { + return; + } + + m_menu.Attach(winResLoadMenu(MAKEINTRESOURCE(IDR_MENU))); + menu = (HMENU)m_menu; + + if(m_pMainWnd) + m_pMainWnd->SetMenu(&m_menu); +} + +void winlog(const char *msg, ...) +{ + CString buffer; + va_list valist; + + va_start(valist, msg); + buffer.FormatV(msg, valist); + + if(theApp.winout == NULL) { + theApp.winout = fopen("vba-trace.log","w"); + } + + fputs(buffer, theApp.winout); + + va_end(valist); +} + +void log(const char *msg, ...) +{ + CString buffer; + va_list valist; + + va_start(valist, msg); + buffer.FormatV(msg, valist); + + toolsLog(buffer); + + va_end(valist); +} + +bool systemReadJoypads() +{ + if(theApp.input) + return theApp.input->readDevices(); + return false; +} + +u32 systemReadJoypad(int which) +{ + if(theApp.input) + return theApp.input->readDevice(which); + return 0; +} + +void systemDrawScreen() +{ + if(theApp.display == NULL) + return; + + theApp.renderedFrames++; + + if(theApp.updateCount) { + POSITION pos = theApp.updateList.GetHeadPosition(); + while(pos) { + IUpdateListener *up = theApp.updateList.GetNext(pos); + up->update(); + } + } + + if (Sm60FPS_CanSkipFrame()) + return; + + if( theApp.aviRecording ) { + if( theApp.painting ) { + theApp.skipAudioFrames++; + } else { + unsigned char *bmp; + unsigned short srcPitch = theApp.sizeX * ( systemColorDepth >> 3 ) + 4; + switch( systemColorDepth ) + { + case 16: + bmp = new unsigned char[ theApp.sizeX * theApp.sizeY * 2 ]; + cpyImg16bmp( bmp, pix + srcPitch, srcPitch, theApp.sizeX, theApp.sizeY ); + break; + case 32: + // use 24 bit colors to reduce video size + bmp = new unsigned char[ theApp.sizeX * theApp.sizeY * 3 ]; + cpyImg32bmp( bmp, pix + srcPitch, srcPitch, theApp.sizeX, theApp.sizeY ); + break; + } + if( false == theApp.aviRecorder->AddVideoFrame( bmp ) ) { + systemMessage( IDS_AVI_CANNOT_WRITE_VIDEO, "Cannot write video frame to AVI file." ); + delete theApp.aviRecorder; + theApp.aviRecorder = NULL; + theApp.aviRecording = false; + } + delete bmp; + } + } + + if( theApp.ifbFunction ) { + theApp.ifbFunction( pix + (theApp.filterWidth * (systemColorDepth>>3)) + 4, + (theApp.filterWidth * (systemColorDepth>>3)) + 4, + theApp.filterWidth, theApp.filterHeight ); + } + + if(!soundBufferLow) + { + theApp.display->render(); + Sm60FPS_Sleep(); + } + else + soundBufferLow = false; + +} + +void systemScreenCapture(int captureNumber) +{ + if(theApp.m_pMainWnd) + ((MainWnd *)theApp.m_pMainWnd)->screenCapture(captureNumber); +} + +u32 systemGetClock() +{ + return GetTickCount(); +} + +void systemMessage(int number, const char *defaultMsg, ...) +{ + CString buffer; + va_list valist; + CString msg = defaultMsg; + if(number) + msg = winResLoadString(number); + + va_start(valist, defaultMsg); + buffer.FormatV(msg, valist); + + AfxGetApp()->m_pMainWnd->MessageBox(buffer, winResLoadString(IDS_ERROR), MB_OK|MB_ICONERROR); + + va_end(valist); +} + +void systemSetTitle(const char *title) +{ + if(theApp.m_pMainWnd != NULL) { + AfxGetApp()->m_pMainWnd->SetWindowText(title); + } +} + +void systemShowSpeed(int speed) +{ + systemSpeed = speed; + theApp.showRenderedFrames = theApp.renderedFrames; + theApp.renderedFrames = 0; + if(theApp.videoOption <= VIDEO_4X && theApp.showSpeed) { + CString buffer; + if(theApp.showSpeed == 1) + buffer.Format("VisualBoyAdvance-%3d%%", systemSpeed); + else + buffer.Format("VisualBoyAdvance-%3d%%(%d, %d fps)", systemSpeed, + systemFrameSkip, + theApp.showRenderedFrames); + + systemSetTitle(buffer); + } +} + + +void systemFrame() +{ + if( theApp.movieRecording || theApp.moviePlaying ) { + theApp.movieFrame++; + } + +#ifdef LOG_PERFORMANCE + systemSpeedTable[systemSpeedCounter++ % PERFORMANCE_INTERVAL] = systemSpeed; +#endif +} + + +void system10Frames(int rate) +{ + if( theApp.autoFrameSkip ) + { + u32 time = systemGetClock(); + u32 diff = time - theApp.autoFrameSkipLastTime; + theApp.autoFrameSkipLastTime = time; + if( diff ) { + // countermeasure against div/0 when debugging + Sm60FPS::nCurSpeed = (1000000/rate)/diff; + } else { + Sm60FPS::nCurSpeed = 100; + } + } + + + if(theApp.rewindMemory) { + if(++theApp.rewindCounter >= (theApp.rewindTimer)) { + theApp.rewindSaveNeeded = true; + theApp.rewindCounter = 0; + } + } + if(systemSaveUpdateCounter) { + if(--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) { + ((MainWnd *)theApp.m_pMainWnd)->writeBatteryFile(); + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + } + } + + theApp.wasPaused = false; + +#ifdef LOG_PERFORMANCE + if( systemSpeedCounter >= PERFORMANCE_INTERVAL ) { + // log performance every PERFORMANCE_INTERVAL frames + float a = 0.0f; + for( unsigned short i = 0 ; i < PERFORMANCE_INTERVAL ; i++ ) { + a += (float)systemSpeedTable[i]; + } + a /= (float)PERFORMANCE_INTERVAL; + log( _T("Speed: %f\n"), a ); + systemSpeedCounter = 0; + } +#endif +} + +void systemScreenMessage(const char *msg) +{ + theApp.screenMessage = true; + theApp.screenMessageTime = GetTickCount(); + theApp.screenMessageBuffer = msg; + + if(theApp.screenMessageBuffer.GetLength() > 40) + theApp.screenMessageBuffer = theApp.screenMessageBuffer.Left(40); +} + +void systemUpdateMotionSensor() +{ + if(theApp.input) + theApp.input->checkMotionKeys(); +} + +int systemGetSensorX() +{ + return theApp.sensorX; +} + +int systemGetSensorY() +{ + return theApp.sensorY; +} + + +bool systemSoundInit() +{ + systemSoundShutdown(); + + switch( theApp.audioAPI ) + { + case DIRECTSOUND: + theApp.sound = newDirectSound(); + break; +#ifndef NO_OAL + case OPENAL_SOUND: + theApp.sound = newOpenAL(); + break; +#endif + } + + return theApp.sound->init(); +} + + +void systemSoundShutdown() +{ + if( theApp.aviRecorder ) { + delete theApp.aviRecorder; + theApp.aviRecorder = NULL; + } + theApp.aviRecording = false; + + + if( theApp.soundRecorder ) { + delete theApp.soundRecorder; + theApp.soundRecorder = NULL; + } + theApp.soundRecording = false; + + + if( theApp.sound ) { + delete theApp.sound; + theApp.sound = NULL; + } +} + + +void systemSoundPause() +{ + if(theApp.sound) + theApp.sound->pause(); +} + +void systemSoundReset() +{ + if(theApp.sound) + theApp.sound->reset(); +} + +void systemSoundResume() +{ + if(theApp.sound) + theApp.sound->resume(); +} + +void systemWriteDataToSoundBuffer() +{ + if( theApp.soundRecording ) { + if( theApp.soundRecorder ) { + theApp.soundRecorder->AddSound( (const u8 *)soundFinalWave, soundBufferLen ); + } else { + WAVEFORMATEX format; + format.cbSize = 0; + format.wFormatTag = WAVE_FORMAT_PCM; + format.nChannels = 2; + format.nSamplesPerSec = 44100 / soundQuality; + format.wBitsPerSample = 16; + format.nBlockAlign = format.nChannels * ( format.wBitsPerSample >> 3 ); + format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; + theApp.soundRecorder = new WavWriter; + if( theApp.soundRecorder->Open( theApp.soundRecordName ) ) { + theApp.soundRecorder->SetFormat( &format ); + } + } + } + + if( theApp.aviRecording && theApp.aviRecorder && !soundOffFlag ) { + if( theApp.skipAudioFrames ) { + theApp.skipAudioFrames--; + } else { + if( false == theApp.aviRecorder->AddAudioFrame( soundFinalWave ) ) { + systemMessage( IDS_AVI_CANNOT_WRITE_AUDIO, "Cannot write audio frame to AVI file." ); + delete theApp.aviRecorder; + theApp.aviRecorder = NULL; + theApp.aviRecording = false; + } + } + } + + if( theApp.sound ) { + theApp.sound->write(); + } +} + +bool systemCanChangeSoundQuality() +{ + return true; +} + +bool systemPauseOnFrame() +{ + if(theApp.winPauseNextFrame) { + theApp.paused = true; + theApp.winPauseNextFrame = false; + return true; + } + return false; +} + +void systemGbBorderOn() +{ + if(emulating && theApp.cartridgeType == IMAGE_GB && gbBorderOn) { + theApp.updateWindowSize(theApp.videoOption); + } +} + +BOOL VBA::OnIdle(LONG lCount) +{ + if(emulating && debugger) { + MSG msg; + remoteStubMain(); + if(debugger) + return TRUE; // continue loop + return !::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE); + } else if(emulating && active && !paused) { + for(int i = 0; i < 2; i++) { + emulator.emuMain(emulator.emuCount); + if(lanlink.connected&&linkid&&lc.numtransfers==0) lc.CheckConn(); + + if(rewindSaveNeeded && rewindMemory && emulator.emuWriteMemState) { + rewindCount++; + if(rewindCount > 8) + rewindCount = 8; + if(emulator.emuWriteMemState(&rewindMemory[rewindPos*REWIND_SIZE], + REWIND_SIZE)) { + rewindPos = ++rewindPos & 7; + if(rewindCount == 8) + rewindTopPos = ++rewindTopPos & 7; + } + } + + rewindSaveNeeded = false; + } + + if(mouseCounter) { + if(--mouseCounter == 0) { + SetCursor(NULL); + } + } + return TRUE; + } + return FALSE; + + // return CWinApp::OnIdle(lCount); +} + +void VBA::addRecentFile(CString file) +{ + // Do not change recent list if frozen + if(recentFreeze) + return; + int i = 0; + for(i = 0; i < 10; i++) { + if(recentFiles[i].GetLength() == 0) + break; + + if(recentFiles[i].Compare(file) == 0) { + if(i == 0) + return; + CString p = recentFiles[i]; + for(int j = i; j > 0; j--) { + recentFiles[j] = recentFiles[j-1]; + } + recentFiles[0] = p; + return; + } + } + int num = 0; + for(i = 0; i < 10; i++) { + if(recentFiles[i].GetLength() != 0) + num++; + } + if(num == 10) { + num--; + } + + for(i = num; i >= 1; i--) { + recentFiles[i] = recentFiles[i-1]; + } + recentFiles[0] = file; +} + +void VBA::loadSettings() +{ + CString buffer; + + lastFullscreen = (VIDEO_SIZE)regQueryDwordValue("lastFullscreen", VIDEO_1024x768); + + languageOption = regQueryDwordValue("language", 1); + if(languageOption < 0 || languageOption > 2) + languageOption = 1; + + buffer = regQueryStringValue("languageName", ""); + if(!buffer.IsEmpty()) { + languageName = buffer.Left(3); + } else + languageName = ""; + + winSetLanguageOption(languageOption, true); + + frameSkip = regQueryDwordValue("frameSkip", 0); + if(frameSkip < 0 || frameSkip > 9) + frameSkip = 0; + + gbFrameSkip = regQueryDwordValue("gbFrameSkip", 0); + if(gbFrameSkip < 0 || gbFrameSkip > 9) + gbFrameSkip = 0; + + vsync = regQueryDwordValue("vsync", false) ? true : false ; + synchronize = regQueryDwordValue("synchronize", 1) ? true : false; + fullScreenStretch = regQueryDwordValue("stretch", 0) ? true : false; + + videoOption = regQueryDwordValue("video", VIDEO_3X); + + strcpy(pluginName, regQueryStringValue("pluginName", "Scale2x.rpi")); + + if(videoOption < VIDEO_1X || videoOption > VIDEO_OTHER) + videoOption = VIDEO_3X; + + fsAdapter = regQueryDwordValue("fsAdapter", 0); + fsWidth = regQueryDwordValue("fsWidth", 800); + fsHeight = regQueryDwordValue("fsHeight", 600); + fsColorDepth = regQueryDwordValue("fsColorDepth", 32); + fsFrequency = regQueryDwordValue("fsFrequency", 60); + + if(videoOption == VIDEO_OTHER) { + if(fsWidth < 0 || fsWidth > 4095 || fsHeight < 0 || fsHeight > 4095) + videoOption = 0; + if(fsColorDepth != 16 && fsColorDepth != 24 && fsColorDepth != 32) + videoOption = 0; + } + + renderMethod = (DISPLAY_TYPE)regQueryDwordValue("renderMethod", DIRECT_3D); +#ifdef NO_OGL + if( renderMethod == OPENGL ) { + renderMethod = DIRECT_3D; + } +#endif +#ifdef NO_D3D + if( renderMethod == DIRECT_3D ) { + renderMethod = OPENGL; + } +#endif + + audioAPI = (AUDIO_API)regQueryDwordValue( "audioAPI", DIRECTSOUND ); + if( ( audioAPI != DIRECTSOUND ) +#ifndef NO_OAL + && ( audioAPI != OPENAL_SOUND ) +#endif + ) { + audioAPI = DIRECTSOUND; + } + + windowPositionX = regQueryDwordValue("windowX", 0); + if(windowPositionX < 0) + windowPositionX = 0; + windowPositionY = regQueryDwordValue("windowY", 0); + if(windowPositionY < 0) + windowPositionY = 0; + + useBiosFileGBA = ( regQueryDwordValue("useBiosGBA", 0) == 1 ) ? true : false; + + useBiosFileGB = ( regQueryDwordValue("useBiosGB", 0) == 1 ) ? true : false; + + skipBiosFile = regQueryDwordValue("skipBios", 0) ? true : false; + + buffer = regQueryStringValue("biosFileGBA", ""); + + if(!buffer.IsEmpty()) { + biosFileNameGBA = buffer; + } + + buffer = regQueryStringValue("biosFileGB", ""); + + if(!buffer.IsEmpty()) { + biosFileNameGB = buffer; + } + + int res = regQueryDwordValue("soundEnable", 0x30f); + + soundEnable(res); + soundDisable(~res); + + soundOffFlag = (regQueryDwordValue("soundOff", 0)) ? true : false; + + soundQuality = regQueryDwordValue("soundQuality", 1); + + soundEcho = regQueryDwordValue("soundEcho", 0) ? true : false; + + soundLowPass = regQueryDwordValue("soundLowPass", 0) ? true : false; + + soundReverse = regQueryDwordValue("soundReverse", 0) ? true : false; + + soundVolume = regQueryDwordValue("soundVolume", 0); + if(soundVolume < 0 || soundVolume > 5) + soundVolume = 0; + + soundInterpolation = regQueryDwordValue("soundInterpolation", 0); + if(soundInterpolation < 0 || soundInterpolation > 1) + soundInterpolation = 0; + + tripleBuffering = regQueryDwordValue("tripleBuffering", false) ? true : false; + +#ifndef NO_D3D + d3dFilter = regQueryDwordValue("d3dFilter", 1); + if(d3dFilter < 0 || d3dFilter > 1) + d3dFilter = 1; + + d3dMotionBlur = ( regQueryDwordValue("d3dMotionBlur", 0) == 1 ) ? true : false; +#endif + + glFilter = regQueryDwordValue("glFilter", 1); + if(glFilter < 0 || glFilter > 1) + glFilter = 1; + + + filterType = regQueryDwordValue("filter", 0); + if(filterType < 0 || filterType > 17) + filterType = 0; + + disableMMX = regQueryDwordValue("disableMMX", false) ? true: false; + + disableStatusMessage = regQueryDwordValue("disableStatus", 0) ? true : false; + + showSpeed = regQueryDwordValue("showSpeed", 0); + if(showSpeed < 0 || showSpeed > 2) + showSpeed = 0; + + showSpeedTransparent = regQueryDwordValue("showSpeedTransparent", TRUE) ? + TRUE : FALSE; + + winGbPrinterEnabled = regQueryDwordValue("gbPrinter", false) ? true : false; + + if(winGbPrinterEnabled) + gbSerialFunction = gbPrinterSend; + else + gbSerialFunction = NULL; + + pauseWhenInactive = regQueryDwordValue("pauseWhenInactive", 1) ? + true : false; + + captureFormat = regQueryDwordValue("captureFormat", 0); + + removeIntros = regQueryDwordValue("removeIntros", false) ? true : false; + + recentFreeze = regQueryDwordValue("recentFreeze", false) ? true : false; + + autoIPS = regQueryDwordValue("autoIPS", true) ? true : false; + + cpuDisableSfx = regQueryDwordValue("disableSfx", 0) ? true : false; + + winSaveType = regQueryDwordValue("saveType", 0); + if(winSaveType < 0 || winSaveType > 5) + winSaveType = 0; + + ifbType = regQueryDwordValue("ifbType", 0); + if(ifbType < 0 || ifbType > 2) + ifbType = 0; + + winFlashSize = regQueryDwordValue("flashSize", 0x10000); + if(winFlashSize != 0x10000 && winFlashSize != 0x20000) + winFlashSize = 0x10000; + flashSize = winFlashSize; + + agbPrintEnable(regQueryDwordValue("agbPrint", 0) ? true : false); + + winRtcEnable = regQueryDwordValue("rtcEnabled", 0) ? true : false; + rtcEnable(winRtcEnable); + + switch(videoOption) { + case VIDEO_320x240: + fsWidth = 320; + fsHeight = 240; + fsColorDepth = 16; + fsFrequency = 60; + break; + case VIDEO_640x480: + fsWidth = 640; + fsHeight = 480; + fsColorDepth = 16; + fsFrequency = 60; + break; + case VIDEO_800x600: + fsWidth = 800; + fsHeight = 600; + fsColorDepth = 16; + fsFrequency = 60; + break; + case VIDEO_1024x768: + fsWidth = 1024; + fsHeight = 768; + fsColorDepth = 16; + fsFrequency = 60; + break; + case VIDEO_1280x1024: + fsWidth = 1280; + fsHeight = 1024; + fsColorDepth = 16; + fsFrequency = 60; + break; + } + + winGbBorderOn = regQueryDwordValue("borderOn", 0); + gbBorderAutomatic = regQueryDwordValue("borderAutomatic", 0); + gbEmulatorType = regQueryDwordValue("emulatorType", 1); + if(gbEmulatorType < 0 || gbEmulatorType > 5) + gbEmulatorType = 1; + gbColorOption = regQueryDwordValue("colorOption", 0); + + threadPriority = regQueryDwordValue("priority", 2); + + if(threadPriority < 0 || threadPriority >3) + threadPriority = 2; + updatePriority(); + + autoSaveLoadCheatList = regQueryDwordValue("autoSaveCheatList", 0) ? + true : false; + + gbPaletteOption = regQueryDwordValue("gbPaletteOption", 0); + if(gbPaletteOption < 0) + gbPaletteOption = 0; + if(gbPaletteOption > 2) + gbPaletteOption = 2; + + regQueryBinaryValue("gbPalette", (char *)systemGbPalette, + 24*sizeof(u16)); + + rewindTimer = regQueryDwordValue("rewindTimer", 0); + + if(rewindTimer < 0 || rewindTimer > 600) + rewindTimer = 0; + + rewindTimer *= 6; // convert to 10 frames multiple + + if(rewindTimer != 0) + rewindMemory = (char *)malloc(8*REWIND_SIZE); + + for(int i = 0; i < 10; i++) { + buffer.Format("recent%d", i); + char *s = regQueryStringValue(buffer, NULL); + if(s == NULL) + break; + recentFiles[i] = s; + } + + joypadDefault = regQueryDwordValue("joypadDefault", 0); + if(joypadDefault < 0 || joypadDefault > 3) + joypadDefault = 0; + + autoLoadMostRecent = regQueryDwordValue("autoLoadMostRecent", false) ? true : + false; + + cheatsEnabled = regQueryDwordValue("cheatsEnabled", false) ? true : false; + + fsMaxScale = regQueryDwordValue("fsMaxScale", 0); + + updateThrottle( (unsigned short)regQueryDwordValue( "throttle", 0 ) ); + + linktimeout = regQueryDwordValue("LinkTimeout", 1000); + + linklog = regQueryDwordValue("Linklog", false) ? true : false; + if(linklog) + openLinkLog(); + + adapter = regQueryDwordValue("RFU", false) ? true : false; + linkenable = regQueryDwordValue("linkEnabled", false) ? true : false; + + lanlink.active = regQueryDwordValue("LAN", 0) ? true : false; + + Sm60FPS::bSaveMoreCPU = regQueryDwordValue("saveMoreCPU", 0); + +#ifndef NO_OAL + buffer = regQueryStringValue( "oalDevice", "Generic Software" ); + if( oalDevice ) { + free( oalDevice ); + } + oalDevice = (TCHAR*)malloc( ( buffer.GetLength() + 1 ) * sizeof( TCHAR ) ); + _tcscpy( oalDevice, buffer.GetBuffer() ); + + oalBufferCount = regQueryDwordValue( "oalBufferCount", 5 ); +#endif +} + +void VBA::updateFrameSkip() +{ + switch(cartridgeType) { + case 0: + systemFrameSkip = frameSkip; + break; + case 1: + systemFrameSkip = gbFrameSkip; + break; + } +} + +void VBA::updateVideoSize(UINT id) +{ + int value = 0; + + switch(id) { + case ID_OPTIONS_VIDEO_X1: + value = VIDEO_1X; + break; + case ID_OPTIONS_VIDEO_X2: + value = VIDEO_2X; + break; + case ID_OPTIONS_VIDEO_X3: + value = VIDEO_3X; + break; + case ID_OPTIONS_VIDEO_X4: + value = VIDEO_4X; + break; + case ID_OPTIONS_VIDEO_FULLSCREEN320X240: + value = VIDEO_320x240; + fsWidth = 320; + fsHeight = 240; + fsColorDepth = 16; + break; + case ID_OPTIONS_VIDEO_FULLSCREEN640X480: + value = VIDEO_640x480; + fsWidth = 640; + fsHeight = 480; + fsColorDepth = 16; + break; + case ID_OPTIONS_VIDEO_FULLSCREEN800X600: + value = VIDEO_800x600; + fsWidth = 800; + fsHeight = 600; + fsColorDepth = 16; + break; + case ID_OPTIONS_VIDEO_FULLSCREEN1024X768: + value = VIDEO_1024x768; + fsWidth = 1024; + fsHeight = 768; + fsColorDepth = 32; + break; + case ID_OPTIONS_VIDEO_FULLSCREEN1280X1024: + value = VIDEO_1280x1024; + fsWidth = 1280; + fsHeight = 1024; + fsColorDepth = 32; + break; + case ID_OPTIONS_VIDEO_FULLSCREEN: + value = VIDEO_OTHER; + break; + } + + updateWindowSize(value); +} + + +void VBA::updateWindowSize(int value) +{ + regSetDwordValue("video", value); + + if(value == VIDEO_OTHER) { + regSetDwordValue("fsWidth", fsWidth); + regSetDwordValue("fsHeight", fsHeight); + regSetDwordValue("fsColorDepth", fsColorDepth); + } + + if(((value >= VIDEO_320x240) && + (videoOption != value)) || + (videoOption >= VIDEO_320x240 && + value <= VIDEO_4X) || + fsForceChange) { + fsForceChange = false; + changingVideoSize = true; + if( videoOption <= VIDEO_4X ) { + lastWindowed = (VIDEO_SIZE)videoOption; // save for when leaving full screen + } else { + lastFullscreen = (VIDEO_SIZE)videoOption; // save for when using quick switch to fullscreen + } + shutdownDisplay(); + if(input) { + delete input; + input = NULL; + } + m_pMainWnd->DragAcceptFiles(FALSE); + CWnd *pWnd = m_pMainWnd; + m_pMainWnd = NULL; + pWnd->DestroyWindow(); + delete pWnd; + videoOption = value; + if(!initDisplay()) { + if(videoOption == VIDEO_320x240 || + videoOption == VIDEO_640x480 || + videoOption == VIDEO_800x600 || + videoOption == VIDEO_1024x768 || + videoOption == VIDEO_1280x1024 || + videoOption == VIDEO_OTHER) { + regSetDwordValue("video", VIDEO_1X); + } + changingVideoSize = false; + AfxPostQuitMessage(0); + return; + } + if(!initInput()) { + changingVideoSize = false; + AfxPostQuitMessage(0); + return; + } + input->checkKeys(); + + + changingVideoSize = FALSE; + updateWindowSize(videoOption); + return; + } + + sizeX = 240; + sizeY = 160; + + videoOption = value; + + if(cartridgeType == IMAGE_GB) { + if(gbBorderOn) { + sizeX = 256; + sizeY = 224; + gbBorderLineSkip = 256; + gbBorderColumnSkip = 48; + gbBorderRowSkip = 40; + } else { + sizeX = 160; + sizeY = 144; + gbBorderLineSkip = 160; + gbBorderColumnSkip = 0; + gbBorderRowSkip = 0; + } + } + + surfaceSizeX = sizeX; + surfaceSizeY = sizeY; + + switch(videoOption) { + case VIDEO_1X: + surfaceSizeX = sizeX; + surfaceSizeY = sizeY; + break; + case VIDEO_2X: + surfaceSizeX = sizeX * 2; + surfaceSizeY = sizeY * 2; + break; + case VIDEO_3X: + surfaceSizeX = sizeX * 3; + surfaceSizeY = sizeY * 3; + break; + case VIDEO_4X: + surfaceSizeX = sizeX * 4; + surfaceSizeY = sizeY * 4; + break; + case VIDEO_320x240: + case VIDEO_640x480: + case VIDEO_800x600: + case VIDEO_1024x768: + case VIDEO_1280x1024: + case VIDEO_OTHER: + { + int scaleX = 1; + int scaleY = 1; + scaleX = (fsWidth / sizeX); + scaleY = (fsHeight / sizeY); + int min = scaleX < scaleY ? scaleX : scaleY; + if(fsMaxScale) + min = min > fsMaxScale ? fsMaxScale : min; + surfaceSizeX = min * sizeX; + surfaceSizeY = min * sizeY; + if((fullScreenStretch && (display != NULL && + (display->getType() != DIRECT_3D))) + || (display != NULL && display->getType() >= DIRECT_3D)) { + surfaceSizeX = fsWidth; + surfaceSizeY = fsHeight; + } + } + break; + } + + rect.right = sizeX; + rect.bottom = sizeY; + + int winSizeX = sizeX; + int winSizeY = sizeY; + + if(videoOption <= VIDEO_4X) { + dest.left = 0; + dest.top = 0; + dest.right = surfaceSizeX; + dest.bottom = surfaceSizeY; + + DWORD style = WS_POPUP | WS_VISIBLE; + + style |= WS_OVERLAPPEDWINDOW; + + menuToggle = TRUE; + AdjustWindowRectEx(&dest, style, TRUE, 0); //WS_EX_TOPMOST); + + winSizeX = dest.right-dest.left; + winSizeY = dest.bottom-dest.top; + + m_pMainWnd->SetWindowPos(0, //HWND_TOPMOST, + windowPositionX, + windowPositionY, + winSizeX, + winSizeY, + SWP_NOMOVE | SWP_SHOWWINDOW); + + // content of old seperate 'winCheckMenuBarInfo' function: + MENUBARINFO info; + info.cbSize = sizeof(MENUBARINFO); + theApp.m_pMainWnd->GetMenuBarInfo(OBJID_MENU, 0, &info); + int menuHeight = GetSystemMetrics(SM_CYMENU); // includes white line + if((info.rcBar.bottom - info.rcBar.top) > menuHeight) + { + winSizeY += (info.rcBar.bottom - info.rcBar.top) - menuHeight + 1; + m_pMainWnd->SetWindowPos( + 0, //HWND_TOPMOST, + theApp.windowPositionX, + theApp.windowPositionY, + winSizeX, + winSizeY, + SWP_NOMOVE | SWP_SHOWWINDOW); + } + } + + adjustDestRect(); + + updateIFB(); + updateFilter(); + + if(display) + display->resize(theApp.dest.right-theApp.dest.left, theApp.dest.bottom-theApp.dest.top); + + m_pMainWnd->RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN); +} + + +bool VBA::initDisplay() +{ + return updateRenderMethod(false); +} + + +bool VBA::preInitialize() +{ + switch( cartridgeType ) + { + case IMAGE_GBA: + sizeX = 240; + sizeY = 160; + break; + case IMAGE_GB: + if( gbBorderOn ) { + sizeX = 256; + sizeY = 224; + } else { + sizeX = 160; + sizeY = 144; + } + break; + } + + switch( videoOption ) + { + case VIDEO_1X: + surfaceSizeX = sizeX; + surfaceSizeY = sizeY; + break; + case VIDEO_2X: + surfaceSizeX = sizeX * 2; + surfaceSizeY = sizeY * 2; + break; + case VIDEO_3X: + surfaceSizeX = sizeX * 3; + surfaceSizeY = sizeY * 3; + break; + case VIDEO_4X: + surfaceSizeX = sizeX * 4; + surfaceSizeY = sizeY * 4; + break; + case VIDEO_320x240: + case VIDEO_640x480: + case VIDEO_800x600: + case VIDEO_1024x768: + case VIDEO_1280x1024: + case VIDEO_OTHER: + float scaleX = (float)fsWidth / sizeX; + float scaleY = (float)fsHeight / sizeY; + float min = ( scaleX < scaleY ) ? scaleX : scaleY; + if( fullScreenStretch ) { + surfaceSizeX = fsWidth; + surfaceSizeY = fsHeight; + } else { + surfaceSizeX = (int)( sizeX * min ); + surfaceSizeY = (int)( sizeY * min ); + } + break; + } + + rect.left = 0; + rect.top = 0; + rect.right = sizeX; + rect.bottom = sizeY; + + dest.left = 0; + dest.top = 0; + dest.right = surfaceSizeX; + dest.bottom = surfaceSizeY; + + + DWORD style = WS_POPUP | WS_VISIBLE; + DWORD styleEx = 0; + + if( videoOption <= VIDEO_4X ) { + style |= WS_OVERLAPPEDWINDOW; + } else { + styleEx = 0; + } + + if( videoOption <= VIDEO_4X ) { + AdjustWindowRectEx( &dest, style, TRUE, styleEx ); + } else { + AdjustWindowRectEx( &dest, style, FALSE, styleEx ); + } + + int winSizeX = dest.right-dest.left; + int winSizeY = dest.bottom-dest.top; + + if( videoOption > VIDEO_4X ) { + winSizeX = fsWidth; + winSizeY = fsHeight; + } + + int x = 0, y = 0; + + if( videoOption <= VIDEO_4X ) { + x = windowPositionX; + y = windowPositionY; + } + + + // Create a window + MainWnd *pWnd = new MainWnd; + m_pMainWnd = pWnd; + + pWnd->CreateEx( + styleEx, + wndClass, + _T("VisualBoyAdvance"), + style, + x, y, + winSizeX, winSizeY, + NULL, + 0 + ); + + if( !((HWND)*pWnd) ) { + winlog( "Error creating Window %08x\n", GetLastError() ); + return false; + } + pWnd->DragAcceptFiles( TRUE ); + updateMenuBar(); + adjustDestRect(); + + return true; +} + + +bool VBA::updateRenderMethod(bool force) +{ + bool ret = true; + + Sm60FPS_Init(); + + if( !updateRenderMethod0( force ) ) { + // fall back to safe configuration + renderMethod = DIRECT_3D; + fsAdapter = 0; + videoOption = VIDEO_1X; + ret = updateRenderMethod( true ); + } + + return ret; +} + + +bool VBA::updateRenderMethod0(bool force) +{ + bool initInput = false; + b16to32Video = false; + + if(display) { + if(display->getType() != renderMethod || force) { + initInput = true; + changingVideoSize = true; + shutdownDisplay(); + if(input) { + delete input; + input = NULL; + } + CWnd *pWnd = m_pMainWnd; + + m_pMainWnd = NULL; + pWnd->DragAcceptFiles(FALSE); + pWnd->DestroyWindow(); + delete pWnd; + + display = NULL; + regSetDwordValue("renderMethod", renderMethod); + } + } + if(display == NULL) { + switch(renderMethod) { +#ifndef NO_OGL + case OPENGL: + display = newOpenGLDisplay(); + break; +#endif +#ifndef NO_D3D + case DIRECT_3D: + display = newDirect3DDisplay(); + break; +#endif + } + + if( preInitialize() ) { + if( display->initialize() ) { + if( initInput ) { + if( !this->initInput() ) { + changingVideoSize = false; + AfxPostQuitMessage(0); + return false; + } + input->checkKeys(); + updateMenuBar(); + changingVideoSize = false; + updateWindowSize(videoOption); + + m_pMainWnd->ShowWindow(SW_SHOW); + m_pMainWnd->UpdateWindow(); + m_pMainWnd->SetFocus(); + + return true; + } else { + changingVideoSize = false; + return true; + } + } + } + changingVideoSize = false; + } + return true; +} + + +void VBA::shutdownDisplay() +{ + if(display != NULL) { + display->cleanup(); + delete display; + display = NULL; + } +} + +void VBA::directXMessage(const char *msg) +{ + systemMessage(IDS_DIRECTX_7_REQUIRED, + "DirectX 7.0 or greater is required to run.\nDownload at http://www.microsoft.com/directx.\n\nError found at: %s", + msg); +} + +void VBA::updatePriority() +{ + switch(threadPriority) { + case 0: + SetThreadPriority(THREAD_PRIORITY_HIGHEST); + break; + case 1: + SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL); + break; + case 3: + SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); + break; + default: + SetThreadPriority(THREAD_PRIORITY_NORMAL); + } +} + +#ifdef MMX +bool VBA::detectMMX() +{ + bool support = false; + char brand[13]; + + // check for Intel chip + __try { + __asm { + mov eax, 0; + cpuid; + mov [dword ptr brand+0], ebx; + mov [dword ptr brand+4], edx; + mov [dword ptr brand+8], ecx; + } + } + __except(EXCEPTION_EXECUTE_HANDLER) { + if(_exception_code() == STATUS_ILLEGAL_INSTRUCTION) { + return false; + } + return false; + } + // Check for Intel or AMD CPUs + if(strncmp(brand, "GenuineIntel", 12)) { + if(strncmp(brand, "AuthenticAMD", 12)) { + return false; + } + } + + __asm { + mov eax, 1; + cpuid; + test edx, 00800000h; + jz NotFound; + mov [support], 1; + NotFound: + } + return support; +} +#endif + +void VBA::winSetLanguageOption(int option, bool force) +{ + if(((option == languageOption) && option != 2) && !force) + return; + switch(option) { + case 0: + { + char lbuffer[10]; + + if(GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SABBREVLANGNAME, + lbuffer, 10)) { + HINSTANCE l = winLoadLanguage(lbuffer); + if(l == NULL) { + LCID locIdBase = MAKELCID( MAKELANGID( PRIMARYLANGID( GetSystemDefaultLangID() ), SUBLANG_NEUTRAL ), SORT_DEFAULT ); + if(GetLocaleInfo(locIdBase, LOCALE_SABBREVLANGNAME, + lbuffer, 10)) { + l = winLoadLanguage(lbuffer); + if(l == NULL) { + systemMessage(IDS_FAILED_TO_LOAD_LIBRARY, + "Failed to load library %s", + lbuffer); + return; + } + } + } + AfxSetResourceHandle(l); + if(languageModule != NULL) +#ifdef _AFXDLL + AfxFreeLibrary( languageModule ); +#else + FreeLibrary( languageModule ); +#endif + languageModule = l; + } else { + systemMessage(IDS_FAILED_TO_GET_LOCINFO, + "Failed to get locale information"); + return; + } + } + break; + case 1: + if(languageModule != NULL) +#ifdef _AFXDLL + AfxFreeLibrary( languageModule ); +#else + FreeLibrary( languageModule ); +#endif + languageModule = NULL; + AfxSetResourceHandle(AfxGetInstanceHandle()); + break; + case 2: + { + if(!force) { + LangSelect dlg; + if(dlg.DoModal()) { + HINSTANCE l = winLoadLanguage(languageName); + if(l == NULL) { + systemMessage(IDS_FAILED_TO_LOAD_LIBRARY, + "Failed to load library %s", + languageName); + return; + } + AfxSetResourceHandle(l); + if(languageModule != NULL) + { +#ifdef _AFXDLL + AfxFreeLibrary( languageModule ); +#else + FreeLibrary( languageModule ); +#endif + } + languageModule = l; + } + } else { + if(languageName.IsEmpty()) + return; + HINSTANCE l = winLoadLanguage(languageName); + if(l == NULL) { + systemMessage(IDS_FAILED_TO_LOAD_LIBRARY, + "Failed to load library %s", + languageName); + return; + } + AfxSetResourceHandle(l); + if(languageModule != NULL) + FreeLibrary(languageModule); + languageModule = l; + } + } + break; + } + languageOption = option; + updateMenuBar(); +} + +HINSTANCE VBA::winLoadLanguage(const char *name) +{ + CString buffer; + + buffer.Format( _T("vba_%s.dll"), name); + +#ifdef _AFXDLL + HINSTANCE l = AfxLoadLibrary( buffer ); +#else + HMODULE l = LoadLibrary( buffer ); +#endif + + if(l == NULL) { + if(strlen(name) == 3) { + char buffer2[3]; + buffer2[0] = name[0]; + buffer2[1] = name[1]; + buffer2[2] = 0; + buffer.Format("vba_%s.dll", buffer2); + +#ifdef _AFXDLL + return AfxLoadLibrary( buffer ); +#else + return LoadLibrary( buffer ); +#endif + } + } + return l; +} + + +bool VBA::initInput() +{ + if(input) + delete input; + input = newDirectInput(); + if(input->initialize()) { + input->loadSettings(); + input->checkKeys(); + return true; + } + delete input; + return false; +} + +void VBA::winAddUpdateListener(IUpdateListener *l) +{ + updateList.AddTail(l); + updateCount++; +} + +void VBA::winRemoveUpdateListener(IUpdateListener *l) +{ + POSITION pos = updateList.Find(l); + if(pos) { + updateList.RemoveAt(pos); + updateCount--; + if(updateCount < 0) + updateCount = 0; + } +} + +CString VBA::winLoadFilter(UINT id) +{ + CString res = winResLoadString(id); + res.Replace('_','|'); + + return res; +} + +void VBA::movieReadNext() +{ + if(movieFile) { + bool movieEnd = false; + + if(fread(&moviePlayFrame, 1, sizeof(int), movieFile) == sizeof(int)) { + if(fread(&movieNextJoypad, 1, sizeof(u32), movieFile) == sizeof(int)) { + // make sure we don't have spurious entries on the movie that can + // cause us to play it forever + if(moviePlayFrame <= movieFrame) + movieEnd = true; + } else + movieEnd = true; + } else + movieEnd = true; + if(movieEnd) { + CString string = winResLoadString(IDS_END_OF_MOVIE); + systemScreenMessage(string); + moviePlaying = false; + fclose(movieFile); + movieFile = NULL; + return; + } + } else + moviePlaying = false; +} + +void VBA::saveSettings() +{ + regSetDwordValue("language", languageOption); + + regSetStringValue("languageName", languageName); + + regSetDwordValue("frameSkip", frameSkip); + + regSetDwordValue("gbFrameSkip", gbFrameSkip); + + regSetDwordValue("vsync", vsync); + regSetDwordValue("synchronize", synchronize); + regSetDwordValue("stretch", fullScreenStretch); + + regSetDwordValue("video", videoOption); + + regSetDwordValue("fsAdapter", fsAdapter); + regSetDwordValue("fsWidth", fsWidth); + regSetDwordValue("fsHeight", fsHeight); + regSetDwordValue("fsColorDepth", fsColorDepth); + regSetDwordValue("fsFrequency", fsFrequency); + + regSetDwordValue("renderMethod", renderMethod); + regSetDwordValue( "audioAPI", audioAPI ); + + regSetDwordValue("windowX", windowPositionX); + regSetDwordValue("windowY", windowPositionY); + + regSetDwordValue("useBiosGBA", useBiosFileGBA); + + regSetDwordValue("useBiosGB", useBiosFileGB); + + regSetDwordValue("skipBios", skipBiosFile); + + if(!biosFileNameGBA.IsEmpty()) + regSetStringValue("biosFileGBA", biosFileNameGBA); + + if(!biosFileNameGB.IsEmpty()) + regSetStringValue("biosFileGB", biosFileNameGB); + + regSetDwordValue("soundEnable", soundGetEnable() & 0x30f); + + regSetDwordValue("soundOff", soundOffFlag); + + regSetDwordValue("soundQuality", soundQuality); + + regSetDwordValue("soundEcho", soundEcho); + + regSetDwordValue("soundLowPass", soundLowPass); + + regSetDwordValue("soundReverse", soundReverse); + + regSetDwordValue("soundVolume", soundVolume); + + regSetDwordValue("soundInterpolation", soundInterpolation); + regSetDwordValue("tripleBuffering", tripleBuffering); + +#ifndef NO_D3D + regSetDwordValue("d3dFilter", d3dFilter); + regSetDwordValue("d3dMotionBlur", d3dMotionBlur ? 1 : 0); +#endif + + regSetDwordValue("glFilter", glFilter); + + regSetDwordValue("filter", filterType); + + regSetDwordValue("LCDFilter", filterLCD); + + regSetDwordValue("disableMMX", disableMMX); + + regSetDwordValue("disableStatus", disableStatusMessage); + + regSetDwordValue("showSpeed", showSpeed); + + regSetDwordValue("showSpeedTransparent", showSpeedTransparent); + + regSetDwordValue("gbPrinter", winGbPrinterEnabled); + + regSetDwordValue("pauseWhenInactive", pauseWhenInactive); + + regSetDwordValue("captureFormat", captureFormat); + + regSetDwordValue("removeIntros", removeIntros); + + regSetDwordValue("recentFreeze", recentFreeze); + + regSetDwordValue("autoIPS", autoIPS); + + regSetDwordValue("disableSfx", cpuDisableSfx); + + regSetDwordValue("saveType", winSaveType); + + regSetDwordValue("ifbType", ifbType); + + regSetDwordValue("flashSize", winFlashSize); + + regSetDwordValue("agbPrint", agbPrintIsEnabled()); + + regSetDwordValue("rtcEnabled", winRtcEnable); + + regSetDwordValue("borderOn", winGbBorderOn); + regSetDwordValue("borderAutomatic", gbBorderAutomatic); + regSetDwordValue("emulatorType", gbEmulatorType); + regSetDwordValue("colorOption", gbColorOption); + + regSetDwordValue("priority", threadPriority); + + regSetDwordValue("autoSaveCheatList", autoSaveLoadCheatList); + + regSetDwordValue("gbPaletteOption", gbPaletteOption); + + regSetBinaryValue("gbPalette", (char *)systemGbPalette, + 24*sizeof(u16)); + + regSetDwordValue("rewindTimer", rewindTimer/6); + + CString buffer; + for(int i = 0; i < 10; i++) { + buffer.Format("recent%d", i); + regSetStringValue(buffer, recentFiles[i]); + } + + regSetDwordValue("joypadDefault", joypadDefault); + regSetDwordValue("autoLoadMostRecent", autoLoadMostRecent); + regSetDwordValue("cheatsEnabled", cheatsEnabled); + regSetDwordValue("fsMaxScale", fsMaxScale); + regSetDwordValue("throttle", throttle); + regSetStringValue("pluginName", pluginName); + regSetDwordValue("saveMoreCPU", Sm60FPS::bSaveMoreCPU); + regSetDwordValue("LinkTimeout", linktimeout); + regSetDwordValue("Linklog", linklog); + regSetDwordValue("RFU", adapter); + regSetDwordValue("linkEnabled", linkenable); + regSetDwordValue("lastFullscreen", lastFullscreen); + +#ifndef NO_OAL + regSetStringValue( "oalDevice", oalDevice ); + regSetDwordValue( "oalBufferCount", oalBufferCount ); +#endif +} + +void winSignal(int, int) +{ +} + +#define CPUReadByteQuick(addr) \ + map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] + +void winOutput(const char *s, u32 addr) +{ + if(s) { + toolsLog(s); + } else { + CString str; + char c; + + c = CPUReadByteQuick(addr); + addr++; + while(c) { + str += c; + c = CPUReadByteQuick(addr); + addr++; + } + toolsLog(str); + } +} + + +void Sm60FPS_Init() +{ + Sm60FPS::dwTimeElapse = 0; + Sm60FPS::fWantFPS = 60.f; + Sm60FPS::fCurFPS = 0.f; + Sm60FPS::nFrameCnt = 0; + Sm60FPS::bLastSkip = false; + Sm60FPS::nCurSpeed = 100; +} + + +bool Sm60FPS_CanSkipFrame() +{ + if( theApp.autoFrameSkip ) { + if( Sm60FPS::nFrameCnt == 0 ) { + Sm60FPS::nFrameCnt = 0; + Sm60FPS::dwTimeElapse = 0; + Sm60FPS::dwTime0 = timeGetTime(); + } else { + if( Sm60FPS::nFrameCnt >= 10 ) { + Sm60FPS::nFrameCnt = 0; + Sm60FPS::dwTimeElapse = 0; + + if( Sm60FPS::nCurSpeed > Sm60FPS::K_fCpuSpeed ) { + Sm60FPS::fWantFPS += 1; + if( Sm60FPS::fWantFPS > Sm60FPS::K_fTargetFps ){ + Sm60FPS::fWantFPS = Sm60FPS::K_fTargetFps; + } + } else { + if( Sm60FPS::nCurSpeed < (Sm60FPS::K_fCpuSpeed - 5) ) { + Sm60FPS::fWantFPS -= 1; + if( Sm60FPS::fWantFPS < 30.f ) { + Sm60FPS::fWantFPS = 30.f; + } + } + } + } else { // between frame 1-10 + Sm60FPS::dwTime1 = timeGetTime(); + Sm60FPS::dwTimeElapse += (Sm60FPS::dwTime1 - Sm60FPS::dwTime0); + Sm60FPS::dwTime0 = Sm60FPS::dwTime1; + if( !Sm60FPS::bLastSkip && + ( (Sm60FPS::fWantFPS < Sm60FPS::K_fTargetFps) || Sm60FPS::bSaveMoreCPU) ) { + Sm60FPS::fCurFPS = (float)Sm60FPS::nFrameCnt * 1000 / Sm60FPS::dwTimeElapse; + if( (Sm60FPS::fCurFPS < Sm60FPS::K_fTargetFps) || Sm60FPS::bSaveMoreCPU ) { + Sm60FPS::bLastSkip = true; + Sm60FPS::nFrameCnt++; + return true; + } + } + } + } + Sm60FPS::bLastSkip = false; + Sm60FPS::nFrameCnt++; + } + return false; +} + + +void Sm60FPS_Sleep() +{ + if( theApp.autoFrameSkip ) { + u32 dwTimePass = Sm60FPS::dwTimeElapse + (timeGetTime() - Sm60FPS::dwTime0); + u32 dwTimeShould = (u32)(Sm60FPS::nFrameCnt * Sm60FPS::K_fDT); + if( dwTimeShould > dwTimePass ) { + Sleep(dwTimeShould - dwTimePass); + } + } +} diff --git a/src/win32/VBA.h b/src/win32/VBA.h index d6da00d9..9fb7f6fa 100644 --- a/src/win32/VBA.h +++ b/src/win32/VBA.h @@ -1,278 +1,278 @@ -// -*- C++ -*- -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2005 Forgotten and the VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -// VBA.h : main header file for the VBA application -// - -#pragma once - -#ifndef __AFXWIN_H__ -#error include 'stdafx.h' before including this file for PCH -#endif - -#include "stdafx.h" -#include "resource.h" -//#include - -#include "AcceleratorManager.h" -#include "Display.h" -#include "Input.h" -#include "IUpdate.h" -#include "Sound.h" -#include "../System.h" -#include "../Util.h" - -///////////////////////////////////////////////////////////////////////////// -// VBA: -// See VBA.cpp for the implementation of this class -// - -enum VIDEO_SIZE{ - VIDEO_1X, VIDEO_2X, VIDEO_3X, VIDEO_4X, - VIDEO_320x240, VIDEO_640x480, VIDEO_800x600, VIDEO_1024x768, VIDEO_1280x1024, - VIDEO_OTHER -}; - -enum pixelFilterType -{ - FILTER_NONE, - - FILTER_SIMPLE2X, FILTER_PIXELATE, FILTER_TVMODE, FILTER_SCANLINES, - FILTER_PLUGIN, - FILTER_BILINEAR, FILTER_BILINEARPLUS, FILTER_MAMESCALE2X, - FILTER_2XSAI, FILTER_SUPER2XSAI, FILTER_SUPEREAGLE, FILTER_LQ2X, FILTER_HQ2X, - - FILTER_SIMPLE3X, FILTER_HQ3X, - - FILTER_SIMPLE4X, FILTER_HQ4X -}; - -#define REWIND_SIZE 400000 - -class AVIWrite; -class WavWriter; - -class VBA : public CWinApp -{ - public: - CMenu m_menu; - HMENU menu; - HMENU popup; - bool mode320Available; - bool mode640Available; - bool mode800Available; - bool mode1024Available; - bool mode1280Available; - int windowPositionX; - int windowPositionY; - void (*filterFunction)(u8*,u32,u8*,u8*,u32,int,int); - void (*ifbFunction)(u8*,u32,int,int); - int ifbType; - int filterType; - char pluginName[MAX_PATH]; - int filterWidth; - int filterHeight; - int filterMagnification; - int filterLCD; - int fsWidth; - int fsHeight; - int fsColorDepth; - int fsFrequency; - int fsAdapter; - bool fsForceChange; - int sizeX; - int sizeY; - int surfaceSizeX; - int surfaceSizeY; - int videoOption; - bool fullScreenStretch; - bool disableStatusMessage; - int showSpeed; - BOOL showSpeedTransparent; - int showRenderedFrames; - bool screenMessage; - CString screenMessageBuffer; - DWORD screenMessageTime; - u8 *delta[257*244*4]; - bool menuToggle; - IDisplay *display; - IMAGE_TYPE cartridgeType; - bool soundInitialized; - bool useBiosFileGBA; - bool useBiosFileGB; - bool skipBiosFile; - CString biosFileNameGBA; - CString biosFileNameGB; - bool active; - bool paused; - CString recentFiles[10]; - bool recentFreeze; - bool autoSaveLoadCheatList; - FILE *winout; - bool removeIntros; - bool autoIPS; - int winGbBorderOn; - int winFlashSize; - bool winRtcEnable; - bool winGenericflashcardEnable; - int winSaveType; - char *rewindMemory; - int rewindPos; - int rewindTopPos; - int rewindCounter; - int rewindCount; - bool rewindSaveNeeded; - int rewindTimer; - int captureFormat; - bool tripleBuffering; - unsigned short throttle; - u32 autoFrameSkipLastTime; - bool autoFrameSkip; - bool vsync; - bool changingVideoSize; - DISPLAY_TYPE renderMethod; - AUDIO_API audioAPI; -#ifndef NO_OAL - TCHAR *oalDevice; - int oalBufferCount; -#endif - bool iconic; -#ifndef NO_D3D - int d3dFilter; - bool d3dMotionBlur; -#endif - int glFilter; - bool dinputKeyFocus; - bool pauseWhenInactive; - bool speedupToggle; - bool winGbPrinterEnabled; - int threadPriority; - bool disableMMX; - int languageOption; - CString languageName; - HMODULE languageModule; - int renderedFrames; - Input *input; - int joypadDefault; - int autoFire; - bool autoFireToggle; - bool winPauseNextFrame; - bool soundRecording; - WavWriter *soundRecorder; - CString soundRecordName; - bool dsoundDisableHardwareAcceleration; - ISound *sound; - bool aviRecording; - AVIWrite *aviRecorder; - CString aviRecordName; - bool painting; - unsigned int skipAudioFrames; - bool movieRecording; - bool moviePlaying; - int movieFrame; - int moviePlayFrame; - FILE *movieFile; - u32 movieLastJoypad; - u32 movieNextJoypad; - int sensorX; - int sensorY; - int mouseCounter; - bool wasPaused; - int frameskipadjust; - bool autoLoadMostRecent; - int fsMaxScale; - int romSize; - VIDEO_SIZE lastWindowed; - VIDEO_SIZE lastFullscreen; - - CList updateList; - int updateCount; - - CAcceleratorManager winAccelMgr; - HACCEL hAccel; - - RECT rect; - RECT dest; - - struct EmulatedSystem emulator; - - CString szFile; - CString filename; - CString dir; - - CString wndClass; - - public: - VBA(); - ~VBA(); - - void adjustDestRect(); - void updateIFB(); - void updateFilter(); - void updateThrottle( unsigned short throttle ); - void updateMenuBar(); - void winAddUpdateListener(IUpdateListener *l); - void winRemoveUpdateListener(IUpdateListener *l); - CString winLoadFilter(UINT id); - - // Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(VBA) - public: - virtual BOOL InitInstance(); - virtual BOOL OnIdle(LONG lCount); - //}}AFX_VIRTUAL - - // Implementation - - public: - void saveSettings(); - void movieReadNext(); - bool initInput(); - HMODULE winLoadLanguage(const char *name); - void winSetLanguageOption(int option, bool force); -#ifdef MMX - bool detectMMX(); -#endif - void updatePriority(); - void directXMessage(const char *msg); - void shutdownDisplay(); - bool preInitialize(); - bool updateRenderMethod0(bool force); - bool updateRenderMethod(bool force); - bool initDisplay(); - void updateWindowSize(int value); - void updateVideoSize(UINT id); - void updateFrameSkip(); - void loadSettings(); - void addRecentFile(CString file); - //{{AFX_MSG(VBA) - afx_msg void OnAppAbout(); - // NOTE - the ClassWizard will add and remove member functions here. - // DO NOT EDIT what you see in these blocks of generated code ! - //}}AFX_MSG - DECLARE_MESSAGE_MAP() - }; - - extern VBA theApp; - extern int emulating; - -#ifdef MMX - extern "C" bool cpu_mmx; -#endif +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +// VBA.h : main header file for the VBA application +// + +#pragma once + +#ifndef __AFXWIN_H__ +#error include 'stdafx.h' before including this file for PCH +#endif + +#include "stdafx.h" +#include "resource.h" +//#include + +#include "AcceleratorManager.h" +#include "Display.h" +#include "Input.h" +#include "IUpdate.h" +#include "Sound.h" +#include "../System.h" +#include "../Util.h" + +///////////////////////////////////////////////////////////////////////////// +// VBA: +// See VBA.cpp for the implementation of this class +// + +enum VIDEO_SIZE{ + VIDEO_1X, VIDEO_2X, VIDEO_3X, VIDEO_4X, + VIDEO_320x240, VIDEO_640x480, VIDEO_800x600, VIDEO_1024x768, VIDEO_1280x1024, + VIDEO_OTHER +}; + +enum pixelFilterType +{ + FILTER_NONE, + + FILTER_SIMPLE2X, FILTER_PIXELATE, FILTER_TVMODE, FILTER_SCANLINES, + FILTER_PLUGIN, + FILTER_BILINEAR, FILTER_BILINEARPLUS, FILTER_MAMESCALE2X, + FILTER_2XSAI, FILTER_SUPER2XSAI, FILTER_SUPEREAGLE, FILTER_LQ2X, FILTER_HQ2X, + + FILTER_SIMPLE3X, FILTER_HQ3X, + + FILTER_SIMPLE4X, FILTER_HQ4X +}; + +#define REWIND_SIZE 400000 + +class AVIWrite; +class WavWriter; + +class VBA : public CWinApp +{ + public: + CMenu m_menu; + HMENU menu; + HMENU popup; + bool mode320Available; + bool mode640Available; + bool mode800Available; + bool mode1024Available; + bool mode1280Available; + int windowPositionX; + int windowPositionY; + void (*filterFunction)(u8*,u32,u8*,u8*,u32,int,int); + void (*ifbFunction)(u8*,u32,int,int); + int ifbType; + int filterType; + char pluginName[MAX_PATH]; + int filterWidth; + int filterHeight; + int filterMagnification; + int filterLCD; + int fsWidth; + int fsHeight; + int fsColorDepth; + int fsFrequency; + int fsAdapter; + bool fsForceChange; + int sizeX; + int sizeY; + int surfaceSizeX; + int surfaceSizeY; + int videoOption; + bool fullScreenStretch; + bool disableStatusMessage; + int showSpeed; + BOOL showSpeedTransparent; + int showRenderedFrames; + bool screenMessage; + CString screenMessageBuffer; + DWORD screenMessageTime; + u8 *delta[257*244*4]; + bool menuToggle; + IDisplay *display; + IMAGE_TYPE cartridgeType; + bool soundInitialized; + bool useBiosFileGBA; + bool useBiosFileGB; + bool skipBiosFile; + CString biosFileNameGBA; + CString biosFileNameGB; + bool active; + bool paused; + CString recentFiles[10]; + bool recentFreeze; + bool autoSaveLoadCheatList; + FILE *winout; + bool removeIntros; + bool autoIPS; + int winGbBorderOn; + int winFlashSize; + bool winRtcEnable; + bool winGenericflashcardEnable; + int winSaveType; + char *rewindMemory; + int rewindPos; + int rewindTopPos; + int rewindCounter; + int rewindCount; + bool rewindSaveNeeded; + int rewindTimer; + int captureFormat; + bool tripleBuffering; + unsigned short throttle; + u32 autoFrameSkipLastTime; + bool autoFrameSkip; + bool vsync; + bool changingVideoSize; + DISPLAY_TYPE renderMethod; + AUDIO_API audioAPI; +#ifndef NO_OAL + TCHAR *oalDevice; + int oalBufferCount; +#endif + bool iconic; +#ifndef NO_D3D + int d3dFilter; + bool d3dMotionBlur; +#endif + int glFilter; + bool dinputKeyFocus; + bool pauseWhenInactive; + bool speedupToggle; + bool winGbPrinterEnabled; + int threadPriority; + bool disableMMX; + int languageOption; + CString languageName; + HMODULE languageModule; + int renderedFrames; + Input *input; + int joypadDefault; + int autoFire; + bool autoFireToggle; + bool winPauseNextFrame; + bool soundRecording; + WavWriter *soundRecorder; + CString soundRecordName; + bool dsoundDisableHardwareAcceleration; + ISound *sound; + bool aviRecording; + AVIWrite *aviRecorder; + CString aviRecordName; + bool painting; + unsigned int skipAudioFrames; + bool movieRecording; + bool moviePlaying; + int movieFrame; + int moviePlayFrame; + FILE *movieFile; + u32 movieLastJoypad; + u32 movieNextJoypad; + int sensorX; + int sensorY; + int mouseCounter; + bool wasPaused; + int frameskipadjust; + bool autoLoadMostRecent; + int fsMaxScale; + int romSize; + VIDEO_SIZE lastWindowed; + VIDEO_SIZE lastFullscreen; + + CList updateList; + int updateCount; + + CAcceleratorManager winAccelMgr; + HACCEL hAccel; + + RECT rect; + RECT dest; + + struct EmulatedSystem emulator; + + CString szFile; + CString filename; + CString dir; + + CString wndClass; + + public: + VBA(); + ~VBA(); + + void adjustDestRect(); + void updateIFB(); + void updateFilter(); + void updateThrottle( unsigned short throttle ); + void updateMenuBar(); + void winAddUpdateListener(IUpdateListener *l); + void winRemoveUpdateListener(IUpdateListener *l); + CString winLoadFilter(UINT id); + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(VBA) + public: + virtual BOOL InitInstance(); + virtual BOOL OnIdle(LONG lCount); + //}}AFX_VIRTUAL + + // Implementation + + public: + void saveSettings(); + void movieReadNext(); + bool initInput(); + HMODULE winLoadLanguage(const char *name); + void winSetLanguageOption(int option, bool force); +#ifdef MMX + bool detectMMX(); +#endif + void updatePriority(); + void directXMessage(const char *msg); + void shutdownDisplay(); + bool preInitialize(); + bool updateRenderMethod0(bool force); + bool updateRenderMethod(bool force); + bool initDisplay(); + void updateWindowSize(int value); + void updateVideoSize(UINT id); + void updateFrameSkip(); + void loadSettings(); + void addRecentFile(CString file); + //{{AFX_MSG(VBA) + afx_msg void OnAppAbout(); + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + }; + + extern VBA theApp; + extern int emulating; + +#ifdef MMX + extern "C" bool cpu_mmx; +#endif diff --git a/src/win32/VBA.rc b/src/win32/VBA.rc index 62712176..28548f18 100644 --- a/src/win32/VBA.rc +++ b/src/win32/VBA.rc @@ -1,2262 +1,2262 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// German (Germany) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) -#ifdef _WIN32 -LANGUAGE LANG_GERMAN, SUBLANG_GERMAN -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // German (Germany) resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,8,0,0 - PRODUCTVERSION 1,8,0,0 - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", "VBA-M comes with NO WARRANTY. Use it at your own risk." - VALUE "CompanyName", "http://vba-m.ngemu.com/" - VALUE "FileDescription", "GB & GBA emulator for Windows" - VALUE "FileVersion", "1, 8, 0, 0" - VALUE "InternalName", "VBA-M" - VALUE "LegalCopyright", "Copyright © 2008 VBA-M development team" - VALUE "OriginalFilename", "VisualBoyAdvance.exe" - VALUE "ProductName", "VBA-M - A VisualBoyAdvance Fork" - VALUE "ProductVersion", "1, 8, 0, 0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_MAINICON ICON "VBA-M.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_OAL_CONFIG DIALOGEX 0, 0, 167, 114 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "OpenAL configuration" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,66,96,48,12 - PUSHBUTTON "Cancel",IDCANCEL,114,96,48,12 - COMBOBOX IDC_DEVICE,6,18,156,36,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Select device:",IDC_STATIC,6,6,156,8 - GROUPBOX "Sound Buffer Count",IDC_STATIC,6,36,156,54 - CONTROL "",IDC_SLIDER_BUFFERCOUNT,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | WS_TABSTOP,12,48,144,24 - CTEXT "bufferInfo",IDC_BUFFERINFO,12,72,144,12,0,WS_EX_DLGMODALFRAME -END - -IDD_SELECT_PLUGIN DIALOG 0, 0, 201, 120 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Select Filter Plugin" -FONT 8, "MS Sans Serif" -BEGIN - DEFPUSHBUTTON "OK",IDOK,39,89,50,14 - PUSHBUTTON "Cancel",IDCANCEL,103,89,50,14 - COMBOBOX IDC_COMBO_PLUGIN,20,28,163,58,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP - LTEXT "Filter Plugin:",IDC_STATIC,18,15,66,8 -END - -7533 DIALOGEX 0, 0, 254, 203 -STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Link Options" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - CONTROL "Tab1",IDC_TAB1,"SysTabControl32",0x0,9,7,240,162 - PUSHBUTTON "OK",ID_OK,57,180,60,15 - PUSHBUTTON "Cancel",ID_CANCEL,140,180,57,15 -END - -7532 DIALOGEX 0, 0, 184, 79 -STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - LTEXT "Link timeout (in milliseconds)",IDC_STATIC,17,12,92,16 - EDITTEXT IDC_LINKTIMEOUT,116,10,53,14,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Single Computer",IDC_LINK_SINGLE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,17,27,71,16 - CONTROL "Network",IDC_LINK_LAN,"Button",BS_AUTORADIOBUTTON,17,43,70,16 -END - -7534 DIALOG 0, 0, 210, 113 -STYLE DS_SETFONT | WS_CHILD -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "2",IDC_LINK2P,"Button",BS_AUTORADIOBUTTON | WS_GROUP,46,16,21,13 - CONTROL "3",IDC_LINK3P,"Button",BS_AUTORADIOBUTTON,94,16,21,13 - CONTROL "4",IDC_LINK4P,"Button",BS_AUTORADIOBUTTON,142,16,21,13 - CONTROL "TCP/IP",IDC_LINKTCP,"Button",BS_AUTORADIOBUTTON | WS_GROUP,54,47,42,14 - CONTROL "UDP",IDC_LINKUDP,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,121,47,33,14 - PUSHBUTTON "Start!",IDC_SERVERSTART,79,89,50,17 - LTEXT "Select number of players:",IDC_STATIC,60,7,89,10 - LTEXT "Select protocol:",IDC_STATIC,78,33,53,11 - CONTROL "Speed hacks",IDC_SSPEED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,76,70,57,12 -END - -7535 DIALOGEX 0, 0, 188, 108 -STYLE DS_SETFONT | WS_CHILD -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - CONTROL "TCP/IP",IDC_CLINKTCP,"Button",BS_AUTORADIOBUTTON | WS_GROUP,58,20,39,12 - CONTROL "UDP",IDC_CLINKUDP,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,118,20,32,12 - EDITTEXT IDC_SERVERIP,84,39,79,12,ES_AUTOHSCROLL | WS_GROUP - PUSHBUTTON "Connect",IDC_LINKCONNECT,75,81,59,16 - LTEXT "Select protocol:",IDC_STATIC,78,7,53,9 - LTEXT "Server IP address or hostname:",IDC_STATIC,7,37,62,18 - LTEXT "Speed hacks:",IDC_STATIC,7,64,47,10 - CONTROL "Off (accurate)",IDC_SPEEDOFF,"Button",BS_AUTORADIOBUTTON | WS_GROUP,60,63,57,12 - CONTROL "On (fast)",IDC_SPEEDON,"Button",BS_AUTORADIOBUTTON,128,63,48,12 -END - -7536 DIALOG 0, 0, 186, 90 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Waiting for players" -FONT 8, "MS Sans Serif" -BEGIN - PUSHBUTTON "Cancel",IDCANCEL,63,69,50,14 - CONTROL "Progress1",IDC_SERVERWAIT,"msctls_progress32",WS_BORDER,33,50,120,13 - LTEXT "",IDC_STATIC1,7,7,154,8 - LTEXT "",IDC_STATIC2,7,17,105,8 - LTEXT "",IDC_STATIC3,7,25,105,8 - LTEXT "",IDC_STATIC4,7,33,105,8 -END - -IDD_OPENDLG DIALOG 36, 24, 202, 117 -STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CONTEXTHELP | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Open" -FONT 8, "MS Shell Dlg" -BEGIN - LTEXT "File &name:",1090,2,1,81,8 - EDITTEXT 1152,0,10,104,12,ES_AUTOHSCROLL | ES_OEMCONVERT - LISTBOX 1120,1,24,104,53,LBS_SORT | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP - LTEXT "&Folders:",-1,112,0,53,9 - LTEXT "",1088,113,10,86,9,SS_NOPREFIX - LISTBOX 1121,112,24,88,52,LBS_SORT | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP - LTEXT "List files of &type:",1089,1,75,81,9 - COMBOBOX 1136,1,87,104,13,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP - LTEXT "Dri&ves:",1091,113,76,70,9 - COMBOBOX 1137,112,87,71,68,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "OK",IDOK,24,102,50,14,WS_GROUP - PUSHBUTTON "Cancel",IDCANCEL,90,102,50,14,WS_GROUP -END - -IDD_ABOUT DIALOGEX 0, 0, 179, 153 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_TOOLWINDOW -CAPTION "About" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - ICON IDI_MAINICON,IDC_STATIC,6,6,21,20 - CTEXT "VisualBoyAdvance Emulator",IDC_STATIC,36,6,138,8 - CTEXT "Copyright © 2008 VBA-M development team",IDC_STATIC,6,48,168,8 - CTEXT "https://vbam.bountysource.com",IDC_URL,6,138,168,8 - RTEXT "Version:",IDC_STATIC,36,18,54,8 - LTEXT "",IDC_VERSION,96,18,78,8,SS_NOPREFIX - GROUPBOX "VBA-M dev team:",IDC_STATIC,6,72,90,60 - CTEXT "mudlord\nNach\nJonas Quinn\nDJRobX\nSpacy",IDC_STATIC,12,84,78,42 - RTEXT "Date compiled:",IDC_STATIC,36,30,54,8 - LTEXT "",IDC_DATE,96,30,78,8,SS_NOPREFIX - GROUPBOX "Thanks go to:",IDC_STATIC,102,72,72,60 - CTEXT "Orig. VBA team\nCostis",IDC_STATIC,108,84,60,42 -END - -IDD_DIRECTORIES DIALOGEX 0, 0, 222, 270 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Directories" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - GROUPBOX "Game Boy Advance ROMs",IDC_STATIC,6,6,210,30 - EDITTEXT IDC_ROM_PATH,12,18,180,12,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_ROM_DIR,192,18,18,12 - GROUPBOX "Game Boy Color ROMs",IDC_STATIC,6,42,210,30 - EDITTEXT IDC_GBCROM_PATH,12,54,180,12,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_GBCROM_DIR,192,54,18,12 - GROUPBOX "Game Boy ROMs",IDC_STATIC,6,78,210,30 - EDITTEXT IDC_GBROM_PATH,12,90,180,12,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_GBROM_DIR,192,90,18,12 - GROUPBOX "Native Saves",IDC_STATIC,6,114,210,30 - EDITTEXT IDC_BATTERY_PATH,12,126,180,12,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_BATTERY_DIR,192,126,18,12 - GROUPBOX "Emulator Saves",IDC_STATIC,6,150,210,30 - EDITTEXT IDC_SAVE_PATH,12,162,180,12,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_SAVE_DIR,192,162,18,12 - GROUPBOX "Screenshots",IDC_STATIC,6,186,210,30 - EDITTEXT IDC_CAPTURE_PATH,12,198,180,12,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_CAPTURE_DIR,192,198,18,12 - GROUPBOX "Relative Paths",IDC_STATIC,6,222,102,42 - CONTROL "Example:\n .\\battery\n ..\\screenshots\\vba",IDC_STATIC, - "Static",SS_LEFTNOWORDWRAP | WS_GROUP,12,234,90,24 - DEFPUSHBUTTON "OK",IDOK,120,246,48,18 - PUSHBUTTON "Cancel",IDCANCEL,168,246,48,18 -END - -IDD_CONFIG DIALOGEX 0, 0, 448, 102 -STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Joypad configuration" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - RTEXT "Up",IDC_STATIC,6,6,36,12 - EDITTEXT IDC_EDIT_UP,48,6,96,12,ES_AUTOHSCROLL - RTEXT "Down",IDC_STATIC,6,24,36,12 - EDITTEXT IDC_EDIT_DOWN,48,24,96,12,ES_AUTOHSCROLL - RTEXT "Left",IDC_STATIC,6,42,36,12 - EDITTEXT IDC_EDIT_LEFT,48,42,96,12,ES_AUTOHSCROLL - RTEXT "Right",IDC_STATIC,6,60,36,12 - EDITTEXT IDC_EDIT_RIGHT,48,60,96,12,ES_AUTOHSCROLL - RTEXT "A",IDC_STATIC,156,6,36,12 - EDITTEXT IDC_EDIT_BUTTON_A,198,6,96,12,ES_AUTOHSCROLL - RTEXT "B",IDC_STATIC,156,24,36,12 - EDITTEXT IDC_EDIT_BUTTON_B,198,24,96,12,ES_AUTOHSCROLL - RTEXT "L",IDC_STATIC,156,42,36,12 - EDITTEXT IDC_EDIT_BUTTON_L,198,42,96,12,ES_AUTOHSCROLL - RTEXT "R",IDC_STATIC,156,60,36,12 - EDITTEXT IDC_EDIT_BUTTON_R,198,60,96,12,ES_AUTOHSCROLL - RTEXT "Select",IDC_STATIC,6,84,36,12 - EDITTEXT IDC_EDIT_BUTTON_SELECT,48,84,96,12,ES_AUTOHSCROLL - RTEXT "Start",IDC_STATIC,156,84,36,12 - EDITTEXT IDC_EDIT_BUTTON_START,198,84,96,12,ES_AUTOHSCROLL - RTEXT "Speed Up",IDC_STATIC,306,6,36,12 - EDITTEXT IDC_EDIT_SPEED,348,6,96,12,ES_AUTOHSCROLL - RTEXT "Screenshot",IDC_STATIC,306,24,36,12 - EDITTEXT IDC_EDIT_CAPTURE,348,24,96,12,ES_AUTOHSCROLL - RTEXT "GS",IDC_STATIC,306,42,36,12 - EDITTEXT IDC_EDIT_BUTTON_GS,348,42,96,12,ES_AUTOHSCROLL - CONTROL "Multiple key assignments",IDC_APPENDMODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,348,60,96,12 - DEFPUSHBUTTON "OK",ID_OK,348,78,48,18 - PUSHBUTTON "Cancel",ID_CANCEL,396,78,48,18 - PUSHBUTTON "Clear all",IDC_CLEAR_ALL,306,60,36,12 -END - -IDD_CHEATS DIALOG 0, 0, 276, 253 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Search for cheats" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "",IDC_CHEAT_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,3,5,265,111 - CONTROL "Ol&d value",IDC_OLD_VALUE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,129,46,10 - CONTROL "Specifi&c value",IDC_SPECIFIC_VALUE,"Button",BS_AUTORADIOBUTTON,11,141,61,10 - CONTROL "&8 bits",IDC_SIZE_8,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,167,33,10 - CONTROL "&16 bits",IDC_SIZE_16,"Button",BS_AUTORADIOBUTTON,11,179,37,10 - CONTROL "&32 bits",IDC_SIZE_32,"Button",BS_AUTORADIOBUTTON,11,191,37,10 - CONTROL "&Equal",IDC_EQ,"Button",BS_AUTORADIOBUTTON | WS_GROUP,100,128,34,10 - CONTROL "&Not equal",IDC_NE,"Button",BS_AUTORADIOBUTTON,100,140,47,10 - CONTROL "&Less than",IDC_LT,"Button",BS_AUTORADIOBUTTON,100,152,47,10 - CONTROL "Le&ss or equal",IDC_LE,"Button",BS_AUTORADIOBUTTON,100,164,58,10 - CONTROL "&Greather than",IDC_GT,"Button",BS_AUTORADIOBUTTON,100,176,59,10 - CONTROL "G&reater or equal",IDC_GE,"Button",BS_AUTORADIOBUTTON,100,188,67,10 - CONTROL "S&igned",IDC_SIGNED,"Button",BS_AUTORADIOBUTTON | WS_GROUP,202,130,38,10 - CONTROL "&Unsigned",IDC_UNSIGNED,"Button",BS_AUTORADIOBUTTON,202,142,46,10 - CONTROL "&Hexadecimal",IDC_HEXADECIMAL,"Button",BS_AUTORADIOBUTTON,202,154,57,10 - CONTROL "U&pdate values",IDC_UPDATE,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,192,192,62,10 - EDITTEXT IDC_VALUE,95,211,172,14,ES_AUTOHSCROLL - PUSHBUTTON "&Start",IDC_START,15,237,50,14,WS_GROUP - PUSHBUTTON "S&earch",IDC_SEARCH,80,236,50,14 - PUSHBUTTON "&Add cheat",IDC_ADD_CHEAT,145,236,50,14 - DEFPUSHBUTTON "OK",ID_OK,210,236,50,14 - GROUPBOX "&Search type",IDC_STATIC,3,118,84,36 - GROUPBOX "&Data size",IDC_STATIC,3,158,84,44 - GROUPBOX "Compare type",IDC_STATIC,95,118,92,84 - GROUPBOX "Signed/Unsigned",IDC_STATIC,192,118,76,50 - LTEXT "Enter &value:",IDC_STATIC,3,214,69,8 -END - -IDD_ADD_CHEAT DIALOG 0, 0, 186, 137 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Add cheat" -FONT 8, "MS Sans Serif" -BEGIN - EDITTEXT IDC_ADDRESS,60,6,123,14,ES_AUTOHSCROLL - EDITTEXT IDC_VALUE,60,24,123,14,ES_AUTOHSCROLL - EDITTEXT IDC_DESC,60,42,123,14,ES_AUTOHSCROLL - CONTROL "8-bit",IDC_SIZE_8,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,11,70,29,10 - CONTROL "16-bit",IDC_SIZE_16,"Button",BS_AUTORADIOBUTTON,62,70,33,10 - CONTROL "32-bit",IDC_SIZE_32,"Button",BS_AUTORADIOBUTTON,117,70,33,10 - CONTROL "&Signed",IDC_SIGNED,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,11,97,38,10 - CONTROL "&Unsigned",IDC_UNSIGNED,"Button",BS_AUTORADIOBUTTON,62,98,46,10 - CONTROL "&Hexadecimal",IDC_HEXADECIMAL,"Button",BS_AUTORADIOBUTTON,117,98,57,10 - DEFPUSHBUTTON "&OK",ID_OK,36,116,50,14,WS_GROUP - PUSHBUTTON "&Cancel",ID_CANCEL,99,116,50,14 - LTEXT "&Value:",IDC_STATIC,3,27,54,8 - GROUPBOX "Number format",IDC_STATIC,3,88,180,24 - LTEXT "&Address:",IDC_STATIC,3,9,54,8 - GROUPBOX "Size",IDC_STATIC,3,60,180,24 - LTEXT "&Description:",IDC_STATIC,3,45,55,8 -END - -IDD_CHEAT_LIST DIALOG 0, 0, 280, 250 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Cheat list" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "Restore &previous values",IDC_RESTORE,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,5,183,92,10 - PUSHBUTTON "&Code...",IDC_ADD_CODE,9,208,64,14,WS_GROUP - PUSHBUTTON "C&heat...",IDC_ADD_CHEAT,75,208,64,14 - PUSHBUTTON "&Gameshark...",IDC_ADD_GAMESHARK,141,208,64,14 - PUSHBUTTON "CodeBreaker...",IDC_ADD_CODEBREAKER,206,208,64,14 - PUSHBUTTON "&Remove",IDC_REMOVE,9,230,64,14 - PUSHBUTTON "Remove A&ll",IDC_REMOVE_ALL,75,230,64,14 - PUSHBUTTON "&Enable/Dis.",IDC_ENABLE,141,230,64,14 - DEFPUSHBUTTON "&OK",ID_OK,206,230,64,14,WS_GROUP - CONTROL "",IDC_CHEAT_LIST,"SysListView32",LVS_REPORT | WS_BORDER | WS_GROUP | WS_TABSTOP,5,15,269,156 - LTEXT "Status legend:",IDC_STATIC,6,3,46,8 - LTEXT "E: Enabled",IDC_STATIC,188,3,36,8 - LTEXT "D: Disabled",IDC_STATIC,234,3,38,8 - GROUPBOX "Add",IDC_STATIC,5,199,268,27 -END - -IDD_ASSOCIATIONS DIALOG 0, 0, 116, 95 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Associations" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL ".gb",IDC_GB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,15,26,10 - CONTROL ".sgb",IDC_SGB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,29,29,10 - CONTROL ".cgb",IDC_CGB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,43,30,10 - CONTROL ".gbc",IDC_GBC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,57,30,10 - CONTROL ".gba",IDC_GBA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,13,30,10 - CONTROL ".agb",IDC_AGB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,27,30,10 - CONTROL ".bin",IDC_BIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,41,27,10 - DEFPUSHBUTTON "OK",ID_OK,3,78,50,14 - PUSHBUTTON "Cancel",ID_CANCEL,63,78,50,14 - GROUPBOX "GBA Types",IDC_STATIC,63,3,50,51 - GROUPBOX "GB Types",IDC_STATIC,3,3,50,69 -END - -IDD_GBA_ROM_INFO DIALOGEX 0, 0, 220, 142 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "ROM Information" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",ID_OK,84,121,50,14 - LTEXT "Game title:",IDC_STATIC,7,10,60,8 - LTEXT "Game code:",IDC_STATIC,7,24,60,8 - LTEXT "Maker code:",IDC_STATIC,7,38,60,8 - LTEXT "Main unit code:",IDC_STATIC,7,66,60,8 - LTEXT "Device type:",IDC_STATIC,7,80,60,8 - LTEXT "ROM version:",IDC_STATIC,7,94,60,8 - LTEXT "CRC:",IDC_STATIC,7,108,60,8 - LTEXT "Maker name:",IDC_STATIC,7,52,60,8 - LTEXT "",IDC_ROM_TITLE,80,10,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_GAME_CODE,80,24,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_MAKER_CODE,80,38,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_UNIT_CODE,80,66,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_DEVICE_TYPE,80,80,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_VERSION,80,94,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_CRC,80,108,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_MAKER_NAME,80,52,133,8,SS_NOPREFIX -END - -IDD_GB_ROM_INFO DIALOGEX 0, 0, 220, 225 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "ROM Information" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",ID_OK,40,204,50,14 - LTEXT "Game title:",IDC_STATIC,7,10,60,8 - LTEXT "Maker code:",IDC_STATIC,7,38,60,8 - LTEXT "Unit code:",IDC_STATIC,7,68,60,8 - LTEXT "Cartridge type:",IDC_STATIC,7,82,60,8 - LTEXT "ROM version:",IDC_STATIC,7,152,60,8 - LTEXT "CRC:",IDC_STATIC,7,166,60,8 - LTEXT "",IDC_ROM_TITLE,80,10,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_MAKER_CODE,80,38,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_UNIT_CODE,80,68,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_DEVICE_TYPE,80,82,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_VERSION,80,152,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_CRC,80,166,133,8,SS_NOPREFIX - LTEXT "Color:",IDC_STATIC,7,24,60,8 - LTEXT "",IDC_ROM_COLOR,80,24,133,8,SS_NOPREFIX - LTEXT "ROM size:",IDC_STATIC,7,96,60,8 - LTEXT "",IDC_ROM_SIZE,80,96,133,8,SS_NOPREFIX - LTEXT "RAM size:",IDC_STATIC,7,110,60,8 - LTEXT "",IDC_ROM_RAM_SIZE,80,110,133,8,SS_NOPREFIX - LTEXT "Dest. code:",IDC_STATIC,7,124,60,8 - LTEXT "",IDC_ROM_DEST_CODE,80,124,133,8,SS_NOPREFIX - LTEXT "License code:",IDC_STATIC,7,138,60,8 - LTEXT "",IDC_ROM_LIC_CODE,80,138,133,8,SS_NOPREFIX - LTEXT "Checksum:",IDC_STATIC,7,180,60,8 - LTEXT "",IDC_ROM_CHECKSUM,80,180,133,8,SS_NOPREFIX - LTEXT "",IDC_ROM_MAKER_NAME2,80,52,133,8,SS_NOPREFIX - LTEXT "Maker name:",IDC_STATIC,7,52,60,8 -END - -IDD_GB_CHEAT_LIST DIALOG 0, 0, 286, 221 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Gameboy Cheat List" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "",IDC_CHEAT_LIST,"SysListView32",LVS_REPORT | WS_BORDER | WS_GROUP | WS_TABSTOP,9,20,269,156 - PUSHBUTTON "Add &GameGenie...",IDC_ADD_GG_CHEAT,9,183,80,14,WS_GROUP - PUSHBUTTON "&Add GameShark...",IDC_ADD_GS_CHEAT,103,183,80,14,WS_GROUP - PUSHBUTTON "&Remove",IDC_REMOVE,197,183,80,14 - PUSHBUTTON "Remove A&ll",IDC_REMOVE_ALL,9,202,80,14 - PUSHBUTTON "&Enable/Dis.",IDC_ENABLE,103,202,80,14 - DEFPUSHBUTTON "&OK",ID_OK,197,202,80,14 - LTEXT "Status legend:",IDC_STATIC,10,9,46,8 - LTEXT "E: Enabled",IDC_STATIC,195,9,36,8 - LTEXT "D: Disabled",IDC_STATIC,241,9,38,8 -END - -IDD_ADD_CHEAT_DLG DIALOG 0, 0, 182, 107 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Title" -FONT 8, "MS Sans Serif" -BEGIN - EDITTEXT IDC_DESC,60,7,120,14,ES_AUTOHSCROLL - EDITTEXT IDC_CODE,60,23,120,58,ES_MULTILINE | ES_UPPERCASE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN - DEFPUSHBUTTON "OK",ID_OK,33,86,50,14 - PUSHBUTTON "Cancel",ID_CANCEL,99,86,50,14 - LTEXT "&Description:",IDC_STATIC,3,10,54,8 - LTEXT "&Code:",IDC_STATIC,3,29,54,8 -END - -IDD_GB_PRINTER DIALOG 0, 0, 178, 209 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "GB Printer" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "&1x",IDC_1X,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,166,22,10 - CONTROL "&2x",IDC_2X,"Button",BS_AUTORADIOBUTTON,55,166,23,10 - CONTROL "&3x",IDC_3X,"Button",BS_AUTORADIOBUTTON,98,166,23,10 - CONTROL "&4x",IDC_4X,"Button",BS_AUTORADIOBUTTON,141,166,23,10 - DEFPUSHBUTTON "&Print...",ID_PRINT,7,190,50,14,WS_GROUP - PUSHBUTTON "&Save...",ID_SAVE,64,190,50,14 - PUSHBUTTON "&Close",ID_OK,121,190,50,14 - CONTROL "",IDC_GB_PRINTER,"Static",SS_BLACKFRAME | WS_GROUP,7,6,162,146 - GROUPBOX "Print Size",IDC_STATIC,7,156,162,25 -END - -IDD_MOTION_CONFIG DIALOGEX 0, 0, 234, 107 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Motion Sensor" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - EDITTEXT IDC_EDIT_UP,41,2,186,12,ES_AUTOHSCROLL - EDITTEXT IDC_EDIT_DOWN,41,16,186,12,ES_AUTOHSCROLL - EDITTEXT IDC_EDIT_LEFT,41,30,186,12,ES_AUTOHSCROLL - EDITTEXT IDC_EDIT_RIGHT,41,44,186,12,ES_AUTOHSCROLL - PUSHBUTTON "OK",ID_OK,64,86,40,14 - PUSHBUTTON "Cancel",ID_CANCEL,118,86,40,14 - LTEXT "Up:",IDC_STATIC,5,2,35,10 - LTEXT "Down:",IDC_STATIC,5,16,35,10 - LTEXT "Left:",IDC_STATIC,5,30,35,10 - LTEXT "Right:",IDC_STATIC,5,44,35,10 - CONTROL "Assign additional keys to functions",IDC_APPENDMODE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,46,66,135,10 -END - -IDD_LANG_SELECT DIALOG 0, 0, 186, 68 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Language selection" -FONT 8, "MS Sans Serif" -BEGIN - EDITTEXT IDC_LANG_STRING,140,25,40,14,ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",ID_OK,30,49,50,14 - PUSHBUTTON "Cancel",ID_CANCEL,104,49,50,14 - LTEXT "Current system language is:",IDC_STATIC,6,9,123,8 - LTEXT "Enter language name (3 letter):",IDC_STATIC,6,30,127,8 - LTEXT "",IDC_LANG_NAME,140,9,40,8,SS_NOPREFIX -END - -IDD_CODE_SELECT DIALOG 0, 0, 316, 235 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Select codes to import" -FONT 8, "MS Sans Serif" -BEGIN - DEFPUSHBUTTON "OK",ID_OK,91,214,50,14 - PUSHBUTTON "Cancel",ID_CANCEL,174,214,50,14 - LISTBOX IDC_GAME_LIST,7,7,302,205,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP -END - -IDD_MAP_VIEW DIALOG 0, 0, 322, 238 -STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Map view" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "Frame 0",IDC_FRAME_0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,22,41,10 - CONTROL "Frame 1",IDC_FRAME_1,"Button",BS_AUTORADIOBUTTON,13,36,41,10 - CONTROL "BG0",IDC_BG0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,63,30,10 - CONTROL "BG1",IDC_BG1,"Button",BS_AUTORADIOBUTTON,13,77,30,10 - CONTROL "BG2",IDC_BG2,"Button",BS_AUTORADIOBUTTON,13,91,30,10 - CONTROL "BG3",IDC_BG3,"Button",BS_AUTORADIOBUTTON,13,105,30,10 - CONTROL "Stretch to fit",IDC_STRETCH,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,7,122,68,10 - CONTROL "Auto update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,7,134,55,10 - PUSHBUTTON "&Refresh",IDC_REFRESH,25,217,50,14,WS_GROUP - PUSHBUTTON "&Save...",IDC_SAVE,88,217,50,14,WS_GROUP - PUSHBUTTON "&Close",IDC_CLOSE,155,217,50,14 - CONTROL "MapView",IDC_MAP_VIEW,"VbaBitmapControl",WS_GROUP | WS_TABSTOP,187,15,128,128 - CONTROL "Zoom",IDC_MAP_VIEW_ZOOM,"VbaZoomControl",WS_GROUP | WS_TABSTOP,7,148,64,64 - CONTROL "Color",IDC_COLOR,"VbaColorControl",WS_TABSTOP,187,164,48,47 - LTEXT "",IDC_R,245,173,50,8,SS_NOPREFIX - LTEXT "",IDC_G,245,185,50,8,SS_NOPREFIX - LTEXT "",IDC_B,245,197,50,8,SS_NOPREFIX - GROUPBOX "Frame",IDC_STATIC,7,11,63,37 - GROUPBOX "Background",IDC_STATIC,7,52,63,67 - LTEXT "",IDC_XY,129,95,53,8,SS_NOPREFIX - LTEXT "Mode:",IDC_STATIC,80,15,34,8 - LTEXT "",IDC_MODE,130,15,53,8,SS_NOPREFIX - LTEXT "Map Base:",IDC_STATIC,80,25,35,8 - LTEXT "",IDC_MAPBASE,130,25,53,8,SS_NOPREFIX - LTEXT "Char Base:",IDC_STATIC,80,35,36,8 - LTEXT "",IDC_CHARBASE,130,35,53,8,SS_NOPREFIX - LTEXT "Size:",IDC_STATIC,80,45,37,8 - LTEXT "",IDC_DIM,130,45,53,8,SS_NOPREFIX - LTEXT "Colors:",IDC_STATIC,80,55,37,8 - LTEXT "",IDC_NUMCOLORS,130,55,53,8,SS_NOPREFIX - LTEXT "Priority:",IDC_STATIC,80,65,37,8 - LTEXT "",IDC_PRIORITY,130,65,53,8,SS_NOPREFIX - LTEXT "Mosaic:",IDC_STATIC,80,75,37,8 - LTEXT "",IDC_MOSAIC,130,75,53,8,SS_NOPREFIX - LTEXT "Overflow:",IDC_STATIC,80,85,37,8 - LTEXT "",IDC_OVERFLOW,130,85,53,8,SS_NOPREFIX - LTEXT "Address:",IDC_STATIC,80,105,37,8 - LTEXT "",IDC_ADDRESS,130,105,53,8,SS_NOPREFIX - LTEXT "Tile:",IDC_STATIC,80,115,37,8 - LTEXT "",IDC_TILE_NUM,130,115,53,8,SS_NOPREFIX - LTEXT "Flip:",IDC_STATIC,80,125,37,8 - LTEXT "",IDC_FLIP,130,125,53,8,SS_NOPREFIX - LTEXT "Palette:",IDC_STATIC,80,135,37,8 - LTEXT "",IDC_PALETTE_NUM,130,135,53,8,SS_NOPREFIX -END - -IDD_PALETTE_VIEW DIALOG 0, 0, 316, 266 -STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Palette View" -FONT 8, "MS Sans Serif" -BEGIN - PUSHBUTTON "Save BG...",IDC_SAVE_BG,30,245,50,14 - PUSHBUTTON "Save OBJ...",IDC_SAVE_OBJ,98,245,50,14 - PUSHBUTTON "&Refresh",IDC_REFRESH2,166,245,50,14 - PUSHBUTTON "&Close",IDC_CLOSE,234,245,50,14 - LTEXT "",IDC_ADDRESS,53,168,50,8,SS_NOPREFIX - LTEXT "",IDC_R,53,180,50,8,SS_NOPREFIX - LTEXT "",IDC_G,53,192,50,8,SS_NOPREFIX - LTEXT "",IDC_B,53,204,50,8,SS_NOPREFIX - LTEXT "",IDC_VALUE,53,216,50,8,SS_NOPREFIX - CONTROL "Custom1",IDC_COLOR,"VbaColorControl",WS_TABSTOP,161,168,50,50 - CONTROL "PaletteViewBG",IDC_PALETTE_VIEW,"VbaPaletteViewControl",WS_TABSTOP,12,30,128,128 - CONTROL "PaletteViewBG",IDC_PALETTE_VIEW_OBJ, - "VbaPaletteViewControl",WS_TABSTOP,166,30,128,128 - GROUPBOX "Background",IDC_STATIC,7,20,137,143 - GROUPBOX "Sprite",IDC_STATIC,161,20,137,143 - LTEXT "Address:",IDC_STATIC,7,168,38,8 - LTEXT "R:",IDC_STATIC,7,180,41,8 - LTEXT "G:",IDC_STATIC,7,192,43,8 - LTEXT "B:",IDC_STATIC,7,204,38,8 - LTEXT "Value:",IDC_STATIC,7,216,38,8 - LTEXT "Click on a color for more information",IDC_STATIC,7,7,302,8 - CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,229,71,10 -END - -IDD_MEM_VIEWER DIALOG 0, 0, 380, 178 -STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Memory viewer" -FONT 8, "MS Sans Serif" -BEGIN - COMBOBOX IDC_ADDRESSES,7,7,109,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "8-bit",IDC_8_BIT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,120,9,29,10 - CONTROL "16-bit",IDC_16_BIT,"Button",BS_AUTORADIOBUTTON,154,9,33,10 - CONTROL "32-bit",IDC_32_BIT,"Button",BS_AUTORADIOBUTTON,192,9,33,10 - EDITTEXT IDC_ADDRESS,238,7,82,14,ES_UPPERCASE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_GROUP - DEFPUSHBUTTON "&Go",IDC_GO,323,7,50,14,WS_GROUP - CONTROL "Viewer",IDC_VIEWER,"VbaMemoryViewer",WS_TABSTOP,7,22,366,112 - CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,139,71,10 - PUSHBUTTON "&Refresh",IDC_REFRESH,67,157,50,14 - PUSHBUTTON "&Load...",IDC_LOAD,132,157,50,14 - PUSHBUTTON "&Save...",IDC_SAVE,197,157,50,14 - PUSHBUTTON "&Close",IDC_CLOSE,262,157,50,14 - LTEXT "Current address:",IDC_CURRENT_ADDRESS_LABEL,210,142,77,8 - EDITTEXT IDC_CURRENT_ADDRESS,291,139,82,14,ES_RIGHT | ES_AUTOHSCROLL | WS_DISABLED -END - -IDD_OAM_VIEW DIALOGEX 0, 0, 234, 185 -STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "OAM Viewer" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - EDITTEXT IDC_SPRITE,7,19,76,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER - SCROLLBAR IDC_SCROLLBAR,7,33,76,11 - CONTROL "Stretch to fit",IDC_STRETCH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,138,79,10 - PUSHBUTTON "&Refresh",IDC_REFRESH,7,164,50,14,WS_GROUP - PUSHBUTTON "&Save...",IDC_SAVE,91,164,50,14,WS_GROUP - PUSHBUTTON "&Close",IDC_CLOSE,177,164,50,14 - CONTROL "MapView",IDC_OAM_VIEW,"VbaBitmapControl",WS_GROUP | WS_TABSTOP,87,7,64,64 - CONTROL "Zoom",IDC_OAM_VIEW_ZOOM,"VbaZoomControl",WS_GROUP | WS_TABSTOP,163,7,64,64 - CONTROL "Color",IDC_COLOR,"VbaColorControl",WS_TABSTOP,87,79,48,47 - LTEXT "",IDC_POS,31,47,50,8,SS_NOPREFIX - LTEXT "",IDC_MODE,31,57,50,8,SS_NOPREFIX - LTEXT "",IDC_COLORS,31,67,50,8,SS_NOPREFIX - LTEXT "",IDC_PALETTE,31,77,50,8,SS_NOPREFIX - LTEXT "",IDC_TILE,31,87,50,8,SS_NOPREFIX - LTEXT "",IDC_PRIO,31,97,50,8,SS_NOPREFIX - LTEXT "",IDC_SIZE2,31,107,50,8,SS_NOPREFIX - LTEXT "",IDC_ROT,31,117,50,8,SS_NOPREFIX - LTEXT "",IDC_FLAGS,31,127,50,8,SS_NOPREFIX - LTEXT "",IDC_R,145,88,50,8,SS_NOPREFIX - LTEXT "",IDC_G,145,100,50,8,SS_NOPREFIX - LTEXT "",IDC_B,145,112,50,8,SS_NOPREFIX - LTEXT "Pos:",IDC_STATIC,7,47,24,8 - LTEXT "Mode:",IDC_STATIC,7,57,24,8 - LTEXT "Colors:",IDC_STATIC,7,67,24,8 - LTEXT "Pal:",IDC_STATIC,7,77,24,8 - LTEXT "Tile:",IDC_STATIC,7,87,24,8 - LTEXT "Prio:",IDC_STATIC,7,97,24,8 - LTEXT "Size:",IDC_STATIC,7,107,24,8 - LTEXT "Sprite:",IDC_STATIC,7,7,50,8 - LTEXT "Rot.:",IDC_STATIC,7,117,24,8 - LTEXT "Flags:",IDC_STATIC,7,127,24,8 - CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,150,71,10 -END - -IDD_ACCEL_EDITOR DIALOGEX 0, 0, 399, 121 -STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Accelerator editor" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - LTEXT "&Commands:",IDC_STATIC,7,7,38,8 - LISTBOX IDC_COMMANDS,7,18,153,67,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP - LTEXT "Current &Keys:",IDC_STATIC1,176,7,43,8 - LISTBOX IDC_CURRENTS,176,17,153,67,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "OK",ID_OK,342,9,50,14 - PUSHBUTTON "Cancel",ID_CANCEL,342,25,50,14 - LTEXT "Select &New Shortcut Key:",IDC_STATIC3,175,86,82,8 - EDITTEXT IDC_EDIT_KEY,176,95,100,12,ES_AUTOHSCROLL - PUSHBUTTON "&Assign",IDC_ASSIGN,342,70,50,14 - PUSHBUTTON "&Remove",IDC_REMOVE,342,86,50,14 - PUSHBUTTON "Re&set All",IDC_RESET,342,102,50,14 - LTEXT "Static",IDC_ALREADY_AFFECTED,7,96,105,9,SS_CENTERIMAGE - LTEXT "Currently assigned to :",IDC_STATIC2,7,87,73,10 -END - -IDD_TILE_VIEWER DIALOG 0, 0, 326, 266 -STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Tile Viewer" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "16",IDC_16_COLORS,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,20,24,10 - CONTROL "256",IDC_256_COLORS,"Button",BS_AUTORADIOBUTTON,13,30,28,10 - CONTROL "0x6000000",IDC_CHARBASE_0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,57,51,10 - CONTROL "0x6004000",IDC_CHARBASE_1,"Button",BS_AUTORADIOBUTTON,13,67,51,10 - CONTROL "0x6008000",IDC_CHARBASE_2,"Button",BS_AUTORADIOBUTTON,13,77,51,10 - CONTROL "0x600C000",IDC_CHARBASE_3,"Button",BS_AUTORADIOBUTTON,13,87,52,10 - CONTROL "0x6010000",IDC_CHARBASE_4,"Button",BS_AUTORADIOBUTTON,13,97,49,10 - CONTROL "Slider1",IDC_PALETTE_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,1,124,76,22 - CONTROL "Stretch to fit",IDC_STRETCH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,149,79,10 - PUSHBUTTON "Refresh",IDC_REFRESH,7,245,50,14,WS_GROUP - PUSHBUTTON "Save...",IDC_SAVE,138,245,50,14 - PUSHBUTTON "Close",IDC_CLOSE,269,245,50,14 - CONTROL "Custom1",IDC_TILE_VIEW,"VbaBitmapControl",WS_GROUP | WS_TABSTOP,191,7,128,128 - GROUPBOX "Colors",IDC_STATIC,7,7,66,38 - GROUPBOX "Char Base",IDC_STATIC,7,46,65,64 - CONTROL "Zoom",IDC_MAP_VIEW_ZOOM,"VbaZoomControl",WS_GROUP | WS_TABSTOP,7,174,64,64 - CONTROL "Color",IDC_COLOR,"VbaColorControl",WS_TABSTOP,98,183,48,47 - LTEXT "",IDC_R,156,192,50,8,SS_NOPREFIX - LTEXT "",IDC_G,156,204,50,8,SS_NOPREFIX - LTEXT "",IDC_B,156,216,50,8,SS_NOPREFIX - LTEXT "Palette:",IDC_STATIC,7,113,65,8 - CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,160,71,10 - LTEXT "Tile:",IDC_STATIC,79,14,41,8 - LTEXT "Address:",IDC_STATIC,79,26,41,8 - LTEXT "",IDC_TILE_NUMBER,135,14,50,8,SS_NOPREFIX - LTEXT "",IDC_ADDRESS,135,26,50,8,SS_NOPREFIX -END - -IDD_GB_COLORS DIALOG 0, 0, 169, 121 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Gameboy Mono Colors" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "Default",IDC_DEFAULT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7,7,39,10 - CONTROL "User 1",IDC_USER1,"Button",BS_AUTORADIOBUTTON,67,7,37,10 - CONTROL "User 2",IDC_USER2,"Button",BS_AUTORADIOBUTTON,125,7,37,10 - COMBOBOX IDC_PREDEFINED,7,21,155,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "",IDC_COLOR_BG0,15,47,28,14,WS_GROUP - PUSHBUTTON "",IDC_COLOR_BG1,52,47,28,14 - PUSHBUTTON "",IDC_COLOR_BG2,89,47,28,14 - PUSHBUTTON "",IDC_COLOR_BG3,126,47,28,14 - PUSHBUTTON "",IDC_COLOR_OB0,15,78,28,14 - PUSHBUTTON "",IDC_COLOR_OB1,52,78,28,14 - PUSHBUTTON "",IDC_COLOR_OB2,89,78,28,14 - PUSHBUTTON "",IDC_COLOR_OB3,126,78,28,14 - PUSHBUTTON "Reset",IDC_RESET,7,100,50,14 - DEFPUSHBUTTON "OK",ID_OK,59,100,50,14 - PUSHBUTTON "Cancel",ID_CANCEL,111,100,50,14 - GROUPBOX "Background",IDC_STATIC,8,37,154,29 - GROUPBOX "Sprite",IDC_STATIC,8,67,154,30 -END - -IDD_DISASSEMBLE DIALOG 0, 0, 402, 225 -STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Disassemble" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "Automatic",IDC_AUTOMATIC,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7,9,47,10 - CONTROL "ARM",IDC_ARM,"Button",BS_AUTORADIOBUTTON,62,9,32,10 - CONTROL "THUMB",IDC_THUMB,"Button",BS_AUTORADIOBUTTON,103,9,42,10 - EDITTEXT IDC_ADDRESS,158,7,65,14,ES_UPPERCASE | ES_AUTOHSCROLL | WS_GROUP - DEFPUSHBUTTON "Go",IDC_GO,232,7,50,14 - LISTBOX IDC_DISASSEMBLE,7,25,276,161,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_TABSTOP - CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,191,71,10 - PUSHBUTTON "Refresh",IDC_REFRESH,120,204,50,14 - PUSHBUTTON "Next",IDC_NEXT,233,204,50,14 - PUSHBUTTON "Close",IDC_CLOSE,346,204,50,14 - LTEXT "R0:",IDC_STATIC,309,7,18,8 - LTEXT "R1:",IDC_STATIC,309,15,18,8 - LTEXT "R2:",IDC_STATIC,309,23,18,8 - LTEXT "R3:",IDC_STATIC,309,31,18,8 - LTEXT "R4:",IDC_STATIC,309,39,18,8 - LTEXT "R5:",IDC_STATIC,309,47,18,8 - LTEXT "R6:",IDC_STATIC,309,55,18,8 - LTEXT "R7:",IDC_STATIC,309,63,18,8 - LTEXT "",IDC_R0,344,7,52,8,SS_NOPREFIX - LTEXT "",IDC_R1,344,15,52,8,SS_NOPREFIX - LTEXT "",IDC_R2,344,23,52,8,SS_NOPREFIX - LTEXT "",IDC_R3,344,31,52,8,SS_NOPREFIX - LTEXT "",IDC_R4,344,39,52,8,SS_NOPREFIX - LTEXT "",IDC_R5,344,47,52,8,SS_NOPREFIX - LTEXT "",IDC_R6,344,55,52,8,SS_NOPREFIX - LTEXT "",IDC_R7,344,63,52,8,SS_NOPREFIX - LTEXT "",IDC_R8,344,71,52,8,SS_NOPREFIX - LTEXT "",IDC_R9,344,79,52,8,SS_NOPREFIX - LTEXT "",IDC_R10,344,87,52,8,SS_NOPREFIX - LTEXT "",IDC_R11,344,95,52,8,SS_NOPREFIX - LTEXT "",IDC_R12,344,103,52,8,SS_NOPREFIX - LTEXT "",IDC_R13,344,111,52,8,SS_NOPREFIX - LTEXT "",IDC_R14,344,119,52,8,SS_NOPREFIX - LTEXT "",IDC_R15,344,127,52,8,SS_NOPREFIX - LTEXT "R8:",IDC_STATIC,309,71,18,8 - LTEXT "R9:",IDC_STATIC,309,79,18,8 - LTEXT "R10:",IDC_STATIC,309,87,18,8 - LTEXT "R11:",IDC_STATIC,309,95,18,8 - LTEXT "R12:",IDC_STATIC,309,103,18,8 - LTEXT "R13:",IDC_STATIC,309,111,18,8 - LTEXT "R14:",IDC_STATIC,309,119,18,8 - LTEXT "R15:",IDC_STATIC,309,127,18,8 - LTEXT "",IDC_R16,344,135,52,8,SS_NOPREFIX - LTEXT "R16:",IDC_STATIC,309,135,20,8 - CONTROL "N",IDC_N,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,309,146,21,10 - CONTROL "Z",IDC_Z,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,309,156,21,10 - CONTROL "C",IDC_C,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,309,166,21,10 - CONTROL "V",IDC_V,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,309,176,21,10 - CONTROL "F",IDC_F,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,342,156,20,10 - CONTROL "I",IDC_I,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,342,146,18,10 - CONTROL "T",IDC_T,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,342,166,21,10 - LTEXT "Mode:",IDC_STATIC,341,176,21,8 - LTEXT "",IDC_MODE,376,176,20,8,SS_NOPREFIX - SCROLLBAR IDC_VSCROLL,283,25,10,161,SBS_VERT - PUSHBUTTON "Goto R15",IDC_GOPC,7,204,50,14 -END - -IDD_GDB_PORT DIALOG 0, 0, 186, 51 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "GDB connection" -FONT 8, "MS Sans Serif" -BEGIN - DEFPUSHBUTTON "OK",ID_OK,34,30,50,14 - PUSHBUTTON "Cancel",ID_CANCEL,102,30,50,14 - LTEXT "Port to wait for connection:",IDC_STATIC,7,10,105,8 - EDITTEXT IDC_PORT,125,7,54,14,ES_RIGHT | ES_AUTOHSCROLL -END - -IDD_GDB_WAITING DIALOG 0, 0, 186, 44 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Waiting..." -FONT 8, "MS Sans Serif" -BEGIN - PUSHBUTTON "Cancel",ID_CANCEL,67,23,50,14 - LTEXT "Waiting for connection on port:",IDC_STATIC,7,7,117,8 - LTEXT "",IDC_PORT,143,7,36,8,SS_NOPREFIX -END - -IDD_LOGGING DIALOG 0, 0, 366, 218 -STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Logging" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "SWI",IDC_VERBOSE_SWI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,17,87,10 - CONTROL "Unaligned memory",IDC_VERBOSE_UNALIGNED_ACCESS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,30,87,10 - CONTROL "Illegal write",IDC_VERBOSE_ILLEGAL_WRITE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,43,87,10 - CONTROL "Illegal read",IDC_VERBOSE_ILLEGAL_READ,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,56,87,10 - CONTROL "DMA 0",IDC_VERBOSE_DMA0,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,69,87,10 - CONTROL "DMA 1",IDC_VERBOSE_DMA1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,82,87,10 - CONTROL "DMA 2",IDC_VERBOSE_DMA2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,95,87,10 - CONTROL "DMA 3",IDC_VERBOSE_DMA3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,108,87,10 - CONTROL "Undefined instruction",IDC_VERBOSE_UNDEFINED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,121,87,10 - CONTROL "AGBPrint",IDC_VERBOSE_AGBPRINT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,134,87,10 - EDITTEXT IDC_LOG,107,7,252,183,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL - PUSHBUTTON "Save...",IDC_SAVE,75,197,50,14 - PUSHBUTTON "Clear",IDC_CLEAR,137,197,50,14 - DEFPUSHBUTTON "OK",ID_OK,197,197,50,14 - GROUPBOX "Verbose",IDC_STATIC,7,7,93,142 -END - -IDD_EXPORT_SPS DIALOGEX 0, 0, 248, 148 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Export GameShark Snapshot" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - EDITTEXT IDC_TITLE,84,7,157,14,ES_AUTOHSCROLL - EDITTEXT IDC_DESC,84,27,157,14,ES_AUTOHSCROLL - EDITTEXT IDC_NOTES,84,47,157,73,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN - DEFPUSHBUTTON "OK",ID_OK,67,127,50,14 - PUSHBUTTON "Cancel",ID_CANCEL,130,127,50,14 - LTEXT "Title:",IDC_STATIC,7,8,62,8 - LTEXT "Description:",IDC_STATIC,7,28,63,8 - LTEXT "Notes:",IDC_STATIC,7,48,60,8 -END - -IDD_ADDR_SIZE DIALOG 0, 0, 186, 67 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Enter address and size" -FONT 8, "MS Sans Serif" -BEGIN - EDITTEXT IDC_ADDRESS,99,6,80,14,ES_AUTOHSCROLL - EDITTEXT IDC_SIZE_CONTROL,99,26,80,14,ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",ID_OK,34,46,50,14 - PUSHBUTTON "Cancel",ID_CANCEL,102,46,50,14 - LTEXT "Address:",IDC_STATIC,7,11,65,8 - LTEXT "Size:",IDC_STATIC,7,29,65,8 -END - -IDD_THROTTLE DIALOGEX 0, 0, 126, 60 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Throttle" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - EDITTEXT IDC_THROTTLE,6,18,114,12,ES_CENTER | ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",ID_OK,6,36,54,18 - PUSHBUTTON "Cancel",ID_CANCEL,66,36,54,18 - CTEXT "Enter desired throttle (5%...1000%):",IDC_STATIC,6,6,114,8 -END - -IDD_GB_DISASSEMBLE DIALOG 0, 0, 344, 225 -STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "GB Disassemble" -FONT 8, "MS Sans Serif" -BEGIN - EDITTEXT IDC_ADDRESS,7,7,65,14,ES_UPPERCASE | ES_AUTOHSCROLL | WS_GROUP - DEFPUSHBUTTON "Go",IDC_GO,81,7,50,14 - LISTBOX IDC_DISASSEMBLE,7,25,222,161,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_TABSTOP - CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,191,71,10 - PUSHBUTTON "Refresh",IDC_REFRESH,100,204,50,14 - PUSHBUTTON "Next",IDC_NEXT,193,204,50,14 - PUSHBUTTON "Close",IDC_CLOSE,287,204,50,14 - LTEXT "AF:",IDC_STATIC,250,25,18,8 - LTEXT "BC:",IDC_STATIC,250,35,18,8 - LTEXT "DE:",IDC_STATIC,250,45,18,8 - LTEXT "HL:",IDC_STATIC,250,55,18,8 - LTEXT "IFF:",IDC_STATIC,250,85,18,8 - LTEXT "LY:",IDC_STATIC,272,95,18,8 - LTEXT "",IDC_R0,285,25,52,8,SS_NOPREFIX - LTEXT "",IDC_R1,285,35,52,8,SS_NOPREFIX - LTEXT "",IDC_R2,285,45,52,8,SS_NOPREFIX - LTEXT "",IDC_R3,285,55,52,8,SS_NOPREFIX - LTEXT "",IDC_R6,285,85,52,8,SS_NOPREFIX - LTEXT "",IDC_LY,285,95,52,8,SS_NOPREFIX - CONTROL "N",IDC_N,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,250,109,21,10 - CONTROL "Z",IDC_Z,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,250,97,21,10 - CONTROL "C",IDC_C,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,250,133,21,10 - CONTROL "H",IDC_H,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,250,121,21,10 - SCROLLBAR IDC_VSCROLL,229,25,10,161,SBS_VERT - PUSHBUTTON "Goto PC",IDC_GOPC,7,204,50,14 - LTEXT "SP:",IDC_STATIC,250,65,18,8 - LTEXT "",IDC_R4,285,65,52,8,SS_NOPREFIX - LTEXT "PC:",IDC_STATIC,250,75,18,8 - LTEXT "",IDC_R5,285,75,52,8,SS_NOPREFIX -END - -IDD_GB_OAM_VIEW DIALOG 0, 0, 234, 185 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "GB Oam Viewer" -FONT 8, "MS Sans Serif" -BEGIN - EDITTEXT IDC_SPRITE,7,19,76,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER - SCROLLBAR IDC_SCROLLBAR,7,33,76,11 - CONTROL "Stretch to fit",IDC_STRETCH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,138,79,10 - PUSHBUTTON "&Refresh",IDC_REFRESH,7,164,50,14,WS_GROUP - PUSHBUTTON "&Save...",IDC_SAVE,91,164,50,14,WS_GROUP - PUSHBUTTON "&Close",IDC_CLOSE,177,164,50,14 - CONTROL "MapView",IDC_OAM_VIEW,"VbaBitmapControl",WS_GROUP | WS_TABSTOP,87,7,64,64 - CONTROL "Zoom",IDC_OAM_VIEW_ZOOM,"VbaZoomControl",WS_GROUP | WS_TABSTOP,163,7,64,64 - CONTROL "Color",IDC_COLOR,"VbaColorControl",WS_TABSTOP,87,79,48,47 - LTEXT "",IDC_POS,31,47,50,8,SS_NOPREFIX - LTEXT "",IDC_PALETTE,31,87,50,8,SS_NOPREFIX - LTEXT "",IDC_TILE,31,57,50,8,SS_NOPREFIX - LTEXT "",IDC_PRIO,31,67,50,8,SS_NOPREFIX - LTEXT "",IDC_OAP,31,77,50,8,SS_NOPREFIX - LTEXT "",IDC_FLAGS,31,97,50,8,SS_NOPREFIX - LTEXT "",IDC_R,145,88,50,8,SS_NOPREFIX - LTEXT "",IDC_G,145,100,50,8,SS_NOPREFIX - LTEXT "",IDC_B,145,112,50,8,SS_NOPREFIX - LTEXT "Pos:",IDC_STATIC,7,47,24,8 - LTEXT "Pal:",IDC_STATIC,7,87,24,8 - LTEXT "Tile:",IDC_STATIC,7,57,24,8 - LTEXT "Prio:",IDC_STATIC,7,67,24,8 - LTEXT "OAP:",IDC_STATIC,7,77,24,8 - LTEXT "Sprite:",IDC_STATIC,7,7,50,8 - LTEXT "Flags:",IDC_STATIC,7,97,24,8 - CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,150,71,10 - LTEXT "",IDC_BANK,31,107,50,8,SS_NOPREFIX - LTEXT "Bank:",IDC_STATIC,7,107,24,8 -END - -IDD_GB_TILE_VIEWER DIALOG 0, 0, 326, 238 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "GB Tile Viewer" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "0",IDC_BANK_0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,20,20,10 - CONTROL "1",IDC_BANK_1,"Button",BS_AUTORADIOBUTTON,13,30,20,10 - CONTROL "0x8000",IDC_CHARBASE_0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,57,39,10 - CONTROL "0x8800",IDC_CHARBASE_1,"Button",BS_AUTORADIOBUTTON,13,67,39,10 - CONTROL "Stretch to fit",IDC_STRETCH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,122,79,10 - PUSHBUTTON "Refresh",IDC_REFRESH,7,217,50,14,WS_GROUP - PUSHBUTTON "Save...",IDC_SAVE,138,217,50,14 - PUSHBUTTON "Close",IDC_CLOSE,269,217,50,14 - CONTROL "Custom1",IDC_TILE_VIEW,"VbaBitmapControl",WS_GROUP | WS_TABSTOP,191,7,128,128 - GROUPBOX "VRAM Bank",IDC_STATIC,7,7,66,38 - GROUPBOX "Char Base",IDC_STATIC,7,46,65,35 - CONTROL "Zoom",IDC_MAP_VIEW_ZOOM,"VbaZoomControl",WS_GROUP | WS_TABSTOP,7,147,64,64 - CONTROL "Color",IDC_COLOR,"VbaColorControl",WS_TABSTOP,98,156,48,47 - LTEXT "",IDC_R,156,164,50,8,SS_NOPREFIX - LTEXT "",IDC_G,156,176,50,8,SS_NOPREFIX - LTEXT "",IDC_B,156,188,50,8,SS_NOPREFIX - LTEXT "Palette:",IDC_STATIC,7,86,65,8 - CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,133,71,10 - LTEXT "Tile:",IDC_STATIC,79,14,41,8 - LTEXT "Address:",IDC_STATIC,79,26,41,8 - LTEXT "",IDC_TILE_NUMBER,135,14,50,8,SS_NOPREFIX - LTEXT "",IDC_ADDRESS,135,26,50,8,SS_NOPREFIX - CONTROL "Slider1",IDC_PALETTE_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,1,98,76,22 -END - -IDD_GB_MAP_VIEW DIALOG 0, 0, 322, 238 -STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "GB Map Viewer" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "0x8000",IDC_BANK_0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,22,39,10 - CONTROL "0x8800",IDC_BANK_1,"Button",BS_AUTORADIOBUTTON,13,36,39,10 - CONTROL "0x9800",IDC_BG0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,63,39,10 - CONTROL "0x9C00",IDC_BG1,"Button",BS_AUTORADIOBUTTON,13,77,40,10 - CONTROL "Stretch to fit",IDC_STRETCH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,122,68,10 - PUSHBUTTON "&Refresh",IDC_REFRESH,25,217,50,14,WS_GROUP - PUSHBUTTON "&Save...",IDC_SAVE,88,217,50,14,WS_GROUP - PUSHBUTTON "&Close",IDC_CLOSE,155,217,50,14 - CONTROL "MapView",IDC_MAP_VIEW,"VbaBitmapControl",WS_GROUP | WS_TABSTOP,187,15,128,128 - CONTROL "Zoom",IDC_MAP_VIEW_ZOOM,"VbaZoomControl",WS_GROUP | WS_TABSTOP,7,148,64,64 - CONTROL "Color",IDC_COLOR,"VbaColorControl",WS_TABSTOP,187,164,48,47 - LTEXT "",IDC_R,245,173,50,8,SS_NOPREFIX - LTEXT "",IDC_G,245,185,50,8,SS_NOPREFIX - LTEXT "",IDC_B,245,197,50,8,SS_NOPREFIX - GROUPBOX "Char Base",IDC_STATIC,7,11,63,37 - GROUPBOX "Map Base",IDC_STATIC,7,52,63,41 - CONTROL "Auto update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,134,55,10 - LTEXT "",IDC_XY,129,18,53,8,SS_NOPREFIX - LTEXT "Priority:",IDC_STATIC,80,68,37,8 - LTEXT "",IDC_PRIORITY,130,68,53,8,SS_NOPREFIX - LTEXT "Address:",IDC_STATIC,80,28,37,8 - LTEXT "",IDC_ADDRESS,130,28,53,8,SS_NOPREFIX - LTEXT "Tile:",IDC_STATIC,80,38,37,8 - LTEXT "",IDC_TILE_NUM,130,38,53,8,SS_NOPREFIX - LTEXT "Flip:",IDC_STATIC,80,48,37,8 - LTEXT "",IDC_FLIP,130,48,53,8,SS_NOPREFIX - LTEXT "Palette:",IDC_STATIC,80,58,37,8 - LTEXT "",IDC_PALETTE_NUM,130,58,53,8,SS_NOPREFIX -END - -IDD_GB_PALETTE_VIEW DIALOG 0, 0, 196, 234 -STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "GB Palette Viewer" -FONT 8, "MS Sans Serif" -BEGIN - PUSHBUTTON "Save BG...",IDC_SAVE_BG,7,191,50,14 - PUSHBUTTON "Save OBJ...",IDC_SAVE_OBJ,73,191,50,14 - PUSHBUTTON "&Refresh",IDC_REFRESH2,139,191,50,14 - PUSHBUTTON "&Close",IDC_CLOSE,73,213,50,14 - LTEXT "",IDC_ADDRESS,53,117,50,8,SS_NOPREFIX - LTEXT "",IDC_R,53,129,50,8,SS_NOPREFIX - LTEXT "",IDC_G,53,141,50,8,SS_NOPREFIX - LTEXT "",IDC_B,53,153,50,8,SS_NOPREFIX - LTEXT "",IDC_VALUE,53,165,50,8,SS_NOPREFIX - CONTROL "Custom1",IDC_COLOR,"VbaColorControl",WS_TABSTOP,119,117,50,50 - CONTROL "PaletteViewBG",IDC_PALETTE_VIEW,"VbaPaletteViewControl",WS_TABSTOP,11,30,64,64 - CONTROL "PaletteViewBG",IDC_PALETTE_VIEW_OBJ, - "VbaPaletteViewControl",WS_TABSTOP,120,30,64,64 - GROUPBOX "BG",IDC_STATIC,6,20,74,81 - GROUPBOX "Sprite",IDC_STATIC,115,20,74,81 - LTEXT "Index:",IDC_STATIC,7,117,38,8 - LTEXT "R:",IDC_STATIC,7,129,41,8 - LTEXT "G:",IDC_STATIC,7,141,43,8 - LTEXT "B:",IDC_STATIC,7,153,38,8 - LTEXT "Value:",IDC_STATIC,7,165,38,8 - LTEXT "Click on a color for more information",IDC_STATIC,7,7,182,8 - CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,178,71,10 -END - -IDD_REWIND_INTERVAL DIALOG 0, 0, 186, 68 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Select rewind interval" -FONT 8, "MS Sans Serif" -BEGIN - EDITTEXT IDC_INTERVAL,7,28,172,14,ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",ID_OK,37,47,50,14 - PUSHBUTTON "Cancel",ID_CANCEL,99,47,50,14 - LTEXT "Enter rewind interval (0...600) seconds:",IDC_STATIC,7,7,172,8 - LTEXT "Enter 0 to disable rewind.",IDC_STATIC,7,17,172,8 -END - -IDD_IO_VIEWER DIALOG 0, 0, 269, 238 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "I/O Viewer" -FONT 8, "MS Sans Serif" -BEGIN - COMBOBOX IDC_ADDRESSES,7,7,255,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - RTEXT "",IDC_VALUE,103,23,159,8 - CONTROL "",IDC_BIT_15,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,34,255,10 - CONTROL "",IDC_BIT_14,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,44,255,10 - CONTROL "",IDC_BIT_13,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,54,255,8 - CONTROL "",IDC_BIT_12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,64,255,10 - CONTROL "",IDC_BIT_11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,74,255,10 - CONTROL "",IDC_BIT_10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,84,255,10 - CONTROL "",IDC_BIT_9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,94,255,10 - CONTROL "",IDC_BIT_8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,104,255,10 - CONTROL "",IDC_BIT_7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,114,255,10 - CONTROL "",IDC_BIT_6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,124,255,10 - CONTROL "",IDC_BIT_5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,134,255,10 - CONTROL "",IDC_BIT_4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,144,255,10 - CONTROL "",IDC_BIT_3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,154,255,10 - CONTROL "",IDC_BIT_2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,164,255,10 - CONTROL "",IDC_BIT_1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,174,255,10 - CONTROL "",IDC_BIT_0,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,184,255,10 - CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,201,71,10 - DEFPUSHBUTTON "&Refresh",IDC_REFRESH,54,221,50,14 - DEFPUSHBUTTON "&Apply",IDC_APPLY,110,221,50,14 - PUSHBUTTON "&Close",IDC_CLOSE,166,221,50,14 - LTEXT "Value:",IDC_STATIC,7,23,72,8 -END - -IDD_MAX_SCALE DIALOG 0, 0, 186, 68 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Fullscreen scale" -FONT 8, "MS Sans Serif" -BEGIN - EDITTEXT IDC_VALUE,7,28,172,14,ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",ID_OK,37,47,50,14 - PUSHBUTTON "Cancel",ID_CANCEL,99,47,50,14 - LTEXT "Enter the maxium fullscreen scale:",IDC_STATIC,7,7,172,8 - LTEXT "Enter 0 to use maximum scale.",IDC_STATIC,7,17,172,8 -END - -IDD_GAME_OVERRIDES DIALOGEX 0, 0, 268, 132 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Game overrides" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - COMBOBOX IDC_RTC,84,42,180,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_SAVE_TYPE,84,60,180,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_FLASH_SIZE,84,78,180,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_MIRRORING,84,96,180,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "OK",IDOK,6,114,72,12 - PUSHBUTTON "Defaults",IDC_DEFAULTS,108,114,54,12 - PUSHBUTTON "Cancel",IDCANCEL,192,114,72,12 - LTEXT "Game Code",IDC_STATIC,6,6,72,12 - EDITTEXT IDC_NAME,84,6,180,12,ES_AUTOHSCROLL | WS_DISABLED - LTEXT "Real Time Clock:",IDC_STATIC,6,42,72,12 - LTEXT "Save Type:",IDC_STATIC,6,60,72,12 - LTEXT "Flash Size:",IDC_STATIC,6,78,72,12 - LTEXT "Mirroring:",IDC_STATIC,6,96,72,12 - LTEXT "Comment",IDC_STATIC,6,24,72,12 - EDITTEXT IDC_COMMENT,84,24,180,12,ES_AUTOHSCROLL -END - -IDD_BIOS DIALOGEX 0, 0, 220, 126 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "BIOS Files" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,84,102,60,18 - PUSHBUTTON "Cancel",IDCANCEL,150,102,60,18 - GROUPBOX "Game Boy mono",IDC_STATIC,6,6,210,30 - GROUPBOX "Game Boy Advance",IDC_STATIC,6,48,210,30 - EDITTEXT IDC_GB_BIOS_PATH,12,18,180,12,ES_AUTOHSCROLL - EDITTEXT IDC_GBA_BIOS_PATH,12,60,180,12,ES_AUTOHSCROLL - GROUPBOX "Options",IDC_STATIC,6,90,72,30 - CONTROL "Skip boot logo",IDC_SKIP_BOOT_LOGO,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,12,102,60,12 - CONTROL "Enable",IDC_ENABLE_GB_BIOS,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,174,6,36,8 - CONTROL "Enable",IDC_ENABLE_GBA_BIOS,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,174,48,36,8 - PUSHBUTTON "...",IDC_SELECT_GB_BIOS_PATH,192,18,18,12 - PUSHBUTTON "...",IDC_SELECT_GBA_BIOS_PATH,192,60,18,12 -END - -IDD_FULLSCREEN DIALOGEX 0, 0, 167, 96 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Fullscreen Settings" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,60,78,48,12 - PUSHBUTTON "Cancel",IDCANCEL,114,78,48,12 - COMBOBOX IDC_COMBO_RESOLUTION,60,42,102,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - RTEXT "Resolution:",IDC_STATIC,6,42,48,12 - RTEXT "Color depth:",IDC_STATIC,6,24,48,12 - COMBOBOX IDC_COMBO_COLOR_DEPTH,60,24,102,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - RTEXT "Refresh rate:",IDC_STATIC,6,60,48,12 - COMBOBOX IDC_COMBO_REFRESH_RATE,60,60,102,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_COMBO_DEVICE,60,6,102,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - RTEXT "Device:",IDC_STATIC,6,6,48,12 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_OAL_CONFIG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 160 - TOPMARGIN, 7 - BOTTOMMARGIN, 107 - END - - IDD_OPENDLG, DIALOG - BEGIN - RIGHTMARGIN, 165 - END - - IDD_ABOUT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 172 - TOPMARGIN, 7 - BOTTOMMARGIN, 146 - END - - IDD_DIRECTORIES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 215 - TOPMARGIN, 7 - BOTTOMMARGIN, 263 - END - - IDD_CONFIG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 441 - TOPMARGIN, 7 - BOTTOMMARGIN, 95 - END - - IDD_CHEATS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 269 - TOPMARGIN, 7 - BOTTOMMARGIN, 246 - END - - IDD_ADD_CHEAT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 130 - END - - IDD_CHEAT_LIST, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 273 - TOPMARGIN, 7 - BOTTOMMARGIN, 243 - END - - IDD_ASSOCIATIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 109 - TOPMARGIN, 7 - BOTTOMMARGIN, 88 - END - - IDD_GBA_ROM_INFO, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 213 - TOPMARGIN, 7 - BOTTOMMARGIN, 135 - END - - IDD_GB_ROM_INFO, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 213 - TOPMARGIN, 7 - BOTTOMMARGIN, 218 - END - - IDD_GB_CHEAT_LIST, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 279 - TOPMARGIN, 7 - BOTTOMMARGIN, 214 - END - - IDD_ADD_CHEAT_DLG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 175 - TOPMARGIN, 7 - BOTTOMMARGIN, 100 - END - - IDD_GB_PRINTER, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 171 - TOPMARGIN, 7 - BOTTOMMARGIN, 202 - END - - IDD_MOTION_CONFIG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 227 - TOPMARGIN, 7 - BOTTOMMARGIN, 100 - END - - IDD_LANG_SELECT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 61 - END - - IDD_CODE_SELECT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 309 - TOPMARGIN, 7 - BOTTOMMARGIN, 228 - END - - IDD_MAP_VIEW, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 315 - TOPMARGIN, 7 - BOTTOMMARGIN, 231 - END - - IDD_PALETTE_VIEW, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 309 - TOPMARGIN, 7 - BOTTOMMARGIN, 259 - END - - IDD_MEM_VIEWER, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 373 - TOPMARGIN, 7 - BOTTOMMARGIN, 171 - END - - IDD_OAM_VIEW, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 227 - TOPMARGIN, 7 - BOTTOMMARGIN, 178 - END - - IDD_ACCEL_EDITOR, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 392 - TOPMARGIN, 7 - BOTTOMMARGIN, 114 - END - - IDD_TILE_VIEWER, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 319 - TOPMARGIN, 7 - BOTTOMMARGIN, 259 - END - - IDD_GB_COLORS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 162 - TOPMARGIN, 7 - BOTTOMMARGIN, 114 - END - - IDD_DISASSEMBLE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 396 - TOPMARGIN, 7 - BOTTOMMARGIN, 218 - END - - IDD_GDB_PORT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 44 - END - - IDD_GDB_WAITING, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 37 - END - - IDD_LOGGING, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 359 - TOPMARGIN, 7 - BOTTOMMARGIN, 211 - END - - IDD_EXPORT_SPS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 241 - TOPMARGIN, 7 - BOTTOMMARGIN, 141 - END - - IDD_ADDR_SIZE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 60 - END - - IDD_THROTTLE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 119 - TOPMARGIN, 7 - BOTTOMMARGIN, 53 - END - - IDD_GB_DISASSEMBLE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 337 - TOPMARGIN, 7 - BOTTOMMARGIN, 218 - END - - IDD_GB_OAM_VIEW, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 227 - TOPMARGIN, 7 - BOTTOMMARGIN, 178 - END - - IDD_GB_TILE_VIEWER, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 319 - TOPMARGIN, 7 - BOTTOMMARGIN, 231 - END - - IDD_GB_MAP_VIEW, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 315 - TOPMARGIN, 7 - BOTTOMMARGIN, 231 - END - - IDD_GB_PALETTE_VIEW, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 189 - TOPMARGIN, 7 - BOTTOMMARGIN, 227 - END - - IDD_REWIND_INTERVAL, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 61 - END - - IDD_IO_VIEWER, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 262 - TOPMARGIN, 7 - BOTTOMMARGIN, 235 - END - - IDD_MAX_SCALE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 61 - END - - IDD_GAME_OVERRIDES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 261 - TOPMARGIN, 7 - BOTTOMMARGIN, 105 - END - - IDD_BIOS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 213 - TOPMARGIN, 7 - BOTTOMMARGIN, 119 - END - - IDD_FULLSCREEN, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 160 - TOPMARGIN, 7 - BOTTOMMARGIN, 89 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDR_MENU MENU -BEGIN - POPUP "&File" - BEGIN - MENUITEM "Open GB...", ID_FILE_OPENGAMEBOY - MENUITEM "Open GBC...", ID_FILE_OPEN_GBC - MENUITEM "Open GBA...", ID_FILE_OPEN - MENUITEM SEPARATOR - MENUITEM "Load...", ID_FILE_LOAD - MENUITEM "Save...", ID_FILE_SAVE - POPUP "Load Game" - BEGIN - MENUITEM "Most recent", ID_FILE_LOADGAME_MOSTRECENT - MENUITEM "Auto load most recent", ID_FILE_LOADGAME_AUTOLOADMOSTRECENT - MENUITEM SEPARATOR - MENUITEM "Slot #1", ID_FILE_LOADGAME_SLOT1 - MENUITEM "Slot #2", ID_FILE_LOADGAME_SLOT2 - MENUITEM "Slot #3", ID_FILE_LOADGAME_SLOT3 - MENUITEM "Slot #4", ID_FILE_LOADGAME_SLOT4 - MENUITEM "Slot #5", ID_FILE_LOADGAME_SLOT5 - MENUITEM "Slot #6", ID_FILE_LOADGAME_SLOT6 - MENUITEM "Slot #7", ID_FILE_LOADGAME_SLOT7 - MENUITEM "Slot #8", ID_FILE_LOADGAME_SLOT8 - MENUITEM "Slot #9", ID_FILE_LOADGAME_SLOT9 - MENUITEM "Slot #10", ID_FILE_LOADGAME_SLOT10 - END - POPUP "Save Game" - BEGIN - MENUITEM "Oldest slot", ID_FILE_SAVEGAME_OLDESTSLOT - MENUITEM SEPARATOR - MENUITEM "Slot #1", ID_FILE_SAVEGAME_SLOT1 - MENUITEM "Slot #2", ID_FILE_SAVEGAME_SLOT2 - MENUITEM "Slot #3", ID_FILE_SAVEGAME_SLOT3 - MENUITEM "Slot #4", ID_FILE_SAVEGAME_SLOT4 - MENUITEM "Slot #5", ID_FILE_SAVEGAME_SLOT5 - MENUITEM "Slot #6", ID_FILE_SAVEGAME_SLOT6 - MENUITEM "Slot #7", ID_FILE_SAVEGAME_SLOT7 - MENUITEM "Slot #8", ID_FILE_SAVEGAME_SLOT8 - MENUITEM "Slot #9", ID_FILE_SAVEGAME_SLOT9 - MENUITEM "Slot #10", ID_FILE_SAVEGAME_SLOT10 - END - MENUITEM SEPARATOR - MENUITEM "Pause", ID_FILE_PAUSE - MENUITEM "Reset", ID_FILE_RESET - MENUITEM SEPARATOR - POPUP "Recent" - BEGIN - MENUITEM "&Reset", ID_FILE_RECENT_RESET - MENUITEM "&Freeze", ID_FILE_RECENT_FREEZE - MENUITEM SEPARATOR - END - MENUITEM SEPARATOR - POPUP "Import" - BEGIN - MENUITEM "&Battery file...", ID_FILE_IMPORT_BATTERYFILE - MENUITEM "Gameshark &code file...", ID_FILE_IMPORT_GAMESHARKCODEFILE - MENUITEM "&Gameshark Snapshot...", ID_FILE_IMPORT_GAMESHARKSNAPSHOT - END - POPUP "Export" - BEGIN - MENUITEM "&Battery file...", ID_FILE_EXPORT_BATTERYFILE - MENUITEM "&Gameshark Snapshot...", ID_FILE_EXPORT_GAMESHARKSNAPSHOT - END - MENUITEM SEPARATOR - MENUITEM "Screen Capture...", ID_FILE_SCREENCAPTURE - MENUITEM "ROM Information...", ID_FILE_ROMINFORMATION - MENUITEM "Toggle Fullscreen", ID_FILE_TOGGLEMENU - MENUITEM SEPARATOR - MENUITEM "Close", ID_FILE_CLOSE - MENUITEM SEPARATOR - MENUITEM "Exit", ID_FILE_EXIT - END - POPUP "&Options" - BEGIN - POPUP "&Video" - BEGIN - POPUP "Render API" - BEGIN - MENUITEM "Direct&3D", ID_OPTIONS_VIDEO_RENDERMETHOD_DIRECT3D - MENUITEM " Filter: Nearest", ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DNOFILTER - MENUITEM " Filter: Bilinear", ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DBILINEAR - MENUITEM " Motion Blur", ID_RENDERAPI_D3DMOTIONBLUR - MENUITEM SEPARATOR - MENUITEM "&OpenGL", ID_OPTIONS_VIDEO_RENDERMETHOD_OPENGL - MENUITEM " Filter: Nearest", ID_OPTIONS_VIDEO_RENDEROPTIONS_GLNEAREST - MENUITEM " Filter: Bilinear", ID_OPTIONS_VIDEO_RENDEROPTIONS_GLBILINEAR - MENUITEM SEPARATOR - MENUITEM "&VSync", ID_OPTIONS_VIDEO_VSYNC - MENUITEM "Triple Buffering", ID_OPTIONS_VIDEO_TRIPLEBUFFERING - END - MENUITEM SEPARATOR - POPUP "Windowed" - BEGIN - MENUITEM "&1x Size", ID_OPTIONS_VIDEO_X1 - MENUITEM "&2x Size", ID_OPTIONS_VIDEO_X2 - MENUITEM "&3x Size", ID_OPTIONS_VIDEO_X3 - MENUITEM "&4x Size", ID_OPTIONS_VIDEO_X4 - END - POPUP "Fullscreen" - BEGIN - MENUITEM "&Custom...", ID_OPTIONS_VIDEO_FULLSCREEN - MENUITEM SEPARATOR - MENUITEM "320x240x16", ID_OPTIONS_VIDEO_FULLSCREEN320X240 - MENUITEM "640x480x16", ID_OPTIONS_VIDEO_FULLSCREEN640X480 - MENUITEM "800x600x16", ID_OPTIONS_VIDEO_FULLSCREEN800X600 - MENUITEM "1024x768x16", ID_OPTIONS_VIDEO_FULLSCREEN1024X768 - MENUITEM "1280x1024x16", ID_OPTIONS_VIDEO_FULLSCREEN1280X1024 - MENUITEM SEPARATOR - MENUITEM "&Max Scale...", ID_OPTIONS_VIDEO_FULLSCREENMAXSCALE - MENUITEM "Stretch to &fit", ID_OPTIONS_VIDEO_FULLSCREENSTRETCHTOFIT - END - MENUITEM SEPARATOR - MENUITEM "D&isable status messages", ID_OPTIONS_EMULATOR_DISABLESTATUSMESSAGES - END - POPUP "&Pixel Filter" - BEGIN - MENUITEM "&Disable Filters", ID_OPTIONS_FILTER_NORMAL - POPUP "&Magnification" - BEGIN - POPUP "&2X" - BEGIN - MENUITEM "&Simple 2x", ID_OPTIONS_FILTER16BIT_SIMPLE2X - MENUITEM SEPARATOR - MENUITEM "&Pixelate", ID_OPTIONS_FILTER16BIT_PIXELATEEXPERIMENTAL - MENUITEM "&TV Mode", ID_OPTIONS_FILTER_TVMODE - MENUITEM "Scan&lines", ID_OPTIONS_FILTER_SCANLINES - MENUITEM SEPARATOR - MENUITEM "&Bilinear", ID_OPTIONS_FILTER_BILINEAR - MENUITEM "B&ilinear Plus", ID_OPTIONS_FILTER_BILINEARPLUS - MENUITEM SEPARATOR - MENUITEM "AdvanceMAME Scale2x", ID_OPTIONS_FILTER16BIT_ADVANCEMAMESCALE2X - MENUITEM "&2xSaI", ID_OPTIONS_FILTER_2XSAI - MENUITEM "S&uper 2xSaI", ID_OPTIONS_FILTER_SUPER2XSAI - MENUITEM "Super &Eagle", ID_OPTIONS_FILTER_SUPEREAGLE - MENUITEM "&LQ2x", ID_OPTIONS_FILTER_LQ2X - MENUITEM "&HQ2x", ID_OPTIONS_FILTER_HQ2X - END - POPUP "&3X" - BEGIN - MENUITEM "&Simple 3x", ID_OPTIONS_FILTER_SIMPLE3X - MENUITEM SEPARATOR - MENUITEM "&HQ3x", ID_OPTIONS_FILTER_HQ3X - END - POPUP "&4X" - BEGIN - MENUITEM "&Simple 4x", ID_OPTIONS_FILTER_SIMPLE4X - MENUITEM SEPARATOR - MENUITEM "&HQ4x", ID_OPTIONS_FILTER_HQ4X - END - END - MENUITEM SEPARATOR - MENUITEM "&Use Filter Plugin", ID_OPTIONS_FILTER_PLUGIN - MENUITEM "Select Filter &Plugin ...", ID_OPTIONS_SELECT_PLUGIN - MENUITEM SEPARATOR - POPUP "&Interframe Blending" - BEGIN - MENUITEM "&None", ID_OPTIONS_FILTER_INTERFRAMEBLENDING_NONE - MENUITEM "&Motion Blur", ID_OPTIONS_FILTER_INTERFRAMEBLENDING_MOTIONBLUR - MENUITEM "&Smart", ID_OPTIONS_FILTER_INTERFRAMEBLENDING_SMART - END - MENUITEM SEPARATOR - MENUITEM "Disable &MMX", ID_OPTIONS_FILTER_DISABLEMMX - END - POPUP "&Audio" - BEGIN - POPUP "Output API" - BEGIN - MENUITEM "DirectSound", ID_OUTPUTAPI_DIRECTSOUND - MENUITEM SEPARATOR - MENUITEM "OpenAL", ID_OUTPUTAPI_OPENAL - MENUITEM " Configuration...", ID_OUTPUTAPI_OALCONFIGURATION - MENUITEM SEPARATOR - MENUITEM "&Sync game to audio", ID_OPTIONS_EMULATOR_SYNCHRONIZE - END - MENUITEM SEPARATOR - MENUITEM "&On", ID_OPTIONS_SOUND_ON - MENUITEM "O&ff", ID_OPTIONS_SOUND_OFF - MENUITEM SEPARATOR - POPUP "&Volume" - BEGIN - MENUITEM "&Mute", ID_OPTIONS_SOUND_MUTE - MENUITEM SEPARATOR - MENUITEM "2&5%", ID_OPTIONS_SOUND_VOLUME_25X - MENUITEM "5&0%", ID_OPTIONS_SOUND_VOLUME_5X - MENUITEM "&100%", ID_OPTIONS_SOUND_VOLUME_1X - MENUITEM "&200%", ID_OPTIONS_SOUND_VOLUME_2X - MENUITEM "&300%", ID_OPTIONS_SOUND_VOLUME_3X - MENUITEM "&400%", ID_OPTIONS_SOUND_VOLUME_4X - END - POPUP "Sampling Rate" - BEGIN - MENUITEM "&11025 Hz", ID_OPTIONS_SOUND_11KHZ - MENUITEM "&22050 Hz", ID_OPTIONS_SOUND_22KHZ - MENUITEM "&44100 Hz", ID_OPTIONS_SOUND_44KHZ - END - POPUP "PCM interpolation" - BEGIN - MENUITEM "On", ID_OPTIONS_SOUND_PCMINTERPOLATION_LINEAR - MENUITEM "Off", ID_OPTIONS_SOUND_PCMINTERPOLATION_NONE - END - MENUITEM SEPARATOR - MENUITEM "&Echo", ID_OPTIONS_SOUND_ECHO - MENUITEM SEPARATOR - POPUP "Sound Channels" - BEGIN - MENUITEM "Channel &1", ID_OPTIONS_SOUND_CHANNEL1, CHECKED - MENUITEM "Channel &2", ID_OPTIONS_SOUND_CHANNEL2, CHECKED - MENUITEM "Channel &3", ID_OPTIONS_SOUND_CHANNEL3, CHECKED - MENUITEM "Channel &4", ID_OPTIONS_SOUND_CHANNEL4, CHECKED - MENUITEM "Direct Sound &A", ID_OPTIONS_SOUND_DIRECTSOUNDA, CHECKED - MENUITEM "Direct Sound &B", ID_OPTIONS_SOUND_DIRECTSOUNDB, CHECKED - END - END - POPUP "&Input" - BEGIN - POPUP "&Set" - BEGIN - MENUITEM "Config &1...", ID_OPTIONS_JOYPAD_CONFIGURE_1 - MENUITEM "Config &2...", ID_OPTIONS_JOYPAD_CONFIGURE_2 - MENUITEM "Config &3...", ID_OPTIONS_JOYPAD_CONFIGURE_3 - MENUITEM "Config &4...", ID_OPTIONS_JOYPAD_CONFIGURE_4 - MENUITEM SEPARATOR - MENUITEM "&Motion...", ID_OPTIONS_JOYPAD_MOTIONCONFIGURE - END - POPUP "&Use" - BEGIN - MENUITEM "Config &1", ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_1 - MENUITEM "Config &2", ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_2 - MENUITEM "Config &3", ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_3 - MENUITEM "Config &4", ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_4 - END - MENUITEM SEPARATOR - POPUP "&Autofire" - BEGIN - MENUITEM "&A", ID_OPTIONS_JOYPAD_AUTOFIRE_A - MENUITEM "&B", ID_OPTIONS_JOYPAD_AUTOFIRE_B - MENUITEM "&L", ID_OPTIONS_JOYPAD_AUTOFIRE_L - MENUITEM "&R", ID_OPTIONS_JOYPAD_AUTOFIRE_R - END - MENUITEM "Rewind interval...", ID_OPTIONS_EMULATOR_REWINDINTERVAL - END - POPUP "&Speed" - BEGIN - POPUP "&Throttle" - BEGIN - MENUITEM "25%", ID_OPTIONS_FRAMESKIP_THROTTLE_25 - MENUITEM "50%", ID_OPTIONS_FRAMESKIP_THROTTLE_50 - MENUITEM "100%", ID_OPTIONS_FRAMESKIP_THROTTLE_100 - MENUITEM "150%", ID_OPTIONS_FRAMESKIP_THROTTLE_150 - MENUITEM "200%", ID_OPTIONS_FRAMESKIP_THROTTLE_200 - MENUITEM "&Other...", ID_OPTIONS_FRAMESKIP_THROTTLE_OTHER - MENUITEM "No throttle", ID_OPTIONS_FRAMESKIP_THROTTLE_NOTHROTTLE - END - MENUITEM SEPARATOR - POPUP "&Frame Skip" - BEGIN - MENUITEM "&No frame skip", ID_OPTIONS_VIDEO_FRAMESKIP_0 - MENUITEM "&1 frame", ID_OPTIONS_VIDEO_FRAMESKIP_1 - MENUITEM "&2 frames", ID_OPTIONS_VIDEO_FRAMESKIP_2 - MENUITEM "&3 frames", ID_OPTIONS_VIDEO_FRAMESKIP_3 - MENUITEM "&4 frames", ID_OPTIONS_VIDEO_FRAMESKIP_4 - MENUITEM "&5 frames", ID_OPTIONS_VIDEO_FRAMESKIP_5 - MENUITEM "&6 frames", ID_OPTIONS_VIDEO_FRAMESKIP_6 - MENUITEM "&7 frames", ID_OPTIONS_VIDEO_FRAMESKIP_7 - MENUITEM "&8 frames", ID_OPTIONS_VIDEO_FRAMESKIP_8 - MENUITEM "&9 frames", ID_OPTIONS_VIDEO_FRAMESKIP_9 - END - MENUITEM "Turbo mode", ID_OPTIONS_EMULATOR_SPEEDUPTOGGLE - END - MENUITEM SEPARATOR - POPUP "&Emulator" - BEGIN - MENUITEM "&Associate...", ID_OPTIONS_EMULATOR_ASSOCIATE - MENUITEM "&Directories...", ID_OPTIONS_EMULATOR_DIRECTORIES - MENUITEM "BIOS Files...", ID_EMULATOR_BIOSFILES - POPUP "&Priority" - BEGIN - MENUITEM "&Highest", ID_OPTIONS_PRIORITY_HIGHEST - MENUITEM "&Above Normal", ID_OPTIONS_PRIORITY_ABOVENORMAL - MENUITEM "&Normal", ID_OPTIONS_PRIORITY_NORMAL - MENUITEM "&Below Normal", ID_OPTIONS_PRIORITY_BELOWNORMAL - END - MENUITEM "&Remove intros (GBA)", ID_OPTIONS_EMULATOR_REMOVEINTROSGBA - MENUITEM "Automatic IPS patching", ID_OPTIONS_EMULATOR_AUTOMATICALLYIPSPATCH - MENUITEM "Pause when inactive", ID_OPTIONS_EMULATOR_PAUSEWHENINACTIVE - MENUITEM "AGB Print", ID_OPTIONS_EMULATOR_AGBPRINT - MENUITEM "Real Time Clock", ID_OPTIONS_EMULATOR_REALTIMECLOCK - MENUITEM "&Game Overrides...", ID_OPTIONS_EMULATOR_GAMEOVERRIDES - POPUP "Show speed" - BEGIN - MENUITEM "None", ID_OPTIONS_EMULATOR_SHOWSPEED_NONE - MENUITEM "Percentage", ID_OPTIONS_EMULATOR_SHOWSPEED_PERCENTAGE - MENUITEM "Detailed", ID_OPTIONS_EMULATOR_SHOWSPEED_DETAILED - MENUITEM SEPARATOR - MENUITEM "Transparent", ID_OPTIONS_EMULATOR_SHOWSPEED_TRANSPARENT - END - POPUP "Save Type" - BEGIN - MENUITEM "&Automatic", ID_OPTIONS_EMULATOR_SAVETYPE_AUTOMATIC - MENUITEM "EEPROM", ID_OPTIONS_EMULATOR_SAVETYPE_EEPROM - MENUITEM "SRAM", ID_OPTIONS_EMULATOR_SAVETYPE_SRAM - MENUITEM "Flash", ID_OPTIONS_EMULATOR_SAVETYPE_FLASH - MENUITEM "EEPROM+Sensor", ID_OPTIONS_EMULATOR_SAVETYPE_EEPROMSENSOR - MENUITEM "None", ID_OPTIONS_EMULATOR_SAVETYPE_NONE - MENUITEM SEPARATOR - MENUITEM "Flash 64 KB", ID_OPTIONS_EMULATOR_SAVETYPE_FLASH512K - MENUITEM "Flash 128 KB", ID_OPTIONS_EMULATOR_SAVETYPE_FLASH1M - END - POPUP "Screenshot &Format" - BEGIN - MENUITEM "&PNG", ID_OPTIONS_EMULATOR_PNGFORMAT - MENUITEM "&BMP", ID_OPTIONS_EMULATOR_BMPFORMAT - END - MENUITEM SEPARATOR - POPUP "UI &Language" - BEGIN - MENUITEM "&System", ID_OPTIONS_LANGUAGE_SYSTEM - MENUITEM "&English", ID_OPTIONS_LANGUAGE_ENGLISH - MENUITEM "&Other...", ID_OPTIONS_LANGUAGE_OTHER - END - END - POPUP "&Gameboy" - BEGIN - MENUITEM "&Border", ID_OPTIONS_GAMEBOY_BORDER - MENUITEM "&Printer", ID_OPTIONS_GAMEBOY_PRINTER - MENUITEM "Border Automatic", ID_OPTIONS_GAMEBOY_BORDERAUTOMATIC - MENUITEM SEPARATOR - MENUITEM "&Automatic", ID_OPTIONS_GAMEBOY_AUTOMATIC - MENUITEM "&GBA", ID_OPTIONS_GAMEBOY_GBA - MENUITEM "&CGB/GBC", ID_OPTIONS_GAMEBOY_CGB - MENUITEM "&SGB", ID_OPTIONS_GAMEBOY_SGB - MENUITEM "SGB&2", ID_OPTIONS_GAMEBOY_SGB2 - MENUITEM "G&B", ID_OPTIONS_GAMEBOY_GB - MENUITEM SEPARATOR - MENUITEM "&Real Colors", ID_OPTIONS_GAMEBOY_REALCOLORS - MENUITEM "G&ameboy Colors", ID_OPTIONS_GAMEBOY_GAMEBOYCOLORS - MENUITEM "LCD colors", ID_OPTIONS_FILTER_LCDCOLORS - MENUITEM SEPARATOR - MENUITEM "&Colors...", ID_OPTIONS_GAMEBOY_COLORS - END - POPUP "&Link", GRAYED - BEGIN - MENUITEM "Enable GBA Linking", ID_OPTIONS_LINK_ENABLE - MENUITEM "&Wireless Adapter", ID_OPTIONS_LINK_WIRELESSADAPTER - MENUITEM "&Log", ID_OPTIONS_LINK_LOG - MENUITEM "&Options...", ID_OPTIONS_LINK_OPTIONS - END - END - POPUP "&Cheats" - BEGIN - MENUITEM "&Search for cheats...", ID_CHEATS_SEARCHFORCHEATS - MENUITEM "&Cheat list...", ID_CHEATS_CHEATLIST - MENUITEM SEPARATOR - MENUITEM "&Automatic save/load cheats", ID_CHEATS_AUTOMATICSAVELOADCHEATS - MENUITEM "Disable cheats", ID_CHEATS_DISABLECHEATS - MENUITEM "&Load cheat list...", ID_CHEATS_LOADCHEATLIST - MENUITEM "Sa&ve cheat list...", ID_CHEATS_SAVECHEATLIST - END - POPUP "&Tools" - BEGIN - MENUITEM "Disassemble...", ID_TOOLS_DISASSEMBLE - MENUITEM "Logging...", ID_TOOLS_LOGGING - MENUITEM "&IO Viewer...", ID_TOOLS_IOVIEWER - MENUITEM "&Map Viewer...", ID_TOOLS_MAPVIEW - MENUITEM "&Memory viewer...", ID_TOOLS_MEMORYVIEWER - MENUITEM "OAM Viewer...", ID_TOOLS_OAMVIEWER - MENUITEM "&Palette Viewer...", ID_TOOLS_PALETTEVIEW - MENUITEM "Tile Viewer...", ID_TOOLS_TILEVIEWER - MENUITEM SEPARATOR - MENUITEM "&Next frame", ID_DEBUG_NEXTFRAME - POPUP "GDB" - BEGIN - MENUITEM "Wait for connection...", ID_TOOLS_DEBUG_GDB - MENUITEM "Load and wait...", ID_TOOLS_DEBUG_LOADANDWAIT - MENUITEM "Break into GDB", ID_TOOLS_DEBUG_BREAK - MENUITEM "Disconnect", ID_TOOLS_DEBUG_DISCONNECT - END - MENUITEM SEPARATOR - POPUP "Record" - BEGIN - MENUITEM "Start sound recording...", ID_OPTIONS_SOUND_STARTRECORDING - MENUITEM "Stop sound recording", ID_OPTIONS_SOUND_STOPRECORDING - MENUITEM "Start AVI recording...", ID_TOOLS_RECORD_STARTAVIRECORDING - MENUITEM "Stop AVI recording", ID_TOOLS_RECORD_STOPAVIRECORDING - MENUITEM "Start movie recording...", ID_TOOLS_RECORD_STARTMOVIERECORDING - MENUITEM "Stop movie recording", ID_TOOLS_RECORD_STOPMOVIERECORDING - END - POPUP "Play" - BEGIN - MENUITEM "Start playing movie...", ID_TOOLS_PLAY_STARTMOVIEPLAYING - MENUITEM "Stop playing movie", ID_TOOLS_PLAY_STOPMOVIEPLAYING - END - MENUITEM SEPARATOR - MENUITEM "Rewind", ID_TOOLS_REWIND - MENUITEM "Customize...", ID_TOOLS_CUSTOMIZE - END - POPUP "&Help" - BEGIN - MENUITEM "VBA-M Help", ID_HELP_FAQ - MENUITEM "VBA-M Support Forum", ID_HELP_BUGREPORT - MENUITEM "License...", ID_HELP_GNUPUBLICLICENSE - MENUITEM SEPARATOR - MENUITEM "&About VBA-M...", ID_HELP_ABOUT - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Accelerator -// - -IDR_ACCELERATOR ACCELERATORS -BEGIN - "C", ID_CHEATS_SEARCHFORCHEATS, VIRTKEY, CONTROL, NOINVERT - "N", ID_DEBUG_NEXTFRAME, VIRTKEY, CONTROL, NOINVERT - "X", ID_FILE_EXIT, VIRTKEY, CONTROL, NOINVERT - "L", ID_FILE_LOAD, VIRTKEY, CONTROL, NOINVERT - VK_F1, ID_FILE_LOADGAME_SLOT1, VIRTKEY, NOINVERT - VK_F10, ID_FILE_LOADGAME_SLOT10, VIRTKEY, NOINVERT - VK_F2, ID_FILE_LOADGAME_SLOT2, VIRTKEY, NOINVERT - VK_F3, ID_FILE_LOADGAME_SLOT3, VIRTKEY, NOINVERT - VK_F4, ID_FILE_LOADGAME_SLOT4, VIRTKEY, NOINVERT - VK_F5, ID_FILE_LOADGAME_SLOT5, VIRTKEY, NOINVERT - VK_F6, ID_FILE_LOADGAME_SLOT6, VIRTKEY, NOINVERT - VK_F7, ID_FILE_LOADGAME_SLOT7, VIRTKEY, NOINVERT - VK_F8, ID_FILE_LOADGAME_SLOT8, VIRTKEY, NOINVERT - VK_F9, ID_FILE_LOADGAME_SLOT9, VIRTKEY, NOINVERT - VK_F1, ID_FILE_MRU_FILE1, VIRTKEY, CONTROL, NOINVERT - VK_F10, ID_FILE_MRU_FILE10, VIRTKEY, CONTROL, NOINVERT - VK_F2, ID_FILE_MRU_FILE2, VIRTKEY, CONTROL, NOINVERT - VK_F3, ID_FILE_MRU_FILE3, VIRTKEY, CONTROL, NOINVERT - VK_F4, ID_FILE_MRU_FILE4, VIRTKEY, CONTROL, NOINVERT - VK_F5, ID_FILE_MRU_FILE5, VIRTKEY, CONTROL, NOINVERT - VK_F6, ID_FILE_MRU_FILE6, VIRTKEY, CONTROL, NOINVERT - VK_F7, ID_FILE_MRU_FILE7, VIRTKEY, CONTROL, NOINVERT - VK_F8, ID_FILE_MRU_FILE8, VIRTKEY, CONTROL, NOINVERT - VK_F9, ID_FILE_MRU_FILE9, VIRTKEY, CONTROL, NOINVERT - "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT - "P", ID_FILE_PAUSE, VIRTKEY, CONTROL, NOINVERT - VK_PAUSE, ID_FILE_PAUSE, VIRTKEY, NOINVERT - "R", ID_FILE_RESET, VIRTKEY, CONTROL, NOINVERT - "S", ID_FILE_SAVE, VIRTKEY, CONTROL, NOINVERT - VK_F1, ID_FILE_SAVEGAME_SLOT1, VIRTKEY, SHIFT, NOINVERT - VK_F10, ID_FILE_SAVEGAME_SLOT10, VIRTKEY, SHIFT, NOINVERT - VK_F2, ID_FILE_SAVEGAME_SLOT2, VIRTKEY, SHIFT, NOINVERT - VK_F3, ID_FILE_SAVEGAME_SLOT3, VIRTKEY, SHIFT, NOINVERT - VK_F4, ID_FILE_SAVEGAME_SLOT4, VIRTKEY, SHIFT, NOINVERT - VK_F5, ID_FILE_SAVEGAME_SLOT5, VIRTKEY, SHIFT, NOINVERT - VK_F6, ID_FILE_SAVEGAME_SLOT6, VIRTKEY, SHIFT, NOINVERT - VK_F7, ID_FILE_SAVEGAME_SLOT7, VIRTKEY, SHIFT, NOINVERT - VK_F8, ID_FILE_SAVEGAME_SLOT8, VIRTKEY, SHIFT, NOINVERT - VK_F9, ID_FILE_SAVEGAME_SLOT9, VIRTKEY, SHIFT, NOINVERT - VK_ESCAPE, ID_FILE_TOGGLEMENU, VIRTKEY, NOINVERT - "1", ID_OPTIONS_JOYPAD_AUTOFIRE_A, VIRTKEY, ALT, NOINVERT - "2", ID_OPTIONS_JOYPAD_AUTOFIRE_B, VIRTKEY, ALT, NOINVERT - "3", ID_OPTIONS_JOYPAD_AUTOFIRE_L, VIRTKEY, ALT, NOINVERT - "4", ID_OPTIONS_JOYPAD_AUTOFIRE_R, VIRTKEY, ALT, NOINVERT - "1", ID_OPTIONS_VIDEO_LAYERS_BG0, VIRTKEY, CONTROL, NOINVERT - "2", ID_OPTIONS_VIDEO_LAYERS_BG1, VIRTKEY, CONTROL, NOINVERT - "3", ID_OPTIONS_VIDEO_LAYERS_BG2, VIRTKEY, CONTROL, NOINVERT - "4", ID_OPTIONS_VIDEO_LAYERS_BG3, VIRTKEY, CONTROL, NOINVERT - "5", ID_OPTIONS_VIDEO_LAYERS_OBJ, VIRTKEY, CONTROL, NOINVERT - "8", ID_OPTIONS_VIDEO_LAYERS_OBJWIN, VIRTKEY, CONTROL, NOINVERT - "6", ID_OPTIONS_VIDEO_LAYERS_WIN0, VIRTKEY, CONTROL, NOINVERT - "7", ID_OPTIONS_VIDEO_LAYERS_WIN1, VIRTKEY, CONTROL, NOINVERT - "B", ID_TOOLS_REWIND, VIRTKEY, CONTROL, NOINVERT -END - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_UNSUPPORTED_VBA_SGM "Unsupported VisualBoyAdvance save game version %d" - IDS_CANNOT_LOAD_SGM "Cannot load save game for %s" - IDS_SAVE_GAME_NOT_USING_BIOS "Save game is not using the BIOS file" - IDS_SAVE_GAME_USING_BIOS "Save game is using the BIOS file" - IDS_UNSUPPORTED_SAVE_TYPE "Unsupported save type %d" - IDS_CANNOT_OPEN_FILE "Cannot open file %s" - IDS_BAD_ZIP_FILE "Bad ZIP file %s" - IDS_NO_IMAGE_ON_ZIP "No image found on ZIP file %s" - IDS_ERROR_OPENING_IMAGE "Error opening image %s" - IDS_ERROR_READING_IMAGE "Error reading image %s" - IDS_UNSUPPORTED_BIOS_FUNCTION - "Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour." - IDS_INVALID_BIOS_FILE_SIZE "Invalid BIOS file size" - IDS_INVALID_CHEAT_CODE "Invalid cheat code '%s'. Supported formats are:\nXXXXXXXX:YY, XXXXXXXX:YYYY, XXXXXXXX:YYYYYYYY." - IDS_UNKNOWN_ARM_OPCDOE "Unimplemented opcode %08x from %08x" - IDS_UNKNOWN_THUMB_OPCODE "Unknown opcode %04x from %08x" -END - -STRINGTABLE -BEGIN - IDS_ERROR_CREATING_FILE "Error creating file %s" - IDS_FAILED_TO_READ_SGM "Battery file's size incompatible with the ROM settings %s (%d).\nWarning : save of the battery file is now disabled !" - IDS_FAILED_TO_READ_RTC "Failed to read RTC from save game %s (continuing)" - IDS_UNSUPPORTED_VB_SGM "Unsupported VisualBoy save game version %d" - IDS_CANNOT_LOAD_SGM_FOR "Cannot load save game for %s. Playing %s" - IDS_ERROR_OPENING_IMAGE_FROM "Error opening image %s from zip file %s" - IDS_ERROR_READING_IMAGE_FROM "Error reading image %s from zip file %s" - IDS_UNSUPPORTED_ROM_SIZE "Unsupported rom size %02x" - IDS_UNSUPPORTED_RAM_SIZE "Unsupported ram size %02x" - IDS_UNKNOWN_CARTRIDGE_TYPE "Unknown cartridge type %02x" - IDS_MAXIMUM_NUMBER_OF_CHEATS "Maximum number of cheats reached." - IDS_INVALID_GAMESHARK_CODE "Invalid GameShark code: %s" - IDS_INVALID_GAMEGENIE_CODE "Invalid GameGenie code: %s" - IDS_INVALID_CHEAT_TO_REMOVE "Invalid cheat to remove %d" - IDS_INVALID_CHEAT_CODE_ADDRESS "Invalid cheat code address: %08x" - IDS_UNSUPPORTED_CHEAT_LIST_VERSION "Unsupported cheat list version %d" -END - -STRINGTABLE -BEGIN - IDS_DIRECTX_7_REQUIRED "DirectX 7.0 or greater is required to run.\nDownload at http://www.microsoft.com/directx.\n\nError found at: %s" - IDS_DISABLING_VIDEO_MEMORY "Disabling Use Video Memory setting" - IDS_SETTING_WILL_BE_EFFECTIVE - "Setting will be effective the next time you start the emulator" - IDS_DISABLING_EMULATION_ONLY "Disabling Emulation Only setting" - IDS_FAILED_TO_OPEN_FILE "Failed to open file %s" - IDS_FAILED_TO_READ_ZIP_DIR "Failed to read zip directory for file %s" - IDS_UNSUPPORTED_FILE_TYPE "Unsupported file type: %s" - IDS_CANNOT_CREATE_DIRECTSOUND "Cannot create DirectSound %08x" - IDS_CANNOT_SETCOOPERATIVELEVEL "Cannot SetCooperativeLevel %08x" - IDS_CANNOT_CREATESOUNDBUFFER "Cannot CreateSoundBuffer %08x" - IDS_CANNOT_SETFORMAT_PRIMARY "Cannot SetFormat for primary %08x" - IDS_CANNOT_CREATESOUNDBUFFER_SEC "Cannot CreateSoundBuffer secondary %08x" - IDS_CANNOT_PLAY_PRIMARY "Cannot Play primary %08x" - IDS_SEARCH_PRODUCED_TOO_MANY - "Search produced %d results. Please refine better" - IDS_NUMBER_CANNOT_BE_EMPTY "Number cannot be empty" - IDS_INVALID_ADDRESS "Invalid address: %08x" -END - -STRINGTABLE -BEGIN - IDS_MISALIGNED_HALFWORD "Misaligned half-word address: %08x" - IDS_MISALIGNED_WORD "Misaligned word address: %08x" - IDS_VALUE_CANNOT_BE_EMPTY "Value cannot be empty" - IDS_ERROR_ON_STARTDOC "Error on StartDoc" - IDS_ERROR_ON_STARTPAGE "Error on StartPage" - IDS_ERROR_PRINTING_ON_STRETCH "Error printing on StretchDIBits" - IDS_ERROR_ON_ENDPAGE "Error on EndPage" - IDS_ERROR_ON_ENDDOC "Error on EndDoc" - IDS_ERROR "Error" - IDS_JOY_LEFT "Joy %d Left" - IDS_JOY_RIGHT "Joy %d Right" - IDS_JOY_UP "Joy %d Up" - IDS_JOY_DOWN "Joy %d Down" - IDS_JOY_BUTTON "Joy %d %s" - IDS_SELECT_ROM_DIR "Select ROM directory:" - IDS_SELECT_BATTERY_DIR "Select Battery directory:" -END - -STRINGTABLE -BEGIN - IDS_SELECT_SAVE_DIR "Select Save Directory:" - IDS_SELECT_CAPTURE_DIR "Select Capture directory:" - IDS_RESET "Reset" - IDS_AUTOFIRE_A_DISABLED "autofire A disabled" - IDS_AUTOFIRE_A "autofire A" - IDS_AUTOFIRE_B_DISABLED "autofire B disabled" - IDS_AUTOFIRE_B "autofire B" - IDS_AUTOFIRE_L_DISABLED "autofire L disabled" - IDS_AUTOFIRE_L "autofire L" - IDS_AUTOFIRE_R_DISABLED "autofire R disabled" - IDS_AUTOFIRE_R "autofire R" - IDS_SELECT_ROM "Select ROM" - IDS_SELECT_SAVE_GAME_NAME "Select save game name" - IDS_LOADED_STATE "Loaded state" - IDS_LOADED_STATE_N "Loaded state %d" -END - -STRINGTABLE -BEGIN - IDS_WROTE_STATE "Wrote state" - IDS_WROTE_STATE_N "Wrote state %d" - IDS_LOADED_BATTERY "Loaded battery" - IDS_SELECT_CAPTURE_NAME "Select screen capture name" - IDS_SCREEN_CAPTURE "Screen capture" - IDS_ADDRESS "Address" - IDS_OLD_VALUE "Old Value" - IDS_NEW_VALUE "New Value" - IDS_ADD_CHEAT_CODE "Add cheat code" - IDS_CODE "Code" - IDS_DESCRIPTION "Description" - IDS_STATUS "Status" - IDS_ADD_GG_CODE "Add GameGenie code" - IDS_ADD_GS_CODE "Add GameShark code" - IDS_POCKET_PRINTER "Pocket Printer" - IDS_UNKNOWN "Unknown" -END - -STRINGTABLE -BEGIN - IDS_NONE "None" - IDS_FAILED_TO_LOAD_LIBRARY "Failed to load library %s" - IDS_FAILED_TO_GET_LOCINFO "Failed to get locale information" - IDS_SELECT_CHEAT_LIST_NAME "Select cheat list name" - IDS_FILTER_ROM "Game Boy Advance ROMs_*.GBA;*.AGB;*.BIN;*.ELF;*.MB;*.ZIP;*.7Z;*.Z;*.GZ__" - IDS_FILTER_SGM "VisualBoyAdvance Save Game_*.SGM__" - IDS_FILTER_CHEAT_LIST "VisualBoyAdvance Cheat List_*.CLT__" - IDS_FILTER_PNG "PNG Image_*.PNG_BMP Image_*.BMP__" - IDS_LOADED_CHEATS "Loaded cheats" - IDS_ERROR_DISP_COLOR "Unsupported display setting for color depth: %d bits. \nWindows desktop must be in either 16-bit, 24-bit or 32-bit mode for this program to work in window mode." - IDS_ADD_GSA_CODE "Add GameSharkAdvance code" - IDS_FILTER_SPS "Gameshark Snapshot_*.SPS__" - IDS_SELECT_SNAPSHOT_FILE "Select snapshot file" - IDS_FILTER_SAV "Battery file_*.SAV_Flash save_*.DAT__" - IDS_SELECT_BATTERY_FILE "Select battery file" -END - -STRINGTABLE -BEGIN - IDS_UNSUPPORTED_CHEAT_LIST_TYPE "Unsupported cheat list type %d" - IDS_INVALID_GSA_CODE "Invalid GSA code. Format is XXXXXXXXYYYYYYYY." - IDS_CANNOT_IMPORT_SNAPSHOT_FOR - "Cannot import snapshot for %s. Current game is %s" - IDS_UNSUPPORTED_SNAPSHOT_FILE "Unsupported snapshot file %s" - IDS_UNSUPPORTED_ARM_MODE "Unsupported ARM mode %02x" - IDS_UNSUPPORTED_CODE_FILE "Unsupported code file %s" - IDS_GSA_CODE_WARNING "Warning: cheats are for game %s. Current game is %s.\nCodes may not work correctly." - IDS_INVALID_CBA_CODE "Invalid CBA code. Format is XXXXXXXX YYYY." - IDS_CBA_CODE_WARNING "Warning: Codes seem to be for a different game.\nCodes may not work correctly." - IDS_OUT_OF_MEMORY "Failed to allocate memory for %s" -END - -STRINGTABLE -BEGIN - IDS_FILTER_GBS "Gameboy Snapshot_*.GBS__" - IDS_FILTER_GCF "Gameshark Code File_*.GCF__" - IDS_SELECT_CODE_FILE "Select code file" - IDS_SAVE_WILL_BE_LOST "Importing a snapshot file will erase any saved games. Do you want to continue?" - IDS_CONFIRM_ACTION "Please confirm action" - IDS_CODES_WILL_BE_LOST "Importing a code file will erase any entered codes. Do you want to continue?" - IDS_FILTER_SPC "Gameshark Code File_*.SPC;*.XPC__" - IDS_ADD_CBA_CODE "Add CodeBreakerAdvance code" - IDS_FILTER_WAV "Wave file_*.WAV__" - IDS_SELECT_WAV_NAME "Select wave file name" - IDS_FILTER_GBROM "Game Boy ROMs_*.GB;*.SGB;*.ZIP;*.7Z;*.Z;*.GZ__" - IDS_FILTER_PAL "Windows Palette (*.PAL)_*.PAL_PaintShop Palette (*.PAL)_*.PAL_Adobe Color Table (*.ACT)_*.ACT__" - IDS_SELECT_PALETTE_NAME "Select palette name:" - IDS_SEARCH_PRODUCED_NO_RESULTS "Search produced no results." - IDS_ERROR_BINDING "Error binding socket. Port probably in use." - IDS_ERROR_LISTENING "Error listening on socket." -END - -STRINGTABLE -BEGIN - IDS_ERROR_CREATING_SOCKET "Error creating socket." - IDS_ACK_NOT_RECEIVED "ACK not received from GDB." - IDS_ERROR_NOT_GBA_IMAGE "Error: not a GBA image." - IDS_EEPROM_NOT_SUPPORTED "EEPROM saves cannot be exported." - IDS_FILTER_DUMP "Memory Dump_*.DMP__" - IDS_SELECT_DUMP_FILE "Select dump file name" - IDS_FILTER_AVI "AVI File_*.AVI__" - IDS_SELECT_AVI_NAME "Select AVI file name" - IDS_INVALID_THROTTLE_VALUE - "Invalid throttle value. Please enter a number between 5 and 1000." - IDS_FILTER_INI "Skin INI File_*.INI__" - IDS_SELECT_SKIN_FILE "Select the skin file name" - IDS_FILTER_VMV "VisualBoyAdvance Movie_*.VMV__" - IDS_SELECT_MOVIE_NAME "Select movie name" - IDS_BUG_REPORT "The bug report information is now available on the Windows Clipboard. Please paste it into any bug report made by email or on forums to help solve problems more easily." - IDS_UNSUPPORTED_MOVIE_VERSION "Unsupported movie version %d." - IDS_END_OF_MOVIE "end of movie" -END - -STRINGTABLE -BEGIN - IDS_INVALID_INTERVAL_VALUE - "Invalid rewind interval value. Please enter a number between 0 and 600 seconds." - IDS_REGISTRY "VisualBoyAdvance no longer uses the registry to store its settings. Your previous settings have been exported into the file: %s" - IDS_MOVIE_PLAY "Playing a movie will load a save state which may erase your previous battery saves. Please be sure to have a saved state if you don't want to loose any previous data." -END - -STRINGTABLE -BEGIN - IDS_OAL_NODEVICE "There are no sound devices present on this system." - IDS_OAL_NODLL "OpenAL32.dll could not be found on your system. Please install the runtime from http://openal.org" - IDS_AVI_CANNOT_CREATE_AVI "Cannot create AVI file." - IDS_AVI_CANNOT_CREATE_VIDEO - "Cannot create video stream in AVI file. Make sure the selected codec supports input in RGB24 color space!" - IDS_AVI_CANNOT_CREATE_AUDIO "Cannot create audio stream in AVI file." - IDS_AVI_CANNOT_WRITE_VIDEO "Cannot write video frame to AVI file." - IDS_AVI_CANNOT_WRITE_AUDIO "Cannot write audio frame to AVI file." - IDS_FILTER_GBCROM "Game Boy Color ROMs_*.GBC;*.CGB;*.ZIP;*.7Z;*.Z;*.GZ__" -END - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// German (Germany) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // German (Germany) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,8,0,0 + PRODUCTVERSION 1,8,0,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "VBA-M comes with NO WARRANTY. Use it at your own risk." + VALUE "CompanyName", "http://vba-m.ngemu.com/" + VALUE "FileDescription", "GB & GBA emulator for Windows" + VALUE "FileVersion", "1, 8, 0, 0" + VALUE "InternalName", "VBA-M" + VALUE "LegalCopyright", "Copyright © 2008 VBA-M development team" + VALUE "OriginalFilename", "VisualBoyAdvance.exe" + VALUE "ProductName", "VBA-M - A VisualBoyAdvance Fork" + VALUE "ProductVersion", "1, 8, 0, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MAINICON ICON "VBA-M.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OAL_CONFIG DIALOGEX 0, 0, 167, 114 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "OpenAL configuration" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,66,96,48,12 + PUSHBUTTON "Cancel",IDCANCEL,114,96,48,12 + COMBOBOX IDC_DEVICE,6,18,156,36,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Select device:",IDC_STATIC,6,6,156,8 + GROUPBOX "Sound Buffer Count",IDC_STATIC,6,36,156,54 + CONTROL "",IDC_SLIDER_BUFFERCOUNT,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | WS_TABSTOP,12,48,144,24 + CTEXT "bufferInfo",IDC_BUFFERINFO,12,72,144,12,0,WS_EX_DLGMODALFRAME +END + +IDD_SELECT_PLUGIN DIALOG 0, 0, 201, 120 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Select Filter Plugin" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,39,89,50,14 + PUSHBUTTON "Cancel",IDCANCEL,103,89,50,14 + COMBOBOX IDC_COMBO_PLUGIN,20,28,163,58,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Filter Plugin:",IDC_STATIC,18,15,66,8 +END + +7533 DIALOGEX 0, 0, 254, 203 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Link Options" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "Tab1",IDC_TAB1,"SysTabControl32",0x0,9,7,240,162 + PUSHBUTTON "OK",ID_OK,57,180,60,15 + PUSHBUTTON "Cancel",ID_CANCEL,140,180,57,15 +END + +7532 DIALOGEX 0, 0, 184, 79 +STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LTEXT "Link timeout (in milliseconds)",IDC_STATIC,17,12,92,16 + EDITTEXT IDC_LINKTIMEOUT,116,10,53,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Single Computer",IDC_LINK_SINGLE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,17,27,71,16 + CONTROL "Network",IDC_LINK_LAN,"Button",BS_AUTORADIOBUTTON,17,43,70,16 +END + +7534 DIALOG 0, 0, 210, 113 +STYLE DS_SETFONT | WS_CHILD +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "2",IDC_LINK2P,"Button",BS_AUTORADIOBUTTON | WS_GROUP,46,16,21,13 + CONTROL "3",IDC_LINK3P,"Button",BS_AUTORADIOBUTTON,94,16,21,13 + CONTROL "4",IDC_LINK4P,"Button",BS_AUTORADIOBUTTON,142,16,21,13 + CONTROL "TCP/IP",IDC_LINKTCP,"Button",BS_AUTORADIOBUTTON | WS_GROUP,54,47,42,14 + CONTROL "UDP",IDC_LINKUDP,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,121,47,33,14 + PUSHBUTTON "Start!",IDC_SERVERSTART,79,89,50,17 + LTEXT "Select number of players:",IDC_STATIC,60,7,89,10 + LTEXT "Select protocol:",IDC_STATIC,78,33,53,11 + CONTROL "Speed hacks",IDC_SSPEED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,76,70,57,12 +END + +7535 DIALOGEX 0, 0, 188, 108 +STYLE DS_SETFONT | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "TCP/IP",IDC_CLINKTCP,"Button",BS_AUTORADIOBUTTON | WS_GROUP,58,20,39,12 + CONTROL "UDP",IDC_CLINKUDP,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,118,20,32,12 + EDITTEXT IDC_SERVERIP,84,39,79,12,ES_AUTOHSCROLL | WS_GROUP + PUSHBUTTON "Connect",IDC_LINKCONNECT,75,81,59,16 + LTEXT "Select protocol:",IDC_STATIC,78,7,53,9 + LTEXT "Server IP address or hostname:",IDC_STATIC,7,37,62,18 + LTEXT "Speed hacks:",IDC_STATIC,7,64,47,10 + CONTROL "Off (accurate)",IDC_SPEEDOFF,"Button",BS_AUTORADIOBUTTON | WS_GROUP,60,63,57,12 + CONTROL "On (fast)",IDC_SPEEDON,"Button",BS_AUTORADIOBUTTON,128,63,48,12 +END + +7536 DIALOG 0, 0, 186, 90 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Waiting for players" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,63,69,50,14 + CONTROL "Progress1",IDC_SERVERWAIT,"msctls_progress32",WS_BORDER,33,50,120,13 + LTEXT "",IDC_STATIC1,7,7,154,8 + LTEXT "",IDC_STATIC2,7,17,105,8 + LTEXT "",IDC_STATIC3,7,25,105,8 + LTEXT "",IDC_STATIC4,7,33,105,8 +END + +IDD_OPENDLG DIALOG 36, 24, 202, 117 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CONTEXTHELP | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Open" +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "File &name:",1090,2,1,81,8 + EDITTEXT 1152,0,10,104,12,ES_AUTOHSCROLL | ES_OEMCONVERT + LISTBOX 1120,1,24,104,53,LBS_SORT | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "&Folders:",-1,112,0,53,9 + LTEXT "",1088,113,10,86,9,SS_NOPREFIX + LISTBOX 1121,112,24,88,52,LBS_SORT | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "List files of &type:",1089,1,75,81,9 + COMBOBOX 1136,1,87,104,13,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Dri&ves:",1091,113,76,70,9 + COMBOBOX 1137,112,87,71,68,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "OK",IDOK,24,102,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,90,102,50,14,WS_GROUP +END + +IDD_ABOUT DIALOGEX 0, 0, 179, 153 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "About" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + ICON IDI_MAINICON,IDC_STATIC,6,6,21,20 + CTEXT "VisualBoyAdvance Emulator",IDC_STATIC,36,6,138,8 + CTEXT "Copyright © 2008 VBA-M development team",IDC_STATIC,6,48,168,8 + CTEXT "https://vbam.bountysource.com",IDC_URL,6,138,168,8 + RTEXT "Version:",IDC_STATIC,36,18,54,8 + LTEXT "",IDC_VERSION,96,18,78,8,SS_NOPREFIX + GROUPBOX "VBA-M dev team:",IDC_STATIC,6,72,90,60 + CTEXT "mudlord\nNach\nJonas Quinn\nDJRobX\nSpacy",IDC_STATIC,12,84,78,42 + RTEXT "Date compiled:",IDC_STATIC,36,30,54,8 + LTEXT "",IDC_DATE,96,30,78,8,SS_NOPREFIX + GROUPBOX "Thanks go to:",IDC_STATIC,102,72,72,60 + CTEXT "Orig. VBA team\nCostis",IDC_STATIC,108,84,60,42 +END + +IDD_DIRECTORIES DIALOGEX 0, 0, 222, 270 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Directories" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Game Boy Advance ROMs",IDC_STATIC,6,6,210,30 + EDITTEXT IDC_ROM_PATH,12,18,180,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_ROM_DIR,192,18,18,12 + GROUPBOX "Game Boy Color ROMs",IDC_STATIC,6,42,210,30 + EDITTEXT IDC_GBCROM_PATH,12,54,180,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_GBCROM_DIR,192,54,18,12 + GROUPBOX "Game Boy ROMs",IDC_STATIC,6,78,210,30 + EDITTEXT IDC_GBROM_PATH,12,90,180,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_GBROM_DIR,192,90,18,12 + GROUPBOX "Native Saves",IDC_STATIC,6,114,210,30 + EDITTEXT IDC_BATTERY_PATH,12,126,180,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_BATTERY_DIR,192,126,18,12 + GROUPBOX "Emulator Saves",IDC_STATIC,6,150,210,30 + EDITTEXT IDC_SAVE_PATH,12,162,180,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_SAVE_DIR,192,162,18,12 + GROUPBOX "Screenshots",IDC_STATIC,6,186,210,30 + EDITTEXT IDC_CAPTURE_PATH,12,198,180,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_CAPTURE_DIR,192,198,18,12 + GROUPBOX "Relative Paths",IDC_STATIC,6,222,102,42 + CONTROL "Example:\n .\\battery\n ..\\screenshots\\vba",IDC_STATIC, + "Static",SS_LEFTNOWORDWRAP | WS_GROUP,12,234,90,24 + DEFPUSHBUTTON "OK",IDOK,120,246,48,18 + PUSHBUTTON "Cancel",IDCANCEL,168,246,48,18 +END + +IDD_CONFIG DIALOGEX 0, 0, 448, 102 +STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Joypad configuration" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + RTEXT "Up",IDC_STATIC,6,6,36,12 + EDITTEXT IDC_EDIT_UP,48,6,96,12,ES_AUTOHSCROLL + RTEXT "Down",IDC_STATIC,6,24,36,12 + EDITTEXT IDC_EDIT_DOWN,48,24,96,12,ES_AUTOHSCROLL + RTEXT "Left",IDC_STATIC,6,42,36,12 + EDITTEXT IDC_EDIT_LEFT,48,42,96,12,ES_AUTOHSCROLL + RTEXT "Right",IDC_STATIC,6,60,36,12 + EDITTEXT IDC_EDIT_RIGHT,48,60,96,12,ES_AUTOHSCROLL + RTEXT "A",IDC_STATIC,156,6,36,12 + EDITTEXT IDC_EDIT_BUTTON_A,198,6,96,12,ES_AUTOHSCROLL + RTEXT "B",IDC_STATIC,156,24,36,12 + EDITTEXT IDC_EDIT_BUTTON_B,198,24,96,12,ES_AUTOHSCROLL + RTEXT "L",IDC_STATIC,156,42,36,12 + EDITTEXT IDC_EDIT_BUTTON_L,198,42,96,12,ES_AUTOHSCROLL + RTEXT "R",IDC_STATIC,156,60,36,12 + EDITTEXT IDC_EDIT_BUTTON_R,198,60,96,12,ES_AUTOHSCROLL + RTEXT "Select",IDC_STATIC,6,84,36,12 + EDITTEXT IDC_EDIT_BUTTON_SELECT,48,84,96,12,ES_AUTOHSCROLL + RTEXT "Start",IDC_STATIC,156,84,36,12 + EDITTEXT IDC_EDIT_BUTTON_START,198,84,96,12,ES_AUTOHSCROLL + RTEXT "Speed Up",IDC_STATIC,306,6,36,12 + EDITTEXT IDC_EDIT_SPEED,348,6,96,12,ES_AUTOHSCROLL + RTEXT "Screenshot",IDC_STATIC,306,24,36,12 + EDITTEXT IDC_EDIT_CAPTURE,348,24,96,12,ES_AUTOHSCROLL + RTEXT "GS",IDC_STATIC,306,42,36,12 + EDITTEXT IDC_EDIT_BUTTON_GS,348,42,96,12,ES_AUTOHSCROLL + CONTROL "Multiple key assignments",IDC_APPENDMODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,348,60,96,12 + DEFPUSHBUTTON "OK",ID_OK,348,78,48,18 + PUSHBUTTON "Cancel",ID_CANCEL,396,78,48,18 + PUSHBUTTON "Clear all",IDC_CLEAR_ALL,306,60,36,12 +END + +IDD_CHEATS DIALOG 0, 0, 276, 253 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Search for cheats" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "",IDC_CHEAT_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,3,5,265,111 + CONTROL "Ol&d value",IDC_OLD_VALUE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,129,46,10 + CONTROL "Specifi&c value",IDC_SPECIFIC_VALUE,"Button",BS_AUTORADIOBUTTON,11,141,61,10 + CONTROL "&8 bits",IDC_SIZE_8,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,167,33,10 + CONTROL "&16 bits",IDC_SIZE_16,"Button",BS_AUTORADIOBUTTON,11,179,37,10 + CONTROL "&32 bits",IDC_SIZE_32,"Button",BS_AUTORADIOBUTTON,11,191,37,10 + CONTROL "&Equal",IDC_EQ,"Button",BS_AUTORADIOBUTTON | WS_GROUP,100,128,34,10 + CONTROL "&Not equal",IDC_NE,"Button",BS_AUTORADIOBUTTON,100,140,47,10 + CONTROL "&Less than",IDC_LT,"Button",BS_AUTORADIOBUTTON,100,152,47,10 + CONTROL "Le&ss or equal",IDC_LE,"Button",BS_AUTORADIOBUTTON,100,164,58,10 + CONTROL "&Greather than",IDC_GT,"Button",BS_AUTORADIOBUTTON,100,176,59,10 + CONTROL "G&reater or equal",IDC_GE,"Button",BS_AUTORADIOBUTTON,100,188,67,10 + CONTROL "S&igned",IDC_SIGNED,"Button",BS_AUTORADIOBUTTON | WS_GROUP,202,130,38,10 + CONTROL "&Unsigned",IDC_UNSIGNED,"Button",BS_AUTORADIOBUTTON,202,142,46,10 + CONTROL "&Hexadecimal",IDC_HEXADECIMAL,"Button",BS_AUTORADIOBUTTON,202,154,57,10 + CONTROL "U&pdate values",IDC_UPDATE,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,192,192,62,10 + EDITTEXT IDC_VALUE,95,211,172,14,ES_AUTOHSCROLL + PUSHBUTTON "&Start",IDC_START,15,237,50,14,WS_GROUP + PUSHBUTTON "S&earch",IDC_SEARCH,80,236,50,14 + PUSHBUTTON "&Add cheat",IDC_ADD_CHEAT,145,236,50,14 + DEFPUSHBUTTON "OK",ID_OK,210,236,50,14 + GROUPBOX "&Search type",IDC_STATIC,3,118,84,36 + GROUPBOX "&Data size",IDC_STATIC,3,158,84,44 + GROUPBOX "Compare type",IDC_STATIC,95,118,92,84 + GROUPBOX "Signed/Unsigned",IDC_STATIC,192,118,76,50 + LTEXT "Enter &value:",IDC_STATIC,3,214,69,8 +END + +IDD_ADD_CHEAT DIALOG 0, 0, 186, 137 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Add cheat" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_ADDRESS,60,6,123,14,ES_AUTOHSCROLL + EDITTEXT IDC_VALUE,60,24,123,14,ES_AUTOHSCROLL + EDITTEXT IDC_DESC,60,42,123,14,ES_AUTOHSCROLL + CONTROL "8-bit",IDC_SIZE_8,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,11,70,29,10 + CONTROL "16-bit",IDC_SIZE_16,"Button",BS_AUTORADIOBUTTON,62,70,33,10 + CONTROL "32-bit",IDC_SIZE_32,"Button",BS_AUTORADIOBUTTON,117,70,33,10 + CONTROL "&Signed",IDC_SIGNED,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,11,97,38,10 + CONTROL "&Unsigned",IDC_UNSIGNED,"Button",BS_AUTORADIOBUTTON,62,98,46,10 + CONTROL "&Hexadecimal",IDC_HEXADECIMAL,"Button",BS_AUTORADIOBUTTON,117,98,57,10 + DEFPUSHBUTTON "&OK",ID_OK,36,116,50,14,WS_GROUP + PUSHBUTTON "&Cancel",ID_CANCEL,99,116,50,14 + LTEXT "&Value:",IDC_STATIC,3,27,54,8 + GROUPBOX "Number format",IDC_STATIC,3,88,180,24 + LTEXT "&Address:",IDC_STATIC,3,9,54,8 + GROUPBOX "Size",IDC_STATIC,3,60,180,24 + LTEXT "&Description:",IDC_STATIC,3,45,55,8 +END + +IDD_CHEAT_LIST DIALOG 0, 0, 280, 250 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Cheat list" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Restore &previous values",IDC_RESTORE,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,5,183,92,10 + PUSHBUTTON "&Code...",IDC_ADD_CODE,9,208,64,14,WS_GROUP + PUSHBUTTON "C&heat...",IDC_ADD_CHEAT,75,208,64,14 + PUSHBUTTON "&Gameshark...",IDC_ADD_GAMESHARK,141,208,64,14 + PUSHBUTTON "CodeBreaker...",IDC_ADD_CODEBREAKER,206,208,64,14 + PUSHBUTTON "&Remove",IDC_REMOVE,9,230,64,14 + PUSHBUTTON "Remove A&ll",IDC_REMOVE_ALL,75,230,64,14 + PUSHBUTTON "&Enable/Dis.",IDC_ENABLE,141,230,64,14 + DEFPUSHBUTTON "&OK",ID_OK,206,230,64,14,WS_GROUP + CONTROL "",IDC_CHEAT_LIST,"SysListView32",LVS_REPORT | WS_BORDER | WS_GROUP | WS_TABSTOP,5,15,269,156 + LTEXT "Status legend:",IDC_STATIC,6,3,46,8 + LTEXT "E: Enabled",IDC_STATIC,188,3,36,8 + LTEXT "D: Disabled",IDC_STATIC,234,3,38,8 + GROUPBOX "Add",IDC_STATIC,5,199,268,27 +END + +IDD_ASSOCIATIONS DIALOG 0, 0, 116, 95 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Associations" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL ".gb",IDC_GB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,15,26,10 + CONTROL ".sgb",IDC_SGB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,29,29,10 + CONTROL ".cgb",IDC_CGB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,43,30,10 + CONTROL ".gbc",IDC_GBC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,57,30,10 + CONTROL ".gba",IDC_GBA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,13,30,10 + CONTROL ".agb",IDC_AGB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,27,30,10 + CONTROL ".bin",IDC_BIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,41,27,10 + DEFPUSHBUTTON "OK",ID_OK,3,78,50,14 + PUSHBUTTON "Cancel",ID_CANCEL,63,78,50,14 + GROUPBOX "GBA Types",IDC_STATIC,63,3,50,51 + GROUPBOX "GB Types",IDC_STATIC,3,3,50,69 +END + +IDD_GBA_ROM_INFO DIALOGEX 0, 0, 220, 142 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ROM Information" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",ID_OK,84,121,50,14 + LTEXT "Game title:",IDC_STATIC,7,10,60,8 + LTEXT "Game code:",IDC_STATIC,7,24,60,8 + LTEXT "Maker code:",IDC_STATIC,7,38,60,8 + LTEXT "Main unit code:",IDC_STATIC,7,66,60,8 + LTEXT "Device type:",IDC_STATIC,7,80,60,8 + LTEXT "ROM version:",IDC_STATIC,7,94,60,8 + LTEXT "CRC:",IDC_STATIC,7,108,60,8 + LTEXT "Maker name:",IDC_STATIC,7,52,60,8 + LTEXT "",IDC_ROM_TITLE,80,10,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_GAME_CODE,80,24,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_MAKER_CODE,80,38,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_UNIT_CODE,80,66,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_DEVICE_TYPE,80,80,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_VERSION,80,94,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_CRC,80,108,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_MAKER_NAME,80,52,133,8,SS_NOPREFIX +END + +IDD_GB_ROM_INFO DIALOGEX 0, 0, 220, 225 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ROM Information" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",ID_OK,40,204,50,14 + LTEXT "Game title:",IDC_STATIC,7,10,60,8 + LTEXT "Maker code:",IDC_STATIC,7,38,60,8 + LTEXT "Unit code:",IDC_STATIC,7,68,60,8 + LTEXT "Cartridge type:",IDC_STATIC,7,82,60,8 + LTEXT "ROM version:",IDC_STATIC,7,152,60,8 + LTEXT "CRC:",IDC_STATIC,7,166,60,8 + LTEXT "",IDC_ROM_TITLE,80,10,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_MAKER_CODE,80,38,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_UNIT_CODE,80,68,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_DEVICE_TYPE,80,82,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_VERSION,80,152,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_CRC,80,166,133,8,SS_NOPREFIX + LTEXT "Color:",IDC_STATIC,7,24,60,8 + LTEXT "",IDC_ROM_COLOR,80,24,133,8,SS_NOPREFIX + LTEXT "ROM size:",IDC_STATIC,7,96,60,8 + LTEXT "",IDC_ROM_SIZE,80,96,133,8,SS_NOPREFIX + LTEXT "RAM size:",IDC_STATIC,7,110,60,8 + LTEXT "",IDC_ROM_RAM_SIZE,80,110,133,8,SS_NOPREFIX + LTEXT "Dest. code:",IDC_STATIC,7,124,60,8 + LTEXT "",IDC_ROM_DEST_CODE,80,124,133,8,SS_NOPREFIX + LTEXT "License code:",IDC_STATIC,7,138,60,8 + LTEXT "",IDC_ROM_LIC_CODE,80,138,133,8,SS_NOPREFIX + LTEXT "Checksum:",IDC_STATIC,7,180,60,8 + LTEXT "",IDC_ROM_CHECKSUM,80,180,133,8,SS_NOPREFIX + LTEXT "",IDC_ROM_MAKER_NAME2,80,52,133,8,SS_NOPREFIX + LTEXT "Maker name:",IDC_STATIC,7,52,60,8 +END + +IDD_GB_CHEAT_LIST DIALOG 0, 0, 286, 221 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Gameboy Cheat List" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "",IDC_CHEAT_LIST,"SysListView32",LVS_REPORT | WS_BORDER | WS_GROUP | WS_TABSTOP,9,20,269,156 + PUSHBUTTON "Add &GameGenie...",IDC_ADD_GG_CHEAT,9,183,80,14,WS_GROUP + PUSHBUTTON "&Add GameShark...",IDC_ADD_GS_CHEAT,103,183,80,14,WS_GROUP + PUSHBUTTON "&Remove",IDC_REMOVE,197,183,80,14 + PUSHBUTTON "Remove A&ll",IDC_REMOVE_ALL,9,202,80,14 + PUSHBUTTON "&Enable/Dis.",IDC_ENABLE,103,202,80,14 + DEFPUSHBUTTON "&OK",ID_OK,197,202,80,14 + LTEXT "Status legend:",IDC_STATIC,10,9,46,8 + LTEXT "E: Enabled",IDC_STATIC,195,9,36,8 + LTEXT "D: Disabled",IDC_STATIC,241,9,38,8 +END + +IDD_ADD_CHEAT_DLG DIALOG 0, 0, 182, 107 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Title" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_DESC,60,7,120,14,ES_AUTOHSCROLL + EDITTEXT IDC_CODE,60,23,120,58,ES_MULTILINE | ES_UPPERCASE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN + DEFPUSHBUTTON "OK",ID_OK,33,86,50,14 + PUSHBUTTON "Cancel",ID_CANCEL,99,86,50,14 + LTEXT "&Description:",IDC_STATIC,3,10,54,8 + LTEXT "&Code:",IDC_STATIC,3,29,54,8 +END + +IDD_GB_PRINTER DIALOG 0, 0, 178, 209 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "GB Printer" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "&1x",IDC_1X,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,166,22,10 + CONTROL "&2x",IDC_2X,"Button",BS_AUTORADIOBUTTON,55,166,23,10 + CONTROL "&3x",IDC_3X,"Button",BS_AUTORADIOBUTTON,98,166,23,10 + CONTROL "&4x",IDC_4X,"Button",BS_AUTORADIOBUTTON,141,166,23,10 + DEFPUSHBUTTON "&Print...",ID_PRINT,7,190,50,14,WS_GROUP + PUSHBUTTON "&Save...",ID_SAVE,64,190,50,14 + PUSHBUTTON "&Close",ID_OK,121,190,50,14 + CONTROL "",IDC_GB_PRINTER,"Static",SS_BLACKFRAME | WS_GROUP,7,6,162,146 + GROUPBOX "Print Size",IDC_STATIC,7,156,162,25 +END + +IDD_MOTION_CONFIG DIALOGEX 0, 0, 234, 107 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Motion Sensor" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_EDIT_UP,41,2,186,12,ES_AUTOHSCROLL + EDITTEXT IDC_EDIT_DOWN,41,16,186,12,ES_AUTOHSCROLL + EDITTEXT IDC_EDIT_LEFT,41,30,186,12,ES_AUTOHSCROLL + EDITTEXT IDC_EDIT_RIGHT,41,44,186,12,ES_AUTOHSCROLL + PUSHBUTTON "OK",ID_OK,64,86,40,14 + PUSHBUTTON "Cancel",ID_CANCEL,118,86,40,14 + LTEXT "Up:",IDC_STATIC,5,2,35,10 + LTEXT "Down:",IDC_STATIC,5,16,35,10 + LTEXT "Left:",IDC_STATIC,5,30,35,10 + LTEXT "Right:",IDC_STATIC,5,44,35,10 + CONTROL "Assign additional keys to functions",IDC_APPENDMODE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,46,66,135,10 +END + +IDD_LANG_SELECT DIALOG 0, 0, 186, 68 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Language selection" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_LANG_STRING,140,25,40,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",ID_OK,30,49,50,14 + PUSHBUTTON "Cancel",ID_CANCEL,104,49,50,14 + LTEXT "Current system language is:",IDC_STATIC,6,9,123,8 + LTEXT "Enter language name (3 letter):",IDC_STATIC,6,30,127,8 + LTEXT "",IDC_LANG_NAME,140,9,40,8,SS_NOPREFIX +END + +IDD_CODE_SELECT DIALOG 0, 0, 316, 235 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Select codes to import" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",ID_OK,91,214,50,14 + PUSHBUTTON "Cancel",ID_CANCEL,174,214,50,14 + LISTBOX IDC_GAME_LIST,7,7,302,205,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP +END + +IDD_MAP_VIEW DIALOG 0, 0, 322, 238 +STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Map view" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Frame 0",IDC_FRAME_0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,22,41,10 + CONTROL "Frame 1",IDC_FRAME_1,"Button",BS_AUTORADIOBUTTON,13,36,41,10 + CONTROL "BG0",IDC_BG0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,63,30,10 + CONTROL "BG1",IDC_BG1,"Button",BS_AUTORADIOBUTTON,13,77,30,10 + CONTROL "BG2",IDC_BG2,"Button",BS_AUTORADIOBUTTON,13,91,30,10 + CONTROL "BG3",IDC_BG3,"Button",BS_AUTORADIOBUTTON,13,105,30,10 + CONTROL "Stretch to fit",IDC_STRETCH,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,7,122,68,10 + CONTROL "Auto update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,7,134,55,10 + PUSHBUTTON "&Refresh",IDC_REFRESH,25,217,50,14,WS_GROUP + PUSHBUTTON "&Save...",IDC_SAVE,88,217,50,14,WS_GROUP + PUSHBUTTON "&Close",IDC_CLOSE,155,217,50,14 + CONTROL "MapView",IDC_MAP_VIEW,"VbaBitmapControl",WS_GROUP | WS_TABSTOP,187,15,128,128 + CONTROL "Zoom",IDC_MAP_VIEW_ZOOM,"VbaZoomControl",WS_GROUP | WS_TABSTOP,7,148,64,64 + CONTROL "Color",IDC_COLOR,"VbaColorControl",WS_TABSTOP,187,164,48,47 + LTEXT "",IDC_R,245,173,50,8,SS_NOPREFIX + LTEXT "",IDC_G,245,185,50,8,SS_NOPREFIX + LTEXT "",IDC_B,245,197,50,8,SS_NOPREFIX + GROUPBOX "Frame",IDC_STATIC,7,11,63,37 + GROUPBOX "Background",IDC_STATIC,7,52,63,67 + LTEXT "",IDC_XY,129,95,53,8,SS_NOPREFIX + LTEXT "Mode:",IDC_STATIC,80,15,34,8 + LTEXT "",IDC_MODE,130,15,53,8,SS_NOPREFIX + LTEXT "Map Base:",IDC_STATIC,80,25,35,8 + LTEXT "",IDC_MAPBASE,130,25,53,8,SS_NOPREFIX + LTEXT "Char Base:",IDC_STATIC,80,35,36,8 + LTEXT "",IDC_CHARBASE,130,35,53,8,SS_NOPREFIX + LTEXT "Size:",IDC_STATIC,80,45,37,8 + LTEXT "",IDC_DIM,130,45,53,8,SS_NOPREFIX + LTEXT "Colors:",IDC_STATIC,80,55,37,8 + LTEXT "",IDC_NUMCOLORS,130,55,53,8,SS_NOPREFIX + LTEXT "Priority:",IDC_STATIC,80,65,37,8 + LTEXT "",IDC_PRIORITY,130,65,53,8,SS_NOPREFIX + LTEXT "Mosaic:",IDC_STATIC,80,75,37,8 + LTEXT "",IDC_MOSAIC,130,75,53,8,SS_NOPREFIX + LTEXT "Overflow:",IDC_STATIC,80,85,37,8 + LTEXT "",IDC_OVERFLOW,130,85,53,8,SS_NOPREFIX + LTEXT "Address:",IDC_STATIC,80,105,37,8 + LTEXT "",IDC_ADDRESS,130,105,53,8,SS_NOPREFIX + LTEXT "Tile:",IDC_STATIC,80,115,37,8 + LTEXT "",IDC_TILE_NUM,130,115,53,8,SS_NOPREFIX + LTEXT "Flip:",IDC_STATIC,80,125,37,8 + LTEXT "",IDC_FLIP,130,125,53,8,SS_NOPREFIX + LTEXT "Palette:",IDC_STATIC,80,135,37,8 + LTEXT "",IDC_PALETTE_NUM,130,135,53,8,SS_NOPREFIX +END + +IDD_PALETTE_VIEW DIALOG 0, 0, 316, 266 +STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Palette View" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Save BG...",IDC_SAVE_BG,30,245,50,14 + PUSHBUTTON "Save OBJ...",IDC_SAVE_OBJ,98,245,50,14 + PUSHBUTTON "&Refresh",IDC_REFRESH2,166,245,50,14 + PUSHBUTTON "&Close",IDC_CLOSE,234,245,50,14 + LTEXT "",IDC_ADDRESS,53,168,50,8,SS_NOPREFIX + LTEXT "",IDC_R,53,180,50,8,SS_NOPREFIX + LTEXT "",IDC_G,53,192,50,8,SS_NOPREFIX + LTEXT "",IDC_B,53,204,50,8,SS_NOPREFIX + LTEXT "",IDC_VALUE,53,216,50,8,SS_NOPREFIX + CONTROL "Custom1",IDC_COLOR,"VbaColorControl",WS_TABSTOP,161,168,50,50 + CONTROL "PaletteViewBG",IDC_PALETTE_VIEW,"VbaPaletteViewControl",WS_TABSTOP,12,30,128,128 + CONTROL "PaletteViewBG",IDC_PALETTE_VIEW_OBJ, + "VbaPaletteViewControl",WS_TABSTOP,166,30,128,128 + GROUPBOX "Background",IDC_STATIC,7,20,137,143 + GROUPBOX "Sprite",IDC_STATIC,161,20,137,143 + LTEXT "Address:",IDC_STATIC,7,168,38,8 + LTEXT "R:",IDC_STATIC,7,180,41,8 + LTEXT "G:",IDC_STATIC,7,192,43,8 + LTEXT "B:",IDC_STATIC,7,204,38,8 + LTEXT "Value:",IDC_STATIC,7,216,38,8 + LTEXT "Click on a color for more information",IDC_STATIC,7,7,302,8 + CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,229,71,10 +END + +IDD_MEM_VIEWER DIALOG 0, 0, 380, 178 +STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Memory viewer" +FONT 8, "MS Sans Serif" +BEGIN + COMBOBOX IDC_ADDRESSES,7,7,109,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "8-bit",IDC_8_BIT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,120,9,29,10 + CONTROL "16-bit",IDC_16_BIT,"Button",BS_AUTORADIOBUTTON,154,9,33,10 + CONTROL "32-bit",IDC_32_BIT,"Button",BS_AUTORADIOBUTTON,192,9,33,10 + EDITTEXT IDC_ADDRESS,238,7,82,14,ES_UPPERCASE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_GROUP + DEFPUSHBUTTON "&Go",IDC_GO,323,7,50,14,WS_GROUP + CONTROL "Viewer",IDC_VIEWER,"VbaMemoryViewer",WS_TABSTOP,7,22,366,112 + CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,139,71,10 + PUSHBUTTON "&Refresh",IDC_REFRESH,67,157,50,14 + PUSHBUTTON "&Load...",IDC_LOAD,132,157,50,14 + PUSHBUTTON "&Save...",IDC_SAVE,197,157,50,14 + PUSHBUTTON "&Close",IDC_CLOSE,262,157,50,14 + LTEXT "Current address:",IDC_CURRENT_ADDRESS_LABEL,210,142,77,8 + EDITTEXT IDC_CURRENT_ADDRESS,291,139,82,14,ES_RIGHT | ES_AUTOHSCROLL | WS_DISABLED +END + +IDD_OAM_VIEW DIALOGEX 0, 0, 234, 185 +STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "OAM Viewer" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_SPRITE,7,19,76,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER + SCROLLBAR IDC_SCROLLBAR,7,33,76,11 + CONTROL "Stretch to fit",IDC_STRETCH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,138,79,10 + PUSHBUTTON "&Refresh",IDC_REFRESH,7,164,50,14,WS_GROUP + PUSHBUTTON "&Save...",IDC_SAVE,91,164,50,14,WS_GROUP + PUSHBUTTON "&Close",IDC_CLOSE,177,164,50,14 + CONTROL "MapView",IDC_OAM_VIEW,"VbaBitmapControl",WS_GROUP | WS_TABSTOP,87,7,64,64 + CONTROL "Zoom",IDC_OAM_VIEW_ZOOM,"VbaZoomControl",WS_GROUP | WS_TABSTOP,163,7,64,64 + CONTROL "Color",IDC_COLOR,"VbaColorControl",WS_TABSTOP,87,79,48,47 + LTEXT "",IDC_POS,31,47,50,8,SS_NOPREFIX + LTEXT "",IDC_MODE,31,57,50,8,SS_NOPREFIX + LTEXT "",IDC_COLORS,31,67,50,8,SS_NOPREFIX + LTEXT "",IDC_PALETTE,31,77,50,8,SS_NOPREFIX + LTEXT "",IDC_TILE,31,87,50,8,SS_NOPREFIX + LTEXT "",IDC_PRIO,31,97,50,8,SS_NOPREFIX + LTEXT "",IDC_SIZE2,31,107,50,8,SS_NOPREFIX + LTEXT "",IDC_ROT,31,117,50,8,SS_NOPREFIX + LTEXT "",IDC_FLAGS,31,127,50,8,SS_NOPREFIX + LTEXT "",IDC_R,145,88,50,8,SS_NOPREFIX + LTEXT "",IDC_G,145,100,50,8,SS_NOPREFIX + LTEXT "",IDC_B,145,112,50,8,SS_NOPREFIX + LTEXT "Pos:",IDC_STATIC,7,47,24,8 + LTEXT "Mode:",IDC_STATIC,7,57,24,8 + LTEXT "Colors:",IDC_STATIC,7,67,24,8 + LTEXT "Pal:",IDC_STATIC,7,77,24,8 + LTEXT "Tile:",IDC_STATIC,7,87,24,8 + LTEXT "Prio:",IDC_STATIC,7,97,24,8 + LTEXT "Size:",IDC_STATIC,7,107,24,8 + LTEXT "Sprite:",IDC_STATIC,7,7,50,8 + LTEXT "Rot.:",IDC_STATIC,7,117,24,8 + LTEXT "Flags:",IDC_STATIC,7,127,24,8 + CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,150,71,10 +END + +IDD_ACCEL_EDITOR DIALOGEX 0, 0, 399, 121 +STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Accelerator editor" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LTEXT "&Commands:",IDC_STATIC,7,7,38,8 + LISTBOX IDC_COMMANDS,7,18,153,67,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Current &Keys:",IDC_STATIC1,176,7,43,8 + LISTBOX IDC_CURRENTS,176,17,153,67,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "OK",ID_OK,342,9,50,14 + PUSHBUTTON "Cancel",ID_CANCEL,342,25,50,14 + LTEXT "Select &New Shortcut Key:",IDC_STATIC3,175,86,82,8 + EDITTEXT IDC_EDIT_KEY,176,95,100,12,ES_AUTOHSCROLL + PUSHBUTTON "&Assign",IDC_ASSIGN,342,70,50,14 + PUSHBUTTON "&Remove",IDC_REMOVE,342,86,50,14 + PUSHBUTTON "Re&set All",IDC_RESET,342,102,50,14 + LTEXT "Static",IDC_ALREADY_AFFECTED,7,96,105,9,SS_CENTERIMAGE + LTEXT "Currently assigned to :",IDC_STATIC2,7,87,73,10 +END + +IDD_TILE_VIEWER DIALOG 0, 0, 326, 266 +STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Tile Viewer" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "16",IDC_16_COLORS,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,20,24,10 + CONTROL "256",IDC_256_COLORS,"Button",BS_AUTORADIOBUTTON,13,30,28,10 + CONTROL "0x6000000",IDC_CHARBASE_0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,57,51,10 + CONTROL "0x6004000",IDC_CHARBASE_1,"Button",BS_AUTORADIOBUTTON,13,67,51,10 + CONTROL "0x6008000",IDC_CHARBASE_2,"Button",BS_AUTORADIOBUTTON,13,77,51,10 + CONTROL "0x600C000",IDC_CHARBASE_3,"Button",BS_AUTORADIOBUTTON,13,87,52,10 + CONTROL "0x6010000",IDC_CHARBASE_4,"Button",BS_AUTORADIOBUTTON,13,97,49,10 + CONTROL "Slider1",IDC_PALETTE_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,1,124,76,22 + CONTROL "Stretch to fit",IDC_STRETCH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,149,79,10 + PUSHBUTTON "Refresh",IDC_REFRESH,7,245,50,14,WS_GROUP + PUSHBUTTON "Save...",IDC_SAVE,138,245,50,14 + PUSHBUTTON "Close",IDC_CLOSE,269,245,50,14 + CONTROL "Custom1",IDC_TILE_VIEW,"VbaBitmapControl",WS_GROUP | WS_TABSTOP,191,7,128,128 + GROUPBOX "Colors",IDC_STATIC,7,7,66,38 + GROUPBOX "Char Base",IDC_STATIC,7,46,65,64 + CONTROL "Zoom",IDC_MAP_VIEW_ZOOM,"VbaZoomControl",WS_GROUP | WS_TABSTOP,7,174,64,64 + CONTROL "Color",IDC_COLOR,"VbaColorControl",WS_TABSTOP,98,183,48,47 + LTEXT "",IDC_R,156,192,50,8,SS_NOPREFIX + LTEXT "",IDC_G,156,204,50,8,SS_NOPREFIX + LTEXT "",IDC_B,156,216,50,8,SS_NOPREFIX + LTEXT "Palette:",IDC_STATIC,7,113,65,8 + CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,160,71,10 + LTEXT "Tile:",IDC_STATIC,79,14,41,8 + LTEXT "Address:",IDC_STATIC,79,26,41,8 + LTEXT "",IDC_TILE_NUMBER,135,14,50,8,SS_NOPREFIX + LTEXT "",IDC_ADDRESS,135,26,50,8,SS_NOPREFIX +END + +IDD_GB_COLORS DIALOG 0, 0, 169, 121 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Gameboy Mono Colors" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Default",IDC_DEFAULT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7,7,39,10 + CONTROL "User 1",IDC_USER1,"Button",BS_AUTORADIOBUTTON,67,7,37,10 + CONTROL "User 2",IDC_USER2,"Button",BS_AUTORADIOBUTTON,125,7,37,10 + COMBOBOX IDC_PREDEFINED,7,21,155,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "",IDC_COLOR_BG0,15,47,28,14,WS_GROUP + PUSHBUTTON "",IDC_COLOR_BG1,52,47,28,14 + PUSHBUTTON "",IDC_COLOR_BG2,89,47,28,14 + PUSHBUTTON "",IDC_COLOR_BG3,126,47,28,14 + PUSHBUTTON "",IDC_COLOR_OB0,15,78,28,14 + PUSHBUTTON "",IDC_COLOR_OB1,52,78,28,14 + PUSHBUTTON "",IDC_COLOR_OB2,89,78,28,14 + PUSHBUTTON "",IDC_COLOR_OB3,126,78,28,14 + PUSHBUTTON "Reset",IDC_RESET,7,100,50,14 + DEFPUSHBUTTON "OK",ID_OK,59,100,50,14 + PUSHBUTTON "Cancel",ID_CANCEL,111,100,50,14 + GROUPBOX "Background",IDC_STATIC,8,37,154,29 + GROUPBOX "Sprite",IDC_STATIC,8,67,154,30 +END + +IDD_DISASSEMBLE DIALOG 0, 0, 402, 225 +STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Disassemble" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Automatic",IDC_AUTOMATIC,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7,9,47,10 + CONTROL "ARM",IDC_ARM,"Button",BS_AUTORADIOBUTTON,62,9,32,10 + CONTROL "THUMB",IDC_THUMB,"Button",BS_AUTORADIOBUTTON,103,9,42,10 + EDITTEXT IDC_ADDRESS,158,7,65,14,ES_UPPERCASE | ES_AUTOHSCROLL | WS_GROUP + DEFPUSHBUTTON "Go",IDC_GO,232,7,50,14 + LISTBOX IDC_DISASSEMBLE,7,25,276,161,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_TABSTOP + CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,191,71,10 + PUSHBUTTON "Refresh",IDC_REFRESH,120,204,50,14 + PUSHBUTTON "Next",IDC_NEXT,233,204,50,14 + PUSHBUTTON "Close",IDC_CLOSE,346,204,50,14 + LTEXT "R0:",IDC_STATIC,309,7,18,8 + LTEXT "R1:",IDC_STATIC,309,15,18,8 + LTEXT "R2:",IDC_STATIC,309,23,18,8 + LTEXT "R3:",IDC_STATIC,309,31,18,8 + LTEXT "R4:",IDC_STATIC,309,39,18,8 + LTEXT "R5:",IDC_STATIC,309,47,18,8 + LTEXT "R6:",IDC_STATIC,309,55,18,8 + LTEXT "R7:",IDC_STATIC,309,63,18,8 + LTEXT "",IDC_R0,344,7,52,8,SS_NOPREFIX + LTEXT "",IDC_R1,344,15,52,8,SS_NOPREFIX + LTEXT "",IDC_R2,344,23,52,8,SS_NOPREFIX + LTEXT "",IDC_R3,344,31,52,8,SS_NOPREFIX + LTEXT "",IDC_R4,344,39,52,8,SS_NOPREFIX + LTEXT "",IDC_R5,344,47,52,8,SS_NOPREFIX + LTEXT "",IDC_R6,344,55,52,8,SS_NOPREFIX + LTEXT "",IDC_R7,344,63,52,8,SS_NOPREFIX + LTEXT "",IDC_R8,344,71,52,8,SS_NOPREFIX + LTEXT "",IDC_R9,344,79,52,8,SS_NOPREFIX + LTEXT "",IDC_R10,344,87,52,8,SS_NOPREFIX + LTEXT "",IDC_R11,344,95,52,8,SS_NOPREFIX + LTEXT "",IDC_R12,344,103,52,8,SS_NOPREFIX + LTEXT "",IDC_R13,344,111,52,8,SS_NOPREFIX + LTEXT "",IDC_R14,344,119,52,8,SS_NOPREFIX + LTEXT "",IDC_R15,344,127,52,8,SS_NOPREFIX + LTEXT "R8:",IDC_STATIC,309,71,18,8 + LTEXT "R9:",IDC_STATIC,309,79,18,8 + LTEXT "R10:",IDC_STATIC,309,87,18,8 + LTEXT "R11:",IDC_STATIC,309,95,18,8 + LTEXT "R12:",IDC_STATIC,309,103,18,8 + LTEXT "R13:",IDC_STATIC,309,111,18,8 + LTEXT "R14:",IDC_STATIC,309,119,18,8 + LTEXT "R15:",IDC_STATIC,309,127,18,8 + LTEXT "",IDC_R16,344,135,52,8,SS_NOPREFIX + LTEXT "R16:",IDC_STATIC,309,135,20,8 + CONTROL "N",IDC_N,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,309,146,21,10 + CONTROL "Z",IDC_Z,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,309,156,21,10 + CONTROL "C",IDC_C,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,309,166,21,10 + CONTROL "V",IDC_V,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,309,176,21,10 + CONTROL "F",IDC_F,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,342,156,20,10 + CONTROL "I",IDC_I,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,342,146,18,10 + CONTROL "T",IDC_T,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,342,166,21,10 + LTEXT "Mode:",IDC_STATIC,341,176,21,8 + LTEXT "",IDC_MODE,376,176,20,8,SS_NOPREFIX + SCROLLBAR IDC_VSCROLL,283,25,10,161,SBS_VERT + PUSHBUTTON "Goto R15",IDC_GOPC,7,204,50,14 +END + +IDD_GDB_PORT DIALOG 0, 0, 186, 51 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "GDB connection" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",ID_OK,34,30,50,14 + PUSHBUTTON "Cancel",ID_CANCEL,102,30,50,14 + LTEXT "Port to wait for connection:",IDC_STATIC,7,10,105,8 + EDITTEXT IDC_PORT,125,7,54,14,ES_RIGHT | ES_AUTOHSCROLL +END + +IDD_GDB_WAITING DIALOG 0, 0, 186, 44 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Waiting..." +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Cancel",ID_CANCEL,67,23,50,14 + LTEXT "Waiting for connection on port:",IDC_STATIC,7,7,117,8 + LTEXT "",IDC_PORT,143,7,36,8,SS_NOPREFIX +END + +IDD_LOGGING DIALOG 0, 0, 366, 218 +STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Logging" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "SWI",IDC_VERBOSE_SWI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,17,87,10 + CONTROL "Unaligned memory",IDC_VERBOSE_UNALIGNED_ACCESS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,30,87,10 + CONTROL "Illegal write",IDC_VERBOSE_ILLEGAL_WRITE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,43,87,10 + CONTROL "Illegal read",IDC_VERBOSE_ILLEGAL_READ,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,56,87,10 + CONTROL "DMA 0",IDC_VERBOSE_DMA0,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,69,87,10 + CONTROL "DMA 1",IDC_VERBOSE_DMA1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,82,87,10 + CONTROL "DMA 2",IDC_VERBOSE_DMA2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,95,87,10 + CONTROL "DMA 3",IDC_VERBOSE_DMA3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,108,87,10 + CONTROL "Undefined instruction",IDC_VERBOSE_UNDEFINED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,121,87,10 + CONTROL "AGBPrint",IDC_VERBOSE_AGBPRINT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,134,87,10 + EDITTEXT IDC_LOG,107,7,252,183,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL + PUSHBUTTON "Save...",IDC_SAVE,75,197,50,14 + PUSHBUTTON "Clear",IDC_CLEAR,137,197,50,14 + DEFPUSHBUTTON "OK",ID_OK,197,197,50,14 + GROUPBOX "Verbose",IDC_STATIC,7,7,93,142 +END + +IDD_EXPORT_SPS DIALOGEX 0, 0, 248, 148 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Export GameShark Snapshot" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_TITLE,84,7,157,14,ES_AUTOHSCROLL + EDITTEXT IDC_DESC,84,27,157,14,ES_AUTOHSCROLL + EDITTEXT IDC_NOTES,84,47,157,73,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN + DEFPUSHBUTTON "OK",ID_OK,67,127,50,14 + PUSHBUTTON "Cancel",ID_CANCEL,130,127,50,14 + LTEXT "Title:",IDC_STATIC,7,8,62,8 + LTEXT "Description:",IDC_STATIC,7,28,63,8 + LTEXT "Notes:",IDC_STATIC,7,48,60,8 +END + +IDD_ADDR_SIZE DIALOG 0, 0, 186, 67 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Enter address and size" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_ADDRESS,99,6,80,14,ES_AUTOHSCROLL + EDITTEXT IDC_SIZE_CONTROL,99,26,80,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",ID_OK,34,46,50,14 + PUSHBUTTON "Cancel",ID_CANCEL,102,46,50,14 + LTEXT "Address:",IDC_STATIC,7,11,65,8 + LTEXT "Size:",IDC_STATIC,7,29,65,8 +END + +IDD_THROTTLE DIALOGEX 0, 0, 126, 60 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Throttle" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + EDITTEXT IDC_THROTTLE,6,18,114,12,ES_CENTER | ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",ID_OK,6,36,54,18 + PUSHBUTTON "Cancel",ID_CANCEL,66,36,54,18 + CTEXT "Enter desired throttle (5%...1000%):",IDC_STATIC,6,6,114,8 +END + +IDD_GB_DISASSEMBLE DIALOG 0, 0, 344, 225 +STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "GB Disassemble" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_ADDRESS,7,7,65,14,ES_UPPERCASE | ES_AUTOHSCROLL | WS_GROUP + DEFPUSHBUTTON "Go",IDC_GO,81,7,50,14 + LISTBOX IDC_DISASSEMBLE,7,25,222,161,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_TABSTOP + CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,191,71,10 + PUSHBUTTON "Refresh",IDC_REFRESH,100,204,50,14 + PUSHBUTTON "Next",IDC_NEXT,193,204,50,14 + PUSHBUTTON "Close",IDC_CLOSE,287,204,50,14 + LTEXT "AF:",IDC_STATIC,250,25,18,8 + LTEXT "BC:",IDC_STATIC,250,35,18,8 + LTEXT "DE:",IDC_STATIC,250,45,18,8 + LTEXT "HL:",IDC_STATIC,250,55,18,8 + LTEXT "IFF:",IDC_STATIC,250,85,18,8 + LTEXT "LY:",IDC_STATIC,272,95,18,8 + LTEXT "",IDC_R0,285,25,52,8,SS_NOPREFIX + LTEXT "",IDC_R1,285,35,52,8,SS_NOPREFIX + LTEXT "",IDC_R2,285,45,52,8,SS_NOPREFIX + LTEXT "",IDC_R3,285,55,52,8,SS_NOPREFIX + LTEXT "",IDC_R6,285,85,52,8,SS_NOPREFIX + LTEXT "",IDC_LY,285,95,52,8,SS_NOPREFIX + CONTROL "N",IDC_N,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,250,109,21,10 + CONTROL "Z",IDC_Z,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,250,97,21,10 + CONTROL "C",IDC_C,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,250,133,21,10 + CONTROL "H",IDC_H,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,250,121,21,10 + SCROLLBAR IDC_VSCROLL,229,25,10,161,SBS_VERT + PUSHBUTTON "Goto PC",IDC_GOPC,7,204,50,14 + LTEXT "SP:",IDC_STATIC,250,65,18,8 + LTEXT "",IDC_R4,285,65,52,8,SS_NOPREFIX + LTEXT "PC:",IDC_STATIC,250,75,18,8 + LTEXT "",IDC_R5,285,75,52,8,SS_NOPREFIX +END + +IDD_GB_OAM_VIEW DIALOG 0, 0, 234, 185 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "GB Oam Viewer" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_SPRITE,7,19,76,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER + SCROLLBAR IDC_SCROLLBAR,7,33,76,11 + CONTROL "Stretch to fit",IDC_STRETCH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,138,79,10 + PUSHBUTTON "&Refresh",IDC_REFRESH,7,164,50,14,WS_GROUP + PUSHBUTTON "&Save...",IDC_SAVE,91,164,50,14,WS_GROUP + PUSHBUTTON "&Close",IDC_CLOSE,177,164,50,14 + CONTROL "MapView",IDC_OAM_VIEW,"VbaBitmapControl",WS_GROUP | WS_TABSTOP,87,7,64,64 + CONTROL "Zoom",IDC_OAM_VIEW_ZOOM,"VbaZoomControl",WS_GROUP | WS_TABSTOP,163,7,64,64 + CONTROL "Color",IDC_COLOR,"VbaColorControl",WS_TABSTOP,87,79,48,47 + LTEXT "",IDC_POS,31,47,50,8,SS_NOPREFIX + LTEXT "",IDC_PALETTE,31,87,50,8,SS_NOPREFIX + LTEXT "",IDC_TILE,31,57,50,8,SS_NOPREFIX + LTEXT "",IDC_PRIO,31,67,50,8,SS_NOPREFIX + LTEXT "",IDC_OAP,31,77,50,8,SS_NOPREFIX + LTEXT "",IDC_FLAGS,31,97,50,8,SS_NOPREFIX + LTEXT "",IDC_R,145,88,50,8,SS_NOPREFIX + LTEXT "",IDC_G,145,100,50,8,SS_NOPREFIX + LTEXT "",IDC_B,145,112,50,8,SS_NOPREFIX + LTEXT "Pos:",IDC_STATIC,7,47,24,8 + LTEXT "Pal:",IDC_STATIC,7,87,24,8 + LTEXT "Tile:",IDC_STATIC,7,57,24,8 + LTEXT "Prio:",IDC_STATIC,7,67,24,8 + LTEXT "OAP:",IDC_STATIC,7,77,24,8 + LTEXT "Sprite:",IDC_STATIC,7,7,50,8 + LTEXT "Flags:",IDC_STATIC,7,97,24,8 + CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,150,71,10 + LTEXT "",IDC_BANK,31,107,50,8,SS_NOPREFIX + LTEXT "Bank:",IDC_STATIC,7,107,24,8 +END + +IDD_GB_TILE_VIEWER DIALOG 0, 0, 326, 238 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "GB Tile Viewer" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "0",IDC_BANK_0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,20,20,10 + CONTROL "1",IDC_BANK_1,"Button",BS_AUTORADIOBUTTON,13,30,20,10 + CONTROL "0x8000",IDC_CHARBASE_0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,57,39,10 + CONTROL "0x8800",IDC_CHARBASE_1,"Button",BS_AUTORADIOBUTTON,13,67,39,10 + CONTROL "Stretch to fit",IDC_STRETCH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,122,79,10 + PUSHBUTTON "Refresh",IDC_REFRESH,7,217,50,14,WS_GROUP + PUSHBUTTON "Save...",IDC_SAVE,138,217,50,14 + PUSHBUTTON "Close",IDC_CLOSE,269,217,50,14 + CONTROL "Custom1",IDC_TILE_VIEW,"VbaBitmapControl",WS_GROUP | WS_TABSTOP,191,7,128,128 + GROUPBOX "VRAM Bank",IDC_STATIC,7,7,66,38 + GROUPBOX "Char Base",IDC_STATIC,7,46,65,35 + CONTROL "Zoom",IDC_MAP_VIEW_ZOOM,"VbaZoomControl",WS_GROUP | WS_TABSTOP,7,147,64,64 + CONTROL "Color",IDC_COLOR,"VbaColorControl",WS_TABSTOP,98,156,48,47 + LTEXT "",IDC_R,156,164,50,8,SS_NOPREFIX + LTEXT "",IDC_G,156,176,50,8,SS_NOPREFIX + LTEXT "",IDC_B,156,188,50,8,SS_NOPREFIX + LTEXT "Palette:",IDC_STATIC,7,86,65,8 + CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,133,71,10 + LTEXT "Tile:",IDC_STATIC,79,14,41,8 + LTEXT "Address:",IDC_STATIC,79,26,41,8 + LTEXT "",IDC_TILE_NUMBER,135,14,50,8,SS_NOPREFIX + LTEXT "",IDC_ADDRESS,135,26,50,8,SS_NOPREFIX + CONTROL "Slider1",IDC_PALETTE_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,1,98,76,22 +END + +IDD_GB_MAP_VIEW DIALOG 0, 0, 322, 238 +STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "GB Map Viewer" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "0x8000",IDC_BANK_0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,22,39,10 + CONTROL "0x8800",IDC_BANK_1,"Button",BS_AUTORADIOBUTTON,13,36,39,10 + CONTROL "0x9800",IDC_BG0,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,63,39,10 + CONTROL "0x9C00",IDC_BG1,"Button",BS_AUTORADIOBUTTON,13,77,40,10 + CONTROL "Stretch to fit",IDC_STRETCH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,122,68,10 + PUSHBUTTON "&Refresh",IDC_REFRESH,25,217,50,14,WS_GROUP + PUSHBUTTON "&Save...",IDC_SAVE,88,217,50,14,WS_GROUP + PUSHBUTTON "&Close",IDC_CLOSE,155,217,50,14 + CONTROL "MapView",IDC_MAP_VIEW,"VbaBitmapControl",WS_GROUP | WS_TABSTOP,187,15,128,128 + CONTROL "Zoom",IDC_MAP_VIEW_ZOOM,"VbaZoomControl",WS_GROUP | WS_TABSTOP,7,148,64,64 + CONTROL "Color",IDC_COLOR,"VbaColorControl",WS_TABSTOP,187,164,48,47 + LTEXT "",IDC_R,245,173,50,8,SS_NOPREFIX + LTEXT "",IDC_G,245,185,50,8,SS_NOPREFIX + LTEXT "",IDC_B,245,197,50,8,SS_NOPREFIX + GROUPBOX "Char Base",IDC_STATIC,7,11,63,37 + GROUPBOX "Map Base",IDC_STATIC,7,52,63,41 + CONTROL "Auto update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,134,55,10 + LTEXT "",IDC_XY,129,18,53,8,SS_NOPREFIX + LTEXT "Priority:",IDC_STATIC,80,68,37,8 + LTEXT "",IDC_PRIORITY,130,68,53,8,SS_NOPREFIX + LTEXT "Address:",IDC_STATIC,80,28,37,8 + LTEXT "",IDC_ADDRESS,130,28,53,8,SS_NOPREFIX + LTEXT "Tile:",IDC_STATIC,80,38,37,8 + LTEXT "",IDC_TILE_NUM,130,38,53,8,SS_NOPREFIX + LTEXT "Flip:",IDC_STATIC,80,48,37,8 + LTEXT "",IDC_FLIP,130,48,53,8,SS_NOPREFIX + LTEXT "Palette:",IDC_STATIC,80,58,37,8 + LTEXT "",IDC_PALETTE_NUM,130,58,53,8,SS_NOPREFIX +END + +IDD_GB_PALETTE_VIEW DIALOG 0, 0, 196, 234 +STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "GB Palette Viewer" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Save BG...",IDC_SAVE_BG,7,191,50,14 + PUSHBUTTON "Save OBJ...",IDC_SAVE_OBJ,73,191,50,14 + PUSHBUTTON "&Refresh",IDC_REFRESH2,139,191,50,14 + PUSHBUTTON "&Close",IDC_CLOSE,73,213,50,14 + LTEXT "",IDC_ADDRESS,53,117,50,8,SS_NOPREFIX + LTEXT "",IDC_R,53,129,50,8,SS_NOPREFIX + LTEXT "",IDC_G,53,141,50,8,SS_NOPREFIX + LTEXT "",IDC_B,53,153,50,8,SS_NOPREFIX + LTEXT "",IDC_VALUE,53,165,50,8,SS_NOPREFIX + CONTROL "Custom1",IDC_COLOR,"VbaColorControl",WS_TABSTOP,119,117,50,50 + CONTROL "PaletteViewBG",IDC_PALETTE_VIEW,"VbaPaletteViewControl",WS_TABSTOP,11,30,64,64 + CONTROL "PaletteViewBG",IDC_PALETTE_VIEW_OBJ, + "VbaPaletteViewControl",WS_TABSTOP,120,30,64,64 + GROUPBOX "BG",IDC_STATIC,6,20,74,81 + GROUPBOX "Sprite",IDC_STATIC,115,20,74,81 + LTEXT "Index:",IDC_STATIC,7,117,38,8 + LTEXT "R:",IDC_STATIC,7,129,41,8 + LTEXT "G:",IDC_STATIC,7,141,43,8 + LTEXT "B:",IDC_STATIC,7,153,38,8 + LTEXT "Value:",IDC_STATIC,7,165,38,8 + LTEXT "Click on a color for more information",IDC_STATIC,7,7,182,8 + CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,178,71,10 +END + +IDD_REWIND_INTERVAL DIALOG 0, 0, 186, 68 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Select rewind interval" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_INTERVAL,7,28,172,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",ID_OK,37,47,50,14 + PUSHBUTTON "Cancel",ID_CANCEL,99,47,50,14 + LTEXT "Enter rewind interval (0...600) seconds:",IDC_STATIC,7,7,172,8 + LTEXT "Enter 0 to disable rewind.",IDC_STATIC,7,17,172,8 +END + +IDD_IO_VIEWER DIALOG 0, 0, 269, 238 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "I/O Viewer" +FONT 8, "MS Sans Serif" +BEGIN + COMBOBOX IDC_ADDRESSES,7,7,255,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + RTEXT "",IDC_VALUE,103,23,159,8 + CONTROL "",IDC_BIT_15,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,34,255,10 + CONTROL "",IDC_BIT_14,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,44,255,10 + CONTROL "",IDC_BIT_13,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,54,255,8 + CONTROL "",IDC_BIT_12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,64,255,10 + CONTROL "",IDC_BIT_11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,74,255,10 + CONTROL "",IDC_BIT_10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,84,255,10 + CONTROL "",IDC_BIT_9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,94,255,10 + CONTROL "",IDC_BIT_8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,104,255,10 + CONTROL "",IDC_BIT_7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,114,255,10 + CONTROL "",IDC_BIT_6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,124,255,10 + CONTROL "",IDC_BIT_5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,134,255,10 + CONTROL "",IDC_BIT_4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,144,255,10 + CONTROL "",IDC_BIT_3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,154,255,10 + CONTROL "",IDC_BIT_2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,164,255,10 + CONTROL "",IDC_BIT_1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,174,255,10 + CONTROL "",IDC_BIT_0,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,184,255,10 + CONTROL "Automatic update",IDC_AUTO_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,201,71,10 + DEFPUSHBUTTON "&Refresh",IDC_REFRESH,54,221,50,14 + DEFPUSHBUTTON "&Apply",IDC_APPLY,110,221,50,14 + PUSHBUTTON "&Close",IDC_CLOSE,166,221,50,14 + LTEXT "Value:",IDC_STATIC,7,23,72,8 +END + +IDD_MAX_SCALE DIALOG 0, 0, 186, 68 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Fullscreen scale" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_VALUE,7,28,172,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",ID_OK,37,47,50,14 + PUSHBUTTON "Cancel",ID_CANCEL,99,47,50,14 + LTEXT "Enter the maxium fullscreen scale:",IDC_STATIC,7,7,172,8 + LTEXT "Enter 0 to use maximum scale.",IDC_STATIC,7,17,172,8 +END + +IDD_GAME_OVERRIDES DIALOGEX 0, 0, 268, 132 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Game overrides" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_RTC,84,42,180,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_SAVE_TYPE,84,60,180,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FLASH_SIZE,84,78,180,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_MIRRORING,84,96,180,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "OK",IDOK,6,114,72,12 + PUSHBUTTON "Defaults",IDC_DEFAULTS,108,114,54,12 + PUSHBUTTON "Cancel",IDCANCEL,192,114,72,12 + LTEXT "Game Code",IDC_STATIC,6,6,72,12 + EDITTEXT IDC_NAME,84,6,180,12,ES_AUTOHSCROLL | WS_DISABLED + LTEXT "Real Time Clock:",IDC_STATIC,6,42,72,12 + LTEXT "Save Type:",IDC_STATIC,6,60,72,12 + LTEXT "Flash Size:",IDC_STATIC,6,78,72,12 + LTEXT "Mirroring:",IDC_STATIC,6,96,72,12 + LTEXT "Comment",IDC_STATIC,6,24,72,12 + EDITTEXT IDC_COMMENT,84,24,180,12,ES_AUTOHSCROLL +END + +IDD_BIOS DIALOGEX 0, 0, 220, 126 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "BIOS Files" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,84,102,60,18 + PUSHBUTTON "Cancel",IDCANCEL,150,102,60,18 + GROUPBOX "Game Boy mono",IDC_STATIC,6,6,210,30 + GROUPBOX "Game Boy Advance",IDC_STATIC,6,48,210,30 + EDITTEXT IDC_GB_BIOS_PATH,12,18,180,12,ES_AUTOHSCROLL + EDITTEXT IDC_GBA_BIOS_PATH,12,60,180,12,ES_AUTOHSCROLL + GROUPBOX "Options",IDC_STATIC,6,90,72,30 + CONTROL "Skip boot logo",IDC_SKIP_BOOT_LOGO,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,12,102,60,12 + CONTROL "Enable",IDC_ENABLE_GB_BIOS,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,174,6,36,8 + CONTROL "Enable",IDC_ENABLE_GBA_BIOS,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,174,48,36,8 + PUSHBUTTON "...",IDC_SELECT_GB_BIOS_PATH,192,18,18,12 + PUSHBUTTON "...",IDC_SELECT_GBA_BIOS_PATH,192,60,18,12 +END + +IDD_FULLSCREEN DIALOGEX 0, 0, 167, 96 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Fullscreen Settings" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,60,78,48,12 + PUSHBUTTON "Cancel",IDCANCEL,114,78,48,12 + COMBOBOX IDC_COMBO_RESOLUTION,60,42,102,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + RTEXT "Resolution:",IDC_STATIC,6,42,48,12 + RTEXT "Color depth:",IDC_STATIC,6,24,48,12 + COMBOBOX IDC_COMBO_COLOR_DEPTH,60,24,102,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + RTEXT "Refresh rate:",IDC_STATIC,6,60,48,12 + COMBOBOX IDC_COMBO_REFRESH_RATE,60,60,102,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_DEVICE,60,6,102,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + RTEXT "Device:",IDC_STATIC,6,6,48,12 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_OAL_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 160 + TOPMARGIN, 7 + BOTTOMMARGIN, 107 + END + + IDD_OPENDLG, DIALOG + BEGIN + RIGHTMARGIN, 165 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 172 + TOPMARGIN, 7 + BOTTOMMARGIN, 146 + END + + IDD_DIRECTORIES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 215 + TOPMARGIN, 7 + BOTTOMMARGIN, 263 + END + + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 441 + TOPMARGIN, 7 + BOTTOMMARGIN, 95 + END + + IDD_CHEATS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 269 + TOPMARGIN, 7 + BOTTOMMARGIN, 246 + END + + IDD_ADD_CHEAT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 130 + END + + IDD_CHEAT_LIST, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 273 + TOPMARGIN, 7 + BOTTOMMARGIN, 243 + END + + IDD_ASSOCIATIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 109 + TOPMARGIN, 7 + BOTTOMMARGIN, 88 + END + + IDD_GBA_ROM_INFO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 135 + END + + IDD_GB_ROM_INFO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 218 + END + + IDD_GB_CHEAT_LIST, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 279 + TOPMARGIN, 7 + BOTTOMMARGIN, 214 + END + + IDD_ADD_CHEAT_DLG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 175 + TOPMARGIN, 7 + BOTTOMMARGIN, 100 + END + + IDD_GB_PRINTER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 171 + TOPMARGIN, 7 + BOTTOMMARGIN, 202 + END + + IDD_MOTION_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 227 + TOPMARGIN, 7 + BOTTOMMARGIN, 100 + END + + IDD_LANG_SELECT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 61 + END + + IDD_CODE_SELECT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 309 + TOPMARGIN, 7 + BOTTOMMARGIN, 228 + END + + IDD_MAP_VIEW, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 315 + TOPMARGIN, 7 + BOTTOMMARGIN, 231 + END + + IDD_PALETTE_VIEW, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 309 + TOPMARGIN, 7 + BOTTOMMARGIN, 259 + END + + IDD_MEM_VIEWER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 373 + TOPMARGIN, 7 + BOTTOMMARGIN, 171 + END + + IDD_OAM_VIEW, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 227 + TOPMARGIN, 7 + BOTTOMMARGIN, 178 + END + + IDD_ACCEL_EDITOR, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 392 + TOPMARGIN, 7 + BOTTOMMARGIN, 114 + END + + IDD_TILE_VIEWER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 319 + TOPMARGIN, 7 + BOTTOMMARGIN, 259 + END + + IDD_GB_COLORS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 162 + TOPMARGIN, 7 + BOTTOMMARGIN, 114 + END + + IDD_DISASSEMBLE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 396 + TOPMARGIN, 7 + BOTTOMMARGIN, 218 + END + + IDD_GDB_PORT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 44 + END + + IDD_GDB_WAITING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 37 + END + + IDD_LOGGING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 359 + TOPMARGIN, 7 + BOTTOMMARGIN, 211 + END + + IDD_EXPORT_SPS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 241 + TOPMARGIN, 7 + BOTTOMMARGIN, 141 + END + + IDD_ADDR_SIZE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 60 + END + + IDD_THROTTLE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 119 + TOPMARGIN, 7 + BOTTOMMARGIN, 53 + END + + IDD_GB_DISASSEMBLE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 337 + TOPMARGIN, 7 + BOTTOMMARGIN, 218 + END + + IDD_GB_OAM_VIEW, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 227 + TOPMARGIN, 7 + BOTTOMMARGIN, 178 + END + + IDD_GB_TILE_VIEWER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 319 + TOPMARGIN, 7 + BOTTOMMARGIN, 231 + END + + IDD_GB_MAP_VIEW, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 315 + TOPMARGIN, 7 + BOTTOMMARGIN, 231 + END + + IDD_GB_PALETTE_VIEW, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 189 + TOPMARGIN, 7 + BOTTOMMARGIN, 227 + END + + IDD_REWIND_INTERVAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 61 + END + + IDD_IO_VIEWER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 262 + TOPMARGIN, 7 + BOTTOMMARGIN, 235 + END + + IDD_MAX_SCALE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 61 + END + + IDD_GAME_OVERRIDES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 261 + TOPMARGIN, 7 + BOTTOMMARGIN, 105 + END + + IDD_BIOS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 119 + END + + IDD_FULLSCREEN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 160 + TOPMARGIN, 7 + BOTTOMMARGIN, 89 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU MENU +BEGIN + POPUP "&File" + BEGIN + MENUITEM "Open GB...", ID_FILE_OPENGAMEBOY + MENUITEM "Open GBC...", ID_FILE_OPEN_GBC + MENUITEM "Open GBA...", ID_FILE_OPEN + MENUITEM SEPARATOR + MENUITEM "Load...", ID_FILE_LOAD + MENUITEM "Save...", ID_FILE_SAVE + POPUP "Load Game" + BEGIN + MENUITEM "Most recent", ID_FILE_LOADGAME_MOSTRECENT + MENUITEM "Auto load most recent", ID_FILE_LOADGAME_AUTOLOADMOSTRECENT + MENUITEM SEPARATOR + MENUITEM "Slot #1", ID_FILE_LOADGAME_SLOT1 + MENUITEM "Slot #2", ID_FILE_LOADGAME_SLOT2 + MENUITEM "Slot #3", ID_FILE_LOADGAME_SLOT3 + MENUITEM "Slot #4", ID_FILE_LOADGAME_SLOT4 + MENUITEM "Slot #5", ID_FILE_LOADGAME_SLOT5 + MENUITEM "Slot #6", ID_FILE_LOADGAME_SLOT6 + MENUITEM "Slot #7", ID_FILE_LOADGAME_SLOT7 + MENUITEM "Slot #8", ID_FILE_LOADGAME_SLOT8 + MENUITEM "Slot #9", ID_FILE_LOADGAME_SLOT9 + MENUITEM "Slot #10", ID_FILE_LOADGAME_SLOT10 + END + POPUP "Save Game" + BEGIN + MENUITEM "Oldest slot", ID_FILE_SAVEGAME_OLDESTSLOT + MENUITEM SEPARATOR + MENUITEM "Slot #1", ID_FILE_SAVEGAME_SLOT1 + MENUITEM "Slot #2", ID_FILE_SAVEGAME_SLOT2 + MENUITEM "Slot #3", ID_FILE_SAVEGAME_SLOT3 + MENUITEM "Slot #4", ID_FILE_SAVEGAME_SLOT4 + MENUITEM "Slot #5", ID_FILE_SAVEGAME_SLOT5 + MENUITEM "Slot #6", ID_FILE_SAVEGAME_SLOT6 + MENUITEM "Slot #7", ID_FILE_SAVEGAME_SLOT7 + MENUITEM "Slot #8", ID_FILE_SAVEGAME_SLOT8 + MENUITEM "Slot #9", ID_FILE_SAVEGAME_SLOT9 + MENUITEM "Slot #10", ID_FILE_SAVEGAME_SLOT10 + END + MENUITEM SEPARATOR + MENUITEM "Pause", ID_FILE_PAUSE + MENUITEM "Reset", ID_FILE_RESET + MENUITEM SEPARATOR + POPUP "Recent" + BEGIN + MENUITEM "&Reset", ID_FILE_RECENT_RESET + MENUITEM "&Freeze", ID_FILE_RECENT_FREEZE + MENUITEM SEPARATOR + END + MENUITEM SEPARATOR + POPUP "Import" + BEGIN + MENUITEM "&Battery file...", ID_FILE_IMPORT_BATTERYFILE + MENUITEM "Gameshark &code file...", ID_FILE_IMPORT_GAMESHARKCODEFILE + MENUITEM "&Gameshark Snapshot...", ID_FILE_IMPORT_GAMESHARKSNAPSHOT + END + POPUP "Export" + BEGIN + MENUITEM "&Battery file...", ID_FILE_EXPORT_BATTERYFILE + MENUITEM "&Gameshark Snapshot...", ID_FILE_EXPORT_GAMESHARKSNAPSHOT + END + MENUITEM SEPARATOR + MENUITEM "Screen Capture...", ID_FILE_SCREENCAPTURE + MENUITEM "ROM Information...", ID_FILE_ROMINFORMATION + MENUITEM "Toggle Fullscreen", ID_FILE_TOGGLEMENU + MENUITEM SEPARATOR + MENUITEM "Close", ID_FILE_CLOSE + MENUITEM SEPARATOR + MENUITEM "Exit", ID_FILE_EXIT + END + POPUP "&Options" + BEGIN + POPUP "&Video" + BEGIN + POPUP "Render API" + BEGIN + MENUITEM "Direct&3D", ID_OPTIONS_VIDEO_RENDERMETHOD_DIRECT3D + MENUITEM " Filter: Nearest", ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DNOFILTER + MENUITEM " Filter: Bilinear", ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DBILINEAR + MENUITEM " Motion Blur", ID_RENDERAPI_D3DMOTIONBLUR + MENUITEM SEPARATOR + MENUITEM "&OpenGL", ID_OPTIONS_VIDEO_RENDERMETHOD_OPENGL + MENUITEM " Filter: Nearest", ID_OPTIONS_VIDEO_RENDEROPTIONS_GLNEAREST + MENUITEM " Filter: Bilinear", ID_OPTIONS_VIDEO_RENDEROPTIONS_GLBILINEAR + MENUITEM SEPARATOR + MENUITEM "&VSync", ID_OPTIONS_VIDEO_VSYNC + MENUITEM "Triple Buffering", ID_OPTIONS_VIDEO_TRIPLEBUFFERING + END + MENUITEM SEPARATOR + POPUP "Windowed" + BEGIN + MENUITEM "&1x Size", ID_OPTIONS_VIDEO_X1 + MENUITEM "&2x Size", ID_OPTIONS_VIDEO_X2 + MENUITEM "&3x Size", ID_OPTIONS_VIDEO_X3 + MENUITEM "&4x Size", ID_OPTIONS_VIDEO_X4 + END + POPUP "Fullscreen" + BEGIN + MENUITEM "&Custom...", ID_OPTIONS_VIDEO_FULLSCREEN + MENUITEM SEPARATOR + MENUITEM "320x240x16", ID_OPTIONS_VIDEO_FULLSCREEN320X240 + MENUITEM "640x480x16", ID_OPTIONS_VIDEO_FULLSCREEN640X480 + MENUITEM "800x600x16", ID_OPTIONS_VIDEO_FULLSCREEN800X600 + MENUITEM "1024x768x16", ID_OPTIONS_VIDEO_FULLSCREEN1024X768 + MENUITEM "1280x1024x16", ID_OPTIONS_VIDEO_FULLSCREEN1280X1024 + MENUITEM SEPARATOR + MENUITEM "&Max Scale...", ID_OPTIONS_VIDEO_FULLSCREENMAXSCALE + MENUITEM "Stretch to &fit", ID_OPTIONS_VIDEO_FULLSCREENSTRETCHTOFIT + END + MENUITEM SEPARATOR + MENUITEM "D&isable status messages", ID_OPTIONS_EMULATOR_DISABLESTATUSMESSAGES + END + POPUP "&Pixel Filter" + BEGIN + MENUITEM "&Disable Filters", ID_OPTIONS_FILTER_NORMAL + POPUP "&Magnification" + BEGIN + POPUP "&2X" + BEGIN + MENUITEM "&Simple 2x", ID_OPTIONS_FILTER16BIT_SIMPLE2X + MENUITEM SEPARATOR + MENUITEM "&Pixelate", ID_OPTIONS_FILTER16BIT_PIXELATEEXPERIMENTAL + MENUITEM "&TV Mode", ID_OPTIONS_FILTER_TVMODE + MENUITEM "Scan&lines", ID_OPTIONS_FILTER_SCANLINES + MENUITEM SEPARATOR + MENUITEM "&Bilinear", ID_OPTIONS_FILTER_BILINEAR + MENUITEM "B&ilinear Plus", ID_OPTIONS_FILTER_BILINEARPLUS + MENUITEM SEPARATOR + MENUITEM "AdvanceMAME Scale2x", ID_OPTIONS_FILTER16BIT_ADVANCEMAMESCALE2X + MENUITEM "&2xSaI", ID_OPTIONS_FILTER_2XSAI + MENUITEM "S&uper 2xSaI", ID_OPTIONS_FILTER_SUPER2XSAI + MENUITEM "Super &Eagle", ID_OPTIONS_FILTER_SUPEREAGLE + MENUITEM "&LQ2x", ID_OPTIONS_FILTER_LQ2X + MENUITEM "&HQ2x", ID_OPTIONS_FILTER_HQ2X + END + POPUP "&3X" + BEGIN + MENUITEM "&Simple 3x", ID_OPTIONS_FILTER_SIMPLE3X + MENUITEM SEPARATOR + MENUITEM "&HQ3x", ID_OPTIONS_FILTER_HQ3X + END + POPUP "&4X" + BEGIN + MENUITEM "&Simple 4x", ID_OPTIONS_FILTER_SIMPLE4X + MENUITEM SEPARATOR + MENUITEM "&HQ4x", ID_OPTIONS_FILTER_HQ4X + END + END + MENUITEM SEPARATOR + MENUITEM "&Use Filter Plugin", ID_OPTIONS_FILTER_PLUGIN + MENUITEM "Select Filter &Plugin ...", ID_OPTIONS_SELECT_PLUGIN + MENUITEM SEPARATOR + POPUP "&Interframe Blending" + BEGIN + MENUITEM "&None", ID_OPTIONS_FILTER_INTERFRAMEBLENDING_NONE + MENUITEM "&Motion Blur", ID_OPTIONS_FILTER_INTERFRAMEBLENDING_MOTIONBLUR + MENUITEM "&Smart", ID_OPTIONS_FILTER_INTERFRAMEBLENDING_SMART + END + MENUITEM SEPARATOR + MENUITEM "Disable &MMX", ID_OPTIONS_FILTER_DISABLEMMX + END + POPUP "&Audio" + BEGIN + POPUP "Output API" + BEGIN + MENUITEM "DirectSound", ID_OUTPUTAPI_DIRECTSOUND + MENUITEM SEPARATOR + MENUITEM "OpenAL", ID_OUTPUTAPI_OPENAL + MENUITEM " Configuration...", ID_OUTPUTAPI_OALCONFIGURATION + MENUITEM SEPARATOR + MENUITEM "&Sync game to audio", ID_OPTIONS_EMULATOR_SYNCHRONIZE + END + MENUITEM SEPARATOR + MENUITEM "&On", ID_OPTIONS_SOUND_ON + MENUITEM "O&ff", ID_OPTIONS_SOUND_OFF + MENUITEM SEPARATOR + POPUP "&Volume" + BEGIN + MENUITEM "&Mute", ID_OPTIONS_SOUND_MUTE + MENUITEM SEPARATOR + MENUITEM "2&5%", ID_OPTIONS_SOUND_VOLUME_25X + MENUITEM "5&0%", ID_OPTIONS_SOUND_VOLUME_5X + MENUITEM "&100%", ID_OPTIONS_SOUND_VOLUME_1X + MENUITEM "&200%", ID_OPTIONS_SOUND_VOLUME_2X + MENUITEM "&300%", ID_OPTIONS_SOUND_VOLUME_3X + MENUITEM "&400%", ID_OPTIONS_SOUND_VOLUME_4X + END + POPUP "Sampling Rate" + BEGIN + MENUITEM "&11025 Hz", ID_OPTIONS_SOUND_11KHZ + MENUITEM "&22050 Hz", ID_OPTIONS_SOUND_22KHZ + MENUITEM "&44100 Hz", ID_OPTIONS_SOUND_44KHZ + END + POPUP "PCM interpolation" + BEGIN + MENUITEM "On", ID_OPTIONS_SOUND_PCMINTERPOLATION_LINEAR + MENUITEM "Off", ID_OPTIONS_SOUND_PCMINTERPOLATION_NONE + END + MENUITEM SEPARATOR + MENUITEM "&Echo", ID_OPTIONS_SOUND_ECHO + MENUITEM SEPARATOR + POPUP "Sound Channels" + BEGIN + MENUITEM "Channel &1", ID_OPTIONS_SOUND_CHANNEL1, CHECKED + MENUITEM "Channel &2", ID_OPTIONS_SOUND_CHANNEL2, CHECKED + MENUITEM "Channel &3", ID_OPTIONS_SOUND_CHANNEL3, CHECKED + MENUITEM "Channel &4", ID_OPTIONS_SOUND_CHANNEL4, CHECKED + MENUITEM "Direct Sound &A", ID_OPTIONS_SOUND_DIRECTSOUNDA, CHECKED + MENUITEM "Direct Sound &B", ID_OPTIONS_SOUND_DIRECTSOUNDB, CHECKED + END + END + POPUP "&Input" + BEGIN + POPUP "&Set" + BEGIN + MENUITEM "Config &1...", ID_OPTIONS_JOYPAD_CONFIGURE_1 + MENUITEM "Config &2...", ID_OPTIONS_JOYPAD_CONFIGURE_2 + MENUITEM "Config &3...", ID_OPTIONS_JOYPAD_CONFIGURE_3 + MENUITEM "Config &4...", ID_OPTIONS_JOYPAD_CONFIGURE_4 + MENUITEM SEPARATOR + MENUITEM "&Motion...", ID_OPTIONS_JOYPAD_MOTIONCONFIGURE + END + POPUP "&Use" + BEGIN + MENUITEM "Config &1", ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_1 + MENUITEM "Config &2", ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_2 + MENUITEM "Config &3", ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_3 + MENUITEM "Config &4", ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_4 + END + MENUITEM SEPARATOR + POPUP "&Autofire" + BEGIN + MENUITEM "&A", ID_OPTIONS_JOYPAD_AUTOFIRE_A + MENUITEM "&B", ID_OPTIONS_JOYPAD_AUTOFIRE_B + MENUITEM "&L", ID_OPTIONS_JOYPAD_AUTOFIRE_L + MENUITEM "&R", ID_OPTIONS_JOYPAD_AUTOFIRE_R + END + MENUITEM "Rewind interval...", ID_OPTIONS_EMULATOR_REWINDINTERVAL + END + POPUP "&Speed" + BEGIN + POPUP "&Throttle" + BEGIN + MENUITEM "25%", ID_OPTIONS_FRAMESKIP_THROTTLE_25 + MENUITEM "50%", ID_OPTIONS_FRAMESKIP_THROTTLE_50 + MENUITEM "100%", ID_OPTIONS_FRAMESKIP_THROTTLE_100 + MENUITEM "150%", ID_OPTIONS_FRAMESKIP_THROTTLE_150 + MENUITEM "200%", ID_OPTIONS_FRAMESKIP_THROTTLE_200 + MENUITEM "&Other...", ID_OPTIONS_FRAMESKIP_THROTTLE_OTHER + MENUITEM "No throttle", ID_OPTIONS_FRAMESKIP_THROTTLE_NOTHROTTLE + END + MENUITEM SEPARATOR + POPUP "&Frame Skip" + BEGIN + MENUITEM "&No frame skip", ID_OPTIONS_VIDEO_FRAMESKIP_0 + MENUITEM "&1 frame", ID_OPTIONS_VIDEO_FRAMESKIP_1 + MENUITEM "&2 frames", ID_OPTIONS_VIDEO_FRAMESKIP_2 + MENUITEM "&3 frames", ID_OPTIONS_VIDEO_FRAMESKIP_3 + MENUITEM "&4 frames", ID_OPTIONS_VIDEO_FRAMESKIP_4 + MENUITEM "&5 frames", ID_OPTIONS_VIDEO_FRAMESKIP_5 + MENUITEM "&6 frames", ID_OPTIONS_VIDEO_FRAMESKIP_6 + MENUITEM "&7 frames", ID_OPTIONS_VIDEO_FRAMESKIP_7 + MENUITEM "&8 frames", ID_OPTIONS_VIDEO_FRAMESKIP_8 + MENUITEM "&9 frames", ID_OPTIONS_VIDEO_FRAMESKIP_9 + END + MENUITEM "Turbo mode", ID_OPTIONS_EMULATOR_SPEEDUPTOGGLE + END + MENUITEM SEPARATOR + POPUP "&Emulator" + BEGIN + MENUITEM "&Associate...", ID_OPTIONS_EMULATOR_ASSOCIATE + MENUITEM "&Directories...", ID_OPTIONS_EMULATOR_DIRECTORIES + MENUITEM "BIOS Files...", ID_EMULATOR_BIOSFILES + POPUP "&Priority" + BEGIN + MENUITEM "&Highest", ID_OPTIONS_PRIORITY_HIGHEST + MENUITEM "&Above Normal", ID_OPTIONS_PRIORITY_ABOVENORMAL + MENUITEM "&Normal", ID_OPTIONS_PRIORITY_NORMAL + MENUITEM "&Below Normal", ID_OPTIONS_PRIORITY_BELOWNORMAL + END + MENUITEM "&Remove intros (GBA)", ID_OPTIONS_EMULATOR_REMOVEINTROSGBA + MENUITEM "Automatic IPS patching", ID_OPTIONS_EMULATOR_AUTOMATICALLYIPSPATCH + MENUITEM "Pause when inactive", ID_OPTIONS_EMULATOR_PAUSEWHENINACTIVE + MENUITEM "AGB Print", ID_OPTIONS_EMULATOR_AGBPRINT + MENUITEM "Real Time Clock", ID_OPTIONS_EMULATOR_REALTIMECLOCK + MENUITEM "&Game Overrides...", ID_OPTIONS_EMULATOR_GAMEOVERRIDES + POPUP "Show speed" + BEGIN + MENUITEM "None", ID_OPTIONS_EMULATOR_SHOWSPEED_NONE + MENUITEM "Percentage", ID_OPTIONS_EMULATOR_SHOWSPEED_PERCENTAGE + MENUITEM "Detailed", ID_OPTIONS_EMULATOR_SHOWSPEED_DETAILED + MENUITEM SEPARATOR + MENUITEM "Transparent", ID_OPTIONS_EMULATOR_SHOWSPEED_TRANSPARENT + END + POPUP "Save Type" + BEGIN + MENUITEM "&Automatic", ID_OPTIONS_EMULATOR_SAVETYPE_AUTOMATIC + MENUITEM "EEPROM", ID_OPTIONS_EMULATOR_SAVETYPE_EEPROM + MENUITEM "SRAM", ID_OPTIONS_EMULATOR_SAVETYPE_SRAM + MENUITEM "Flash", ID_OPTIONS_EMULATOR_SAVETYPE_FLASH + MENUITEM "EEPROM+Sensor", ID_OPTIONS_EMULATOR_SAVETYPE_EEPROMSENSOR + MENUITEM "None", ID_OPTIONS_EMULATOR_SAVETYPE_NONE + MENUITEM SEPARATOR + MENUITEM "Flash 64 KB", ID_OPTIONS_EMULATOR_SAVETYPE_FLASH512K + MENUITEM "Flash 128 KB", ID_OPTIONS_EMULATOR_SAVETYPE_FLASH1M + END + POPUP "Screenshot &Format" + BEGIN + MENUITEM "&PNG", ID_OPTIONS_EMULATOR_PNGFORMAT + MENUITEM "&BMP", ID_OPTIONS_EMULATOR_BMPFORMAT + END + MENUITEM SEPARATOR + POPUP "UI &Language" + BEGIN + MENUITEM "&System", ID_OPTIONS_LANGUAGE_SYSTEM + MENUITEM "&English", ID_OPTIONS_LANGUAGE_ENGLISH + MENUITEM "&Other...", ID_OPTIONS_LANGUAGE_OTHER + END + END + POPUP "&Gameboy" + BEGIN + MENUITEM "&Border", ID_OPTIONS_GAMEBOY_BORDER + MENUITEM "&Printer", ID_OPTIONS_GAMEBOY_PRINTER + MENUITEM "Border Automatic", ID_OPTIONS_GAMEBOY_BORDERAUTOMATIC + MENUITEM SEPARATOR + MENUITEM "&Automatic", ID_OPTIONS_GAMEBOY_AUTOMATIC + MENUITEM "&GBA", ID_OPTIONS_GAMEBOY_GBA + MENUITEM "&CGB/GBC", ID_OPTIONS_GAMEBOY_CGB + MENUITEM "&SGB", ID_OPTIONS_GAMEBOY_SGB + MENUITEM "SGB&2", ID_OPTIONS_GAMEBOY_SGB2 + MENUITEM "G&B", ID_OPTIONS_GAMEBOY_GB + MENUITEM SEPARATOR + MENUITEM "&Real Colors", ID_OPTIONS_GAMEBOY_REALCOLORS + MENUITEM "G&ameboy Colors", ID_OPTIONS_GAMEBOY_GAMEBOYCOLORS + MENUITEM "LCD colors", ID_OPTIONS_FILTER_LCDCOLORS + MENUITEM SEPARATOR + MENUITEM "&Colors...", ID_OPTIONS_GAMEBOY_COLORS + END + POPUP "&Link", GRAYED + BEGIN + MENUITEM "Enable GBA Linking", ID_OPTIONS_LINK_ENABLE + MENUITEM "&Wireless Adapter", ID_OPTIONS_LINK_WIRELESSADAPTER + MENUITEM "&Log", ID_OPTIONS_LINK_LOG + MENUITEM "&Options...", ID_OPTIONS_LINK_OPTIONS + END + END + POPUP "&Cheats" + BEGIN + MENUITEM "&Search for cheats...", ID_CHEATS_SEARCHFORCHEATS + MENUITEM "&Cheat list...", ID_CHEATS_CHEATLIST + MENUITEM SEPARATOR + MENUITEM "&Automatic save/load cheats", ID_CHEATS_AUTOMATICSAVELOADCHEATS + MENUITEM "Disable cheats", ID_CHEATS_DISABLECHEATS + MENUITEM "&Load cheat list...", ID_CHEATS_LOADCHEATLIST + MENUITEM "Sa&ve cheat list...", ID_CHEATS_SAVECHEATLIST + END + POPUP "&Tools" + BEGIN + MENUITEM "Disassemble...", ID_TOOLS_DISASSEMBLE + MENUITEM "Logging...", ID_TOOLS_LOGGING + MENUITEM "&IO Viewer...", ID_TOOLS_IOVIEWER + MENUITEM "&Map Viewer...", ID_TOOLS_MAPVIEW + MENUITEM "&Memory viewer...", ID_TOOLS_MEMORYVIEWER + MENUITEM "OAM Viewer...", ID_TOOLS_OAMVIEWER + MENUITEM "&Palette Viewer...", ID_TOOLS_PALETTEVIEW + MENUITEM "Tile Viewer...", ID_TOOLS_TILEVIEWER + MENUITEM SEPARATOR + MENUITEM "&Next frame", ID_DEBUG_NEXTFRAME + POPUP "GDB" + BEGIN + MENUITEM "Wait for connection...", ID_TOOLS_DEBUG_GDB + MENUITEM "Load and wait...", ID_TOOLS_DEBUG_LOADANDWAIT + MENUITEM "Break into GDB", ID_TOOLS_DEBUG_BREAK + MENUITEM "Disconnect", ID_TOOLS_DEBUG_DISCONNECT + END + MENUITEM SEPARATOR + POPUP "Record" + BEGIN + MENUITEM "Start sound recording...", ID_OPTIONS_SOUND_STARTRECORDING + MENUITEM "Stop sound recording", ID_OPTIONS_SOUND_STOPRECORDING + MENUITEM "Start AVI recording...", ID_TOOLS_RECORD_STARTAVIRECORDING + MENUITEM "Stop AVI recording", ID_TOOLS_RECORD_STOPAVIRECORDING + MENUITEM "Start movie recording...", ID_TOOLS_RECORD_STARTMOVIERECORDING + MENUITEM "Stop movie recording", ID_TOOLS_RECORD_STOPMOVIERECORDING + END + POPUP "Play" + BEGIN + MENUITEM "Start playing movie...", ID_TOOLS_PLAY_STARTMOVIEPLAYING + MENUITEM "Stop playing movie", ID_TOOLS_PLAY_STOPMOVIEPLAYING + END + MENUITEM SEPARATOR + MENUITEM "Rewind", ID_TOOLS_REWIND + MENUITEM "Customize...", ID_TOOLS_CUSTOMIZE + END + POPUP "&Help" + BEGIN + MENUITEM "VBA-M Help", ID_HELP_FAQ + MENUITEM "VBA-M Support Forum", ID_HELP_BUGREPORT + MENUITEM "License...", ID_HELP_GNUPUBLICLICENSE + MENUITEM SEPARATOR + MENUITEM "&About VBA-M...", ID_HELP_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCELERATOR ACCELERATORS +BEGIN + "C", ID_CHEATS_SEARCHFORCHEATS, VIRTKEY, CONTROL, NOINVERT + "N", ID_DEBUG_NEXTFRAME, VIRTKEY, CONTROL, NOINVERT + "X", ID_FILE_EXIT, VIRTKEY, CONTROL, NOINVERT + "L", ID_FILE_LOAD, VIRTKEY, CONTROL, NOINVERT + VK_F1, ID_FILE_LOADGAME_SLOT1, VIRTKEY, NOINVERT + VK_F10, ID_FILE_LOADGAME_SLOT10, VIRTKEY, NOINVERT + VK_F2, ID_FILE_LOADGAME_SLOT2, VIRTKEY, NOINVERT + VK_F3, ID_FILE_LOADGAME_SLOT3, VIRTKEY, NOINVERT + VK_F4, ID_FILE_LOADGAME_SLOT4, VIRTKEY, NOINVERT + VK_F5, ID_FILE_LOADGAME_SLOT5, VIRTKEY, NOINVERT + VK_F6, ID_FILE_LOADGAME_SLOT6, VIRTKEY, NOINVERT + VK_F7, ID_FILE_LOADGAME_SLOT7, VIRTKEY, NOINVERT + VK_F8, ID_FILE_LOADGAME_SLOT8, VIRTKEY, NOINVERT + VK_F9, ID_FILE_LOADGAME_SLOT9, VIRTKEY, NOINVERT + VK_F1, ID_FILE_MRU_FILE1, VIRTKEY, CONTROL, NOINVERT + VK_F10, ID_FILE_MRU_FILE10, VIRTKEY, CONTROL, NOINVERT + VK_F2, ID_FILE_MRU_FILE2, VIRTKEY, CONTROL, NOINVERT + VK_F3, ID_FILE_MRU_FILE3, VIRTKEY, CONTROL, NOINVERT + VK_F4, ID_FILE_MRU_FILE4, VIRTKEY, CONTROL, NOINVERT + VK_F5, ID_FILE_MRU_FILE5, VIRTKEY, CONTROL, NOINVERT + VK_F6, ID_FILE_MRU_FILE6, VIRTKEY, CONTROL, NOINVERT + VK_F7, ID_FILE_MRU_FILE7, VIRTKEY, CONTROL, NOINVERT + VK_F8, ID_FILE_MRU_FILE8, VIRTKEY, CONTROL, NOINVERT + VK_F9, ID_FILE_MRU_FILE9, VIRTKEY, CONTROL, NOINVERT + "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT + "P", ID_FILE_PAUSE, VIRTKEY, CONTROL, NOINVERT + VK_PAUSE, ID_FILE_PAUSE, VIRTKEY, NOINVERT + "R", ID_FILE_RESET, VIRTKEY, CONTROL, NOINVERT + "S", ID_FILE_SAVE, VIRTKEY, CONTROL, NOINVERT + VK_F1, ID_FILE_SAVEGAME_SLOT1, VIRTKEY, SHIFT, NOINVERT + VK_F10, ID_FILE_SAVEGAME_SLOT10, VIRTKEY, SHIFT, NOINVERT + VK_F2, ID_FILE_SAVEGAME_SLOT2, VIRTKEY, SHIFT, NOINVERT + VK_F3, ID_FILE_SAVEGAME_SLOT3, VIRTKEY, SHIFT, NOINVERT + VK_F4, ID_FILE_SAVEGAME_SLOT4, VIRTKEY, SHIFT, NOINVERT + VK_F5, ID_FILE_SAVEGAME_SLOT5, VIRTKEY, SHIFT, NOINVERT + VK_F6, ID_FILE_SAVEGAME_SLOT6, VIRTKEY, SHIFT, NOINVERT + VK_F7, ID_FILE_SAVEGAME_SLOT7, VIRTKEY, SHIFT, NOINVERT + VK_F8, ID_FILE_SAVEGAME_SLOT8, VIRTKEY, SHIFT, NOINVERT + VK_F9, ID_FILE_SAVEGAME_SLOT9, VIRTKEY, SHIFT, NOINVERT + VK_ESCAPE, ID_FILE_TOGGLEMENU, VIRTKEY, NOINVERT + "1", ID_OPTIONS_JOYPAD_AUTOFIRE_A, VIRTKEY, ALT, NOINVERT + "2", ID_OPTIONS_JOYPAD_AUTOFIRE_B, VIRTKEY, ALT, NOINVERT + "3", ID_OPTIONS_JOYPAD_AUTOFIRE_L, VIRTKEY, ALT, NOINVERT + "4", ID_OPTIONS_JOYPAD_AUTOFIRE_R, VIRTKEY, ALT, NOINVERT + "1", ID_OPTIONS_VIDEO_LAYERS_BG0, VIRTKEY, CONTROL, NOINVERT + "2", ID_OPTIONS_VIDEO_LAYERS_BG1, VIRTKEY, CONTROL, NOINVERT + "3", ID_OPTIONS_VIDEO_LAYERS_BG2, VIRTKEY, CONTROL, NOINVERT + "4", ID_OPTIONS_VIDEO_LAYERS_BG3, VIRTKEY, CONTROL, NOINVERT + "5", ID_OPTIONS_VIDEO_LAYERS_OBJ, VIRTKEY, CONTROL, NOINVERT + "8", ID_OPTIONS_VIDEO_LAYERS_OBJWIN, VIRTKEY, CONTROL, NOINVERT + "6", ID_OPTIONS_VIDEO_LAYERS_WIN0, VIRTKEY, CONTROL, NOINVERT + "7", ID_OPTIONS_VIDEO_LAYERS_WIN1, VIRTKEY, CONTROL, NOINVERT + "B", ID_TOOLS_REWIND, VIRTKEY, CONTROL, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_UNSUPPORTED_VBA_SGM "Unsupported VisualBoyAdvance save game version %d" + IDS_CANNOT_LOAD_SGM "Cannot load save game for %s" + IDS_SAVE_GAME_NOT_USING_BIOS "Save game is not using the BIOS file" + IDS_SAVE_GAME_USING_BIOS "Save game is using the BIOS file" + IDS_UNSUPPORTED_SAVE_TYPE "Unsupported save type %d" + IDS_CANNOT_OPEN_FILE "Cannot open file %s" + IDS_BAD_ZIP_FILE "Bad ZIP file %s" + IDS_NO_IMAGE_ON_ZIP "No image found on ZIP file %s" + IDS_ERROR_OPENING_IMAGE "Error opening image %s" + IDS_ERROR_READING_IMAGE "Error reading image %s" + IDS_UNSUPPORTED_BIOS_FUNCTION + "Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour." + IDS_INVALID_BIOS_FILE_SIZE "Invalid BIOS file size" + IDS_INVALID_CHEAT_CODE "Invalid cheat code '%s'. Supported formats are:\nXXXXXXXX:YY, XXXXXXXX:YYYY, XXXXXXXX:YYYYYYYY." + IDS_UNKNOWN_ARM_OPCDOE "Unimplemented opcode %08x from %08x" + IDS_UNKNOWN_THUMB_OPCODE "Unknown opcode %04x from %08x" +END + +STRINGTABLE +BEGIN + IDS_ERROR_CREATING_FILE "Error creating file %s" + IDS_FAILED_TO_READ_SGM "Battery file's size incompatible with the ROM settings %s (%d).\nWarning : save of the battery file is now disabled !" + IDS_FAILED_TO_READ_RTC "Failed to read RTC from save game %s (continuing)" + IDS_UNSUPPORTED_VB_SGM "Unsupported VisualBoy save game version %d" + IDS_CANNOT_LOAD_SGM_FOR "Cannot load save game for %s. Playing %s" + IDS_ERROR_OPENING_IMAGE_FROM "Error opening image %s from zip file %s" + IDS_ERROR_READING_IMAGE_FROM "Error reading image %s from zip file %s" + IDS_UNSUPPORTED_ROM_SIZE "Unsupported rom size %02x" + IDS_UNSUPPORTED_RAM_SIZE "Unsupported ram size %02x" + IDS_UNKNOWN_CARTRIDGE_TYPE "Unknown cartridge type %02x" + IDS_MAXIMUM_NUMBER_OF_CHEATS "Maximum number of cheats reached." + IDS_INVALID_GAMESHARK_CODE "Invalid GameShark code: %s" + IDS_INVALID_GAMEGENIE_CODE "Invalid GameGenie code: %s" + IDS_INVALID_CHEAT_TO_REMOVE "Invalid cheat to remove %d" + IDS_INVALID_CHEAT_CODE_ADDRESS "Invalid cheat code address: %08x" + IDS_UNSUPPORTED_CHEAT_LIST_VERSION "Unsupported cheat list version %d" +END + +STRINGTABLE +BEGIN + IDS_DIRECTX_7_REQUIRED "DirectX 7.0 or greater is required to run.\nDownload at http://www.microsoft.com/directx.\n\nError found at: %s" + IDS_DISABLING_VIDEO_MEMORY "Disabling Use Video Memory setting" + IDS_SETTING_WILL_BE_EFFECTIVE + "Setting will be effective the next time you start the emulator" + IDS_DISABLING_EMULATION_ONLY "Disabling Emulation Only setting" + IDS_FAILED_TO_OPEN_FILE "Failed to open file %s" + IDS_FAILED_TO_READ_ZIP_DIR "Failed to read zip directory for file %s" + IDS_UNSUPPORTED_FILE_TYPE "Unsupported file type: %s" + IDS_CANNOT_CREATE_DIRECTSOUND "Cannot create DirectSound %08x" + IDS_CANNOT_SETCOOPERATIVELEVEL "Cannot SetCooperativeLevel %08x" + IDS_CANNOT_CREATESOUNDBUFFER "Cannot CreateSoundBuffer %08x" + IDS_CANNOT_SETFORMAT_PRIMARY "Cannot SetFormat for primary %08x" + IDS_CANNOT_CREATESOUNDBUFFER_SEC "Cannot CreateSoundBuffer secondary %08x" + IDS_CANNOT_PLAY_PRIMARY "Cannot Play primary %08x" + IDS_SEARCH_PRODUCED_TOO_MANY + "Search produced %d results. Please refine better" + IDS_NUMBER_CANNOT_BE_EMPTY "Number cannot be empty" + IDS_INVALID_ADDRESS "Invalid address: %08x" +END + +STRINGTABLE +BEGIN + IDS_MISALIGNED_HALFWORD "Misaligned half-word address: %08x" + IDS_MISALIGNED_WORD "Misaligned word address: %08x" + IDS_VALUE_CANNOT_BE_EMPTY "Value cannot be empty" + IDS_ERROR_ON_STARTDOC "Error on StartDoc" + IDS_ERROR_ON_STARTPAGE "Error on StartPage" + IDS_ERROR_PRINTING_ON_STRETCH "Error printing on StretchDIBits" + IDS_ERROR_ON_ENDPAGE "Error on EndPage" + IDS_ERROR_ON_ENDDOC "Error on EndDoc" + IDS_ERROR "Error" + IDS_JOY_LEFT "Joy %d Left" + IDS_JOY_RIGHT "Joy %d Right" + IDS_JOY_UP "Joy %d Up" + IDS_JOY_DOWN "Joy %d Down" + IDS_JOY_BUTTON "Joy %d %s" + IDS_SELECT_ROM_DIR "Select ROM directory:" + IDS_SELECT_BATTERY_DIR "Select Battery directory:" +END + +STRINGTABLE +BEGIN + IDS_SELECT_SAVE_DIR "Select Save Directory:" + IDS_SELECT_CAPTURE_DIR "Select Capture directory:" + IDS_RESET "Reset" + IDS_AUTOFIRE_A_DISABLED "autofire A disabled" + IDS_AUTOFIRE_A "autofire A" + IDS_AUTOFIRE_B_DISABLED "autofire B disabled" + IDS_AUTOFIRE_B "autofire B" + IDS_AUTOFIRE_L_DISABLED "autofire L disabled" + IDS_AUTOFIRE_L "autofire L" + IDS_AUTOFIRE_R_DISABLED "autofire R disabled" + IDS_AUTOFIRE_R "autofire R" + IDS_SELECT_ROM "Select ROM" + IDS_SELECT_SAVE_GAME_NAME "Select save game name" + IDS_LOADED_STATE "Loaded state" + IDS_LOADED_STATE_N "Loaded state %d" +END + +STRINGTABLE +BEGIN + IDS_WROTE_STATE "Wrote state" + IDS_WROTE_STATE_N "Wrote state %d" + IDS_LOADED_BATTERY "Loaded battery" + IDS_SELECT_CAPTURE_NAME "Select screen capture name" + IDS_SCREEN_CAPTURE "Screen capture" + IDS_ADDRESS "Address" + IDS_OLD_VALUE "Old Value" + IDS_NEW_VALUE "New Value" + IDS_ADD_CHEAT_CODE "Add cheat code" + IDS_CODE "Code" + IDS_DESCRIPTION "Description" + IDS_STATUS "Status" + IDS_ADD_GG_CODE "Add GameGenie code" + IDS_ADD_GS_CODE "Add GameShark code" + IDS_POCKET_PRINTER "Pocket Printer" + IDS_UNKNOWN "Unknown" +END + +STRINGTABLE +BEGIN + IDS_NONE "None" + IDS_FAILED_TO_LOAD_LIBRARY "Failed to load library %s" + IDS_FAILED_TO_GET_LOCINFO "Failed to get locale information" + IDS_SELECT_CHEAT_LIST_NAME "Select cheat list name" + IDS_FILTER_ROM "Game Boy Advance ROMs_*.GBA;*.AGB;*.BIN;*.ELF;*.MB;*.ZIP;*.7Z;*.Z;*.GZ__" + IDS_FILTER_SGM "VisualBoyAdvance Save Game_*.SGM__" + IDS_FILTER_CHEAT_LIST "VisualBoyAdvance Cheat List_*.CLT__" + IDS_FILTER_PNG "PNG Image_*.PNG_BMP Image_*.BMP__" + IDS_LOADED_CHEATS "Loaded cheats" + IDS_ERROR_DISP_COLOR "Unsupported display setting for color depth: %d bits. \nWindows desktop must be in either 16-bit, 24-bit or 32-bit mode for this program to work in window mode." + IDS_ADD_GSA_CODE "Add GameSharkAdvance code" + IDS_FILTER_SPS "Gameshark Snapshot_*.SPS__" + IDS_SELECT_SNAPSHOT_FILE "Select snapshot file" + IDS_FILTER_SAV "Battery file_*.SAV_Flash save_*.DAT__" + IDS_SELECT_BATTERY_FILE "Select battery file" +END + +STRINGTABLE +BEGIN + IDS_UNSUPPORTED_CHEAT_LIST_TYPE "Unsupported cheat list type %d" + IDS_INVALID_GSA_CODE "Invalid GSA code. Format is XXXXXXXXYYYYYYYY." + IDS_CANNOT_IMPORT_SNAPSHOT_FOR + "Cannot import snapshot for %s. Current game is %s" + IDS_UNSUPPORTED_SNAPSHOT_FILE "Unsupported snapshot file %s" + IDS_UNSUPPORTED_ARM_MODE "Unsupported ARM mode %02x" + IDS_UNSUPPORTED_CODE_FILE "Unsupported code file %s" + IDS_GSA_CODE_WARNING "Warning: cheats are for game %s. Current game is %s.\nCodes may not work correctly." + IDS_INVALID_CBA_CODE "Invalid CBA code. Format is XXXXXXXX YYYY." + IDS_CBA_CODE_WARNING "Warning: Codes seem to be for a different game.\nCodes may not work correctly." + IDS_OUT_OF_MEMORY "Failed to allocate memory for %s" +END + +STRINGTABLE +BEGIN + IDS_FILTER_GBS "Gameboy Snapshot_*.GBS__" + IDS_FILTER_GCF "Gameshark Code File_*.GCF__" + IDS_SELECT_CODE_FILE "Select code file" + IDS_SAVE_WILL_BE_LOST "Importing a snapshot file will erase any saved games. Do you want to continue?" + IDS_CONFIRM_ACTION "Please confirm action" + IDS_CODES_WILL_BE_LOST "Importing a code file will erase any entered codes. Do you want to continue?" + IDS_FILTER_SPC "Gameshark Code File_*.SPC;*.XPC__" + IDS_ADD_CBA_CODE "Add CodeBreakerAdvance code" + IDS_FILTER_WAV "Wave file_*.WAV__" + IDS_SELECT_WAV_NAME "Select wave file name" + IDS_FILTER_GBROM "Game Boy ROMs_*.GB;*.SGB;*.ZIP;*.7Z;*.Z;*.GZ__" + IDS_FILTER_PAL "Windows Palette (*.PAL)_*.PAL_PaintShop Palette (*.PAL)_*.PAL_Adobe Color Table (*.ACT)_*.ACT__" + IDS_SELECT_PALETTE_NAME "Select palette name:" + IDS_SEARCH_PRODUCED_NO_RESULTS "Search produced no results." + IDS_ERROR_BINDING "Error binding socket. Port probably in use." + IDS_ERROR_LISTENING "Error listening on socket." +END + +STRINGTABLE +BEGIN + IDS_ERROR_CREATING_SOCKET "Error creating socket." + IDS_ACK_NOT_RECEIVED "ACK not received from GDB." + IDS_ERROR_NOT_GBA_IMAGE "Error: not a GBA image." + IDS_EEPROM_NOT_SUPPORTED "EEPROM saves cannot be exported." + IDS_FILTER_DUMP "Memory Dump_*.DMP__" + IDS_SELECT_DUMP_FILE "Select dump file name" + IDS_FILTER_AVI "AVI File_*.AVI__" + IDS_SELECT_AVI_NAME "Select AVI file name" + IDS_INVALID_THROTTLE_VALUE + "Invalid throttle value. Please enter a number between 5 and 1000." + IDS_FILTER_INI "Skin INI File_*.INI__" + IDS_SELECT_SKIN_FILE "Select the skin file name" + IDS_FILTER_VMV "VisualBoyAdvance Movie_*.VMV__" + IDS_SELECT_MOVIE_NAME "Select movie name" + IDS_BUG_REPORT "The bug report information is now available on the Windows Clipboard. Please paste it into any bug report made by email or on forums to help solve problems more easily." + IDS_UNSUPPORTED_MOVIE_VERSION "Unsupported movie version %d." + IDS_END_OF_MOVIE "end of movie" +END + +STRINGTABLE +BEGIN + IDS_INVALID_INTERVAL_VALUE + "Invalid rewind interval value. Please enter a number between 0 and 600 seconds." + IDS_REGISTRY "VisualBoyAdvance no longer uses the registry to store its settings. Your previous settings have been exported into the file: %s" + IDS_MOVIE_PLAY "Playing a movie will load a save state which may erase your previous battery saves. Please be sure to have a saved state if you don't want to loose any previous data." +END + +STRINGTABLE +BEGIN + IDS_OAL_NODEVICE "There are no sound devices present on this system." + IDS_OAL_NODLL "OpenAL32.dll could not be found on your system. Please install the runtime from http://openal.org" + IDS_AVI_CANNOT_CREATE_AVI "Cannot create AVI file." + IDS_AVI_CANNOT_CREATE_VIDEO + "Cannot create video stream in AVI file. Make sure the selected codec supports input in RGB24 color space!" + IDS_AVI_CANNOT_CREATE_AUDIO "Cannot create audio stream in AVI file." + IDS_AVI_CANNOT_WRITE_VIDEO "Cannot write video frame to AVI file." + IDS_AVI_CANNOT_WRITE_AUDIO "Cannot write audio frame to AVI file." + IDS_FILTER_GBCROM "Game Boy Color ROMs_*.GBC;*.CGB;*.ZIP;*.7Z;*.Z;*.GZ__" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED +