From 8c17ac8da994f28883e11b83158892d625d38990 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 2 May 2020 15:30:58 -0500 Subject: [PATCH] Remove vba-next (#1969) * remove vba-next c code * decouple mgba code from vbanext stuff * delete vbanext C# core * rip out gba core picker * remove reference to VBANext from .csproj file * consolidate --- BizHawk.Client.Common/RomLoader.cs | 2 +- BizHawk.Client.Common/config/Config.cs | 1 - .../movie/import/VbmImport.cs | 2 +- BizHawk.Client.EmuHawk/MainForm.Designer.cs | 62 - BizHawk.Client.EmuHawk/MainForm.Events.cs | 35 - BizHawk.Client.EmuHawk/MainForm.cs | 5 +- BizHawk.Client.EmuHawk/tools/BatchRunner.cs | 5 - .../BizHawk.Emulation.Cores.csproj | 1 - .../Consoles/Nintendo/GBA/GBA.cs | 28 - .../Consoles/Nintendo/GBA/LibVBANext.cs | 214 - .../Consoles/Nintendo/GBA/LibmGBA.cs | 31 +- .../Consoles/Nintendo/GBA/MGBAHawk.cs | 25 +- .../Nintendo/GBA/VBANext.IDebuggable.cs | 25 - .../Nintendo/GBA/VBANext.IGBAGPUViewable.cs | 41 - .../Nintendo/GBA/VBANext.IMemoryDomains.cs | 80 - .../Consoles/Nintendo/GBA/VBANext.ISaveRam.cs | 30 - .../Nintendo/GBA/VBANext.ISettings.cs | 84 - .../Nintendo/GBA/VBANext.ISoundProvider.cs | 38 - .../Nintendo/GBA/VBANext.IStatable.cs | 86 - .../Nintendo/GBA/VBANext.IVideoProvider.cs | 44 - .../Consoles/Nintendo/GBA/VBANext.cs | 237 - .../Nintendo/GBA/VBARegisterHelper.cs | 63 - BizHawk.Emulation.Cores/CoreNames.cs | 1 - output/dll/libvbanext.dll | Bin 1018600 -> 0 bytes vbanext/constarrays.h | 55 - vbanext/instance.cpp | 13699 ---------------- vbanext/instance.h | 227 - vbanext/mingw/Makefile | 44 - vbanext/msvs/libvbanext/libvbanext.sln | 20 - vbanext/msvs/libvbanext/libvbanext.vcxproj | 90 - .../libvbanext/libvbanext.vcxproj.filters | 53 - vbanext/newstate.cpp | 64 - vbanext/newstate.h | 99 - vbanext/optable.inc | 327 - vbanext/port.h | 57 - vbanext/sound_blargg.h | 57 - vbanext/types.h | 33 - 37 files changed, 57 insertions(+), 15908 deletions(-) delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/GBA.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibVBANext.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IDebuggable.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IGBAGPUViewable.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IMemoryDomains.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.ISaveRam.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.ISettings.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.ISoundProvider.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IStatable.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IVideoProvider.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBARegisterHelper.cs delete mode 100644 output/dll/libvbanext.dll delete mode 100644 vbanext/constarrays.h delete mode 100644 vbanext/instance.cpp delete mode 100644 vbanext/instance.h delete mode 100644 vbanext/mingw/Makefile delete mode 100644 vbanext/msvs/libvbanext/libvbanext.sln delete mode 100644 vbanext/msvs/libvbanext/libvbanext.vcxproj delete mode 100644 vbanext/msvs/libvbanext/libvbanext.vcxproj.filters delete mode 100644 vbanext/newstate.cpp delete mode 100644 vbanext/newstate.h delete mode 100644 vbanext/optable.inc delete mode 100644 vbanext/port.h delete mode 100644 vbanext/sound_blargg.h delete mode 100644 vbanext/types.h diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs index 7f02da9f0b..785b5202bd 100644 --- a/BizHawk.Client.Common/RomLoader.cs +++ b/BizHawk.Client.Common/RomLoader.cs @@ -1059,7 +1059,7 @@ namespace BizHawk.Client.Common nextEmulator = cpc; break; case "GBA": - core = CoreInventory.Instance["GBA", Global.Config.PreferredCores["GBA"]]; + core = CoreInventory.Instance["GBA", CoreNames.Mgba]; break; case "PSX": nextEmulator = new Octoshock(nextComm, null, null, rom.FileData, GetCoreSettings(), GetCoreSyncSettings(), "PSX etc."); diff --git a/BizHawk.Client.Common/config/Config.cs b/BizHawk.Client.Common/config/Config.cs index 17013e7743..428290b79a 100644 --- a/BizHawk.Client.Common/config/Config.cs +++ b/BizHawk.Client.Common/config/Config.cs @@ -320,7 +320,6 @@ namespace BizHawk.Client.Common { ["NES"] = CoreNames.QuickNes, ["SNES"] = CoreNames.Snes9X, - ["GBA"] = CoreNames.Mgba, ["GB"] = CoreNames.Gambatte }; diff --git a/BizHawk.Client.Common/movie/import/VbmImport.cs b/BizHawk.Client.Common/movie/import/VbmImport.cs index 278e17b771..c7b08b1423 100644 --- a/BizHawk.Client.Common/movie/import/VbmImport.cs +++ b/BizHawk.Client.Common/movie/import/VbmImport.cs @@ -310,6 +310,6 @@ namespace BizHawk.Client.Common.movie.import } private static SimpleController GbaController() - => new SimpleController { Definition = GBA.GBAController }; + => new SimpleController { Definition = MGBAHawk.GBAController }; } } diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index f5b939ac88..067363a719 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -191,9 +191,6 @@ this.CoreSNESSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.Coresnes9xMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.CorebsnesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.GbaCoreSubMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.VbaNextCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.MgbaCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.SGBCoreSubmenu = new System.Windows.Forms.ToolStripMenuItem(); this.SgbBsnesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.SgbSameBoyMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -292,9 +289,6 @@ this.GBGameGenieMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.GBPrinterViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.GBASubMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.GBACoreSelectionSubMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.GBAmGBAMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.GBAVBANextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.GBAcoresettingsToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator33 = new System.Windows.Forms.ToolStripSeparator(); this.GbaGpuViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -1802,7 +1796,6 @@ this.CoresSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.NesCoreSubMenu, this.CoreSNESSubMenu, - this.GbaCoreSubMenu, this.SGBCoreSubmenu, this.GBCoreSubmenu, this.GBInSGBMenuItem, @@ -1885,30 +1878,6 @@ this.CorebsnesMenuItem.Text = "BSNES"; this.CorebsnesMenuItem.Click += new System.EventHandler(this.CoreSnesToggle_Click); // - // GbaCoreSubMenu - // - this.GbaCoreSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.VbaNextCoreMenuItem, - this.MgbaCoreMenuItem}); - this.GbaCoreSubMenu.Name = "GbaCoreSubMenu"; - this.GbaCoreSubMenu.Size = new System.Drawing.Size(223, 22); - this.GbaCoreSubMenu.Text = "GBA"; - this.GbaCoreSubMenu.DropDownOpened += new System.EventHandler(this.GbaCoreSubMenu_DropDownOpened); - // - // VbaNextCoreMenuItem - // - this.VbaNextCoreMenuItem.Name = "VbaNextCoreMenuItem"; - this.VbaNextCoreMenuItem.Size = new System.Drawing.Size(120, 22); - this.VbaNextCoreMenuItem.Text = "VBA-Next"; - this.VbaNextCoreMenuItem.Click += new System.EventHandler(this.GbaCorePick_Click); - // - // MgbaCoreMenuItem - // - this.MgbaCoreMenuItem.Name = "MgbaCoreMenuItem"; - this.MgbaCoreMenuItem.Size = new System.Drawing.Size(120, 22); - this.MgbaCoreMenuItem.Text = "mGBA"; - this.MgbaCoreMenuItem.Click += new System.EventHandler(this.GbaCorePick_Click); - // // SGBCoreSubmenu // this.SGBCoreSubmenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -2655,7 +2624,6 @@ // GBASubMenu // this.GBASubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.GBACoreSelectionSubMenu, this.GBAcoresettingsToolStripMenuItem1, this.toolStripSeparator33, this.GbaGpuViewerMenuItem}); @@ -2664,30 +2632,6 @@ this.GBASubMenu.Text = "GBA"; this.GBASubMenu.DropDownOpened += new System.EventHandler(this.GBASubMenu_DropDownOpened); // - // GBACoreSelectionSubMenu - // - this.GBACoreSelectionSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.GBAmGBAMenuItem, - this.GBAVBANextMenuItem}); - this.GBACoreSelectionSubMenu.Name = "GBACoreSelectionSubMenu"; - this.GBACoreSelectionSubMenu.Size = new System.Drawing.Size(129, 22); - this.GBACoreSelectionSubMenu.Text = "&Core"; - this.GBACoreSelectionSubMenu.DropDownOpened += new System.EventHandler(this.GBACoreSelectionSubMenu_DropDownOpened); - // - // GBAmGBAMenuItem - // - this.GBAmGBAMenuItem.Name = "GBAmGBAMenuItem"; - this.GBAmGBAMenuItem.Size = new System.Drawing.Size(120, 22); - this.GBAmGBAMenuItem.Text = "mGBA"; - this.GBAmGBAMenuItem.Click += new System.EventHandler(this.UsemGBAMenuItem_Click); - // - // GBAVBANextMenuItem - // - this.GBAVBANextMenuItem.Name = "GBAVBANextMenuItem"; - this.GBAVBANextMenuItem.Size = new System.Drawing.Size(120, 22); - this.GBAVBANextMenuItem.Text = "&VBA-Next"; - this.GBAVBANextMenuItem.Click += new System.EventHandler(this.UseVbaNextMenuItem_Click); - // // GBAcoresettingsToolStripMenuItem1 // this.GBAcoresettingsToolStripMenuItem1.Name = "GBAcoresettingsToolStripMenuItem1"; @@ -4398,9 +4342,6 @@ private System.Windows.Forms.ToolStripMenuItem subNesHawkMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator34; private System.Windows.Forms.ToolStripSeparator toolStripSeparator35; - private System.Windows.Forms.ToolStripMenuItem GBACoreSelectionSubMenu; - private System.Windows.Forms.ToolStripMenuItem GBAmGBAMenuItem; - private System.Windows.Forms.ToolStripMenuItem GBAVBANextMenuItem; private System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem1; private System.Windows.Forms.ToolStripMenuItem PSXHashDiscsToolStripMenuItem; private System.Windows.Forms.Timer timerMouseIdle; @@ -4455,9 +4396,6 @@ private System.Windows.Forms.ToolStripMenuItem NesCoreSubMenu; private System.Windows.Forms.ToolStripMenuItem QuicknesCoreMenuItem; private System.Windows.Forms.ToolStripMenuItem NesCoreMenuItem; - private System.Windows.Forms.ToolStripMenuItem GbaCoreSubMenu; - private System.Windows.Forms.ToolStripMenuItem VbaNextCoreMenuItem; - private System.Windows.Forms.ToolStripMenuItem MgbaCoreMenuItem; private System.Windows.Forms.ToolStripMenuItem Atari7800HawkCoreMenuItem; private System.Windows.Forms.ToolStripMenuItem SGBCoreSubmenu; private System.Windows.Forms.ToolStripMenuItem SgbBsnesMenuItem; diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index b558c4eb02..f10acfda1e 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -1258,23 +1258,6 @@ namespace BizHawk.Client.EmuHawk } } - private void GbaCoreSubMenu_DropDownOpened(object sender, EventArgs e) - { - VbaNextCoreMenuItem.Checked = Config.PreferredCores["GBA"] == CoreNames.VbaNext; - MgbaCoreMenuItem.Checked = Config.PreferredCores["GBA"] == CoreNames.Mgba; - } - - private void GbaCorePick_Click(object sender, EventArgs e) - { - Config.PreferredCores["GBA"] = Config.PreferredCores["GBA"] == CoreNames.VbaNext - ? CoreNames.Mgba - : CoreNames.VbaNext; - if (Emulator.SystemId == "GBA") - { - FlagNeedsReboot(); - } - } - private void SGBCoreSubmenu_DropDownOpened(object sender, EventArgs e) { SgbBsnesMenuItem.Checked = Config.SgbUseBsnes; @@ -2000,29 +1983,11 @@ namespace BizHawk.Client.EmuHawk Tools.Load(); } - private void UsemGBAMenuItem_Click(object sender, EventArgs e) - { - Config.PreferredCores["GBA"] = CoreNames.Mgba; - FlagNeedsReboot(); - } - - private void UseVbaNextMenuItem_Click(object sender, EventArgs e) - { - Config.PreferredCores["GBA"] = CoreNames.VbaNext; - FlagNeedsReboot(); - } - private void GBASubMenu_DropDownOpened(object sender, EventArgs e) { GbaGpuViewerMenuItem.Enabled = !OSTailoredCode.IsUnixHost; } - private void GBACoreSelectionSubMenu_DropDownOpened(object sender, EventArgs e) - { - GBAmGBAMenuItem.Checked = Config.PreferredCores["GBA"] == CoreNames.Mgba; - GBAVBANextMenuItem.Checked = Config.PreferredCores["GBA"] == CoreNames.VbaNext; - } - #endregion #region NDS diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 65be34780c..310f093b9d 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -1663,9 +1663,8 @@ namespace BizHawk.Client.EmuHawk byte[] sram; - // GBA meteor core might not know how big the saveram ought to be, so just send it the whole file - // GBA vba-next core will try to eat anything, regardless of size - if (Emulator is VBANext || Emulator is MGBAHawk || Emulator is NeoGeoPort) + // some cores might not know how big the saveram ought to be, so just send it the whole file + if (Emulator is MGBAHawk || Emulator is NeoGeoPort) { sram = File.ReadAllBytes(saveRamPath); } diff --git a/BizHawk.Client.EmuHawk/tools/BatchRunner.cs b/BizHawk.Client.EmuHawk/tools/BatchRunner.cs index bbcdaf1040..c0f11d6a3d 100644 --- a/BizHawk.Client.EmuHawk/tools/BatchRunner.cs +++ b/BizHawk.Client.EmuHawk/tools/BatchRunner.cs @@ -166,11 +166,6 @@ namespace BizHawk.Client.EmuHawk _current.CoreType = emu.GetType(); var controller = new Controller(emu.ControllerDefinition); _current.BoardName = emu.HasBoardInfo() ? emu.AsBoardInfo().BoardName : null; - // hack - if (emu is VBANext vba) - { - _current.BoardName = vba.GameCode; - } _current.Frames = 0; _current.LaggedFrames = 0; diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 63f847103a..7cd09a2f55 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -42,7 +42,6 @@ - diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/GBA.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/GBA.cs deleted file mode 100644 index 717e57a20f..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/GBA.cs +++ /dev/null @@ -1,28 +0,0 @@ -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBA -{ - public static class GBA - { - private static readonly ControllerDefinition.AxisRange TiltRange = new ControllerDefinition.AxisRange(-32767, 0, 32767); - - public static readonly ControllerDefinition GBAController = new ControllerDefinition - { - Name = "GBA Controller", - BoolButtons = - { - "Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "L", "R", "Power" - }, - AxisControls = - { - "Tilt X", "Tilt Y", "Tilt Z", - "Light Sensor" - }, - AxisRanges = - { - TiltRange, TiltRange, TiltRange, - new ControllerDefinition.AxisRange(0, 100, 200), - } - }; - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibVBANext.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibVBANext.cs deleted file mode 100644 index 7c955cc8b3..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibVBANext.cs +++ /dev/null @@ -1,214 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBA -{ - public class LibVBANext - { - const string dllname = "libvbanext.dll"; - const CallingConvention cc = CallingConvention.Cdecl; - - [Flags] - public enum Buttons : int - { - A = 1, - B = 2, - Select = 4, - Start = 8, - Right = 16, - Left = 32, - Up = 64, - Down = 128, - R = 256, - L = 512 - } - - [StructLayout(LayoutKind.Sequential)] - public class FrontEndSettings - { - public enum SaveType : int - { - auto = 0, - eeprom = 1, - sram = 2, - flash = 3, - eeprom_sensor = 4, - none = 5 - } - public enum FlashSize : int - { - small = 0x10000, - big = 0x20000 - } - public SaveType saveType; - public FlashSize flashSize = FlashSize.big; - public bool enableRtc; - public bool mirroringEnable; - public bool skipBios; - - public bool RTCUseRealTime = true; - public int RTCyear; // 00..99 - public int RTCmonth; // 00..11 - public int RTCmday; // 01..31 - public int RTCwday; // 00..06 - public int RTChour; // 00..23 - public int RTCmin; // 00..59 - public int RTCsec; // 00..59 - } - - /// - /// create a new context - /// - [DllImport(dllname, CallingConvention = cc)] - public static extern IntPtr Create(); - - /// - /// destroy a context - /// - [DllImport(dllname, CallingConvention = cc)] - public static extern void Destroy(IntPtr g); - - /// - /// load a rom - /// - /// success - [DllImport(dllname, CallingConvention = cc)] - public static extern bool LoadRom(IntPtr g, byte[] romfile, uint romfilelen, byte[] biosfile, uint biosfilelen, [In]FrontEndSettings settings); - - /// - /// hard reset - /// - [DllImport(dllname, CallingConvention = cc)] - public static extern void Reset(IntPtr g); - - /// - /// frame advance - /// - /// 240x160 packed argb32 - /// buffer to recieve stereo audio - /// number of samples created - /// true if lagged - [DllImport(dllname, CallingConvention = cc)] - public static extern bool FrameAdvance(IntPtr g, Buttons input, int[] videobuffer, short[] audiobuffer, out int numsamp, int[] videopalette); - - [DllImport(dllname, CallingConvention = cc)] - public static extern int BinStateSize(IntPtr g); - [DllImport(dllname, CallingConvention = cc)] - public static extern bool BinStateSave(IntPtr g, byte[] data, int length); - [DllImport(dllname, CallingConvention = cc)] - public static extern bool BinStateLoad(IntPtr g, byte[] data, int length); - [DllImport(dllname, CallingConvention = cc)] - public static extern void TxtStateSave(IntPtr g, [In]ref TextStateFPtrs ff); - [DllImport(dllname, CallingConvention = cc)] - public static extern void TxtStateLoad(IntPtr g, [In]ref TextStateFPtrs ff); - - [DllImport(dllname, CallingConvention = cc)] - public static extern int SaveRamSize(IntPtr g); - [DllImport(dllname, CallingConvention = cc)] - public static extern bool SaveRamSave(IntPtr g, byte[] data, int length); - [DllImport(dllname, CallingConvention = cc)] - public static extern bool SaveRamLoad(IntPtr g, byte[] data, int length); - [DllImport(dllname, CallingConvention = cc)] - public static extern void GetMemoryAreas(IntPtr g, [Out]MemoryAreas mem); - - [DllImport(dllname, CallingConvention = cc)] - public static extern void SystemBusWrite(IntPtr g, int addr, byte val); - [DllImport(dllname, CallingConvention = cc)] - public static extern byte SystemBusRead(IntPtr g, int addr); - - [UnmanagedFunctionPointer(cc)] - public delegate void StandardCallback(); - - [DllImport(dllname, CallingConvention = cc)] - public static extern void SetScanlineCallback(IntPtr g, StandardCallback cb, int scanline); - - [DllImport(dllname, CallingConvention = cc)] - public static extern IntPtr GetRegisters(IntPtr g); - - [UnmanagedFunctionPointer(cc)] - public delegate void AddressCallback(uint addr); - - /// if bit 0 is set, thumb mode - [UnmanagedFunctionPointer(cc)] - public delegate void TraceCallback(uint addr, uint opcode); - - [DllImport(dllname, CallingConvention = cc)] - public static extern void SetPadCallback(IntPtr g, StandardCallback cb); - [DllImport(dllname, CallingConvention = cc)] - public static extern void SetFetchCallback(IntPtr g, AddressCallback cb); - [DllImport(dllname, CallingConvention = cc)] - public static extern void SetReadCallback(IntPtr g, AddressCallback cb); - [DllImport(dllname, CallingConvention = cc)] - public static extern void SetWriteCallback(IntPtr g, AddressCallback cb); - [DllImport(dllname, CallingConvention = cc)] - public static extern void SetTraceCallback(IntPtr g, TraceCallback cb); - - - [StructLayout(LayoutKind.Sequential)] - public class MemoryAreas - { - public IntPtr bios; - public IntPtr iwram; - public IntPtr ewram; - public IntPtr palram; - public IntPtr vram; - public IntPtr oam; - public IntPtr rom; - public IntPtr mmio; - public IntPtr sram; - public int sram_size; - } - - // this isn't used directly at the moment. but it could be used for something eventually... - [StructLayout(LayoutKind.Sequential)] - public class Registers - { - public int R0; - public int R1; - public int R2; - public int R3; - public int R4; - public int R5; - public int R6; - public int R7; - public int R8; - public int R9; - public int R10; - public int R11; - public int R12; - public int R13; - public int R14; - public int R15; - public int CPSR; - public int SPSR; - public int R13_IRQ; - public int R14_IRQ; - public int SPSR_IRQ; - public int _unk0; // what are these??? - public int _unk1; - public int _unk2; - public int _unk3; - public int _unk4; - public int R13_USR; - public int R14_USR; - public int R13_SVC; - public int R14_SVC; - public int SPSR_SVC; - public int R13_ABT; - public int R14_ABT; - public int SPSR_ABT; - public int R13_UND; - public int R14_UND; - public int SPSR_UND; - public int R8_FIQ; - public int R9_FIQ; - public int R10_FIQ; - public int R11_FIQ; - public int R12_FIQ; - public int R13_FIQ; - public int R14_FIQ; - public int SPSR_FIQ; - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibmGBA.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibmGBA.cs index a59af3dc2c..d395d60e90 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibmGBA.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibmGBA.cs @@ -1,10 +1,39 @@ using System; using System.Runtime.InteropServices; +using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.Nintendo.GBA { public static class LibmGBA { + [Flags] + public enum Buttons : int + { + A = 1, + B = 2, + Select = 4, + Start = 8, + Right = 16, + Left = 32, + Up = 64, + Down = 128, + R = 256, + L = 512 + } + + public static Buttons GetButtons(IController c) + { + Buttons ret = 0; + foreach (string s in Enum.GetNames(typeof(Buttons))) + { + if (c.IsPressed(s)) + { + ret |= (Buttons)Enum.Parse(typeof(Buttons), s); + } + } + return ret; + } + const string dll = "mgba.dll"; const CallingConvention cc = CallingConvention.Cdecl; @@ -95,7 +124,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA public static extern void BizReset(IntPtr ctx); [DllImport(dll, CallingConvention = cc)] - public static extern bool BizAdvance(IntPtr ctx, LibVBANext.Buttons keys, int[] vbuff, ref int nsamp, short[] sbuff, + public static extern bool BizAdvance(IntPtr ctx, Buttons keys, int[] vbuff, ref int nsamp, short[] sbuff, long time, short gyrox, short gyroy, short gyroz, byte luma); [DllImport(dll, CallingConvention = cc)] diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.cs index 0bdafd1470..5316562699 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.cs @@ -73,7 +73,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA public IEmulatorServiceProvider ServiceProvider { get; } - public ControllerDefinition ControllerDefinition => GBA.GBAController; + public ControllerDefinition ControllerDefinition => GBAController; private ITraceable Tracer { get; } @@ -117,7 +117,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA IsLagFrame = LibmGBA.BizAdvance( Core, - VBANext.GetButtons(controller), + LibmGBA.GetButtons(controller), render ? _videobuff : _dummyvideobuff, ref _nsamp, renderSound ? _soundbuff : _dummysoundbuff, @@ -249,5 +249,26 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA long increment = Frame * 4389L >> 18; return baseTime + increment; } + + private static readonly ControllerDefinition.AxisRange TiltRange = new ControllerDefinition.AxisRange(-32767, 0, 32767); + + public static readonly ControllerDefinition GBAController = new ControllerDefinition + { + Name = "GBA Controller", + BoolButtons = + { + "Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "L", "R", "Power" + }, + AxisControls = + { + "Tilt X", "Tilt Y", "Tilt Z", + "Light Sensor" + }, + AxisRanges = + { + TiltRange, TiltRange, TiltRange, + new ControllerDefinition.AxisRange(0, 100, 200), + } + }; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IDebuggable.cs deleted file mode 100644 index 68c4559bd9..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IDebuggable.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; - -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBA -{ - public partial class VBANext : IDebuggable - { - public IDictionary GetCpuFlagsAndRegisters() => regs.GetAllRegisters(); - - public void SetCpuRegister(string register, int value) => regs.SetRegister(register, value); - - public bool CanStep(StepType type) => false; - - private readonly MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); - public IMemoryCallbackSystem MemoryCallbacks => _memorycallbacks; - - [FeatureNotImplemented] - public void Step(StepType type) => throw new NotImplementedException(); - - [FeatureNotImplemented] - public long TotalExecutedCycles => throw new NotImplementedException(); - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IGBAGPUViewable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IGBAGPUViewable.cs deleted file mode 100644 index ea14fb717e..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IGBAGPUViewable.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; - -namespace BizHawk.Emulation.Cores.Nintendo.GBA -{ - public partial class VBANext : IGBAGPUViewable - { - public GBAGPUMemoryAreas GetMemoryAreas() - { - var s = new LibVBANext.MemoryAreas(); - LibVBANext.GetMemoryAreas(Core, s); - return new GBAGPUMemoryAreas - { - mmio = s.mmio, - oam = s.oam, - palram = s.palram, - vram = s.vram - }; - } - - public void SetScanlineCallback(Action callback, int scanline) - { - if (scanline < 0 || scanline > 227) - { - throw new ArgumentOutOfRangeException(nameof(scanline), "Scanline must be in [0, 227]!"); - } - - if (callback == null) - { - scanlinecb = null; - LibVBANext.SetScanlineCallback(Core, scanlinecb, 0); - } - else - { - scanlinecb = new LibVBANext.StandardCallback(callback); - LibVBANext.SetScanlineCallback(Core, scanlinecb, scanline); - } - } - - private LibVBANext.StandardCallback scanlinecb; - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IMemoryDomains.cs deleted file mode 100644 index bd0fb8c2c3..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IMemoryDomains.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; - -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBA -{ - public partial class VBANext - { - private IMemoryDomains _memoryDomains; - - private void InitMemoryDomains() - { - var mm = new List(); - var s = new LibVBANext.MemoryAreas(); - var l = MemoryDomain.Endian.Little; - LibVBANext.GetMemoryAreas(Core, s); - - mm.Add(new MemoryDomainIntPtr("IWRAM", l, s.iwram, 32 * 1024, true, 4)); - mm.Add(new MemoryDomainIntPtr("EWRAM", l, s.ewram, 256 * 1024, true, 4)); - mm.Add(new MemoryDomainIntPtr("BIOS", l, s.bios, 16 * 1024, false, 4)); - mm.Add(new MemoryDomainIntPtr("PALRAM", l, s.palram, 1024, false, 4)); - mm.Add(new MemoryDomainIntPtr("VRAM", l, s.vram, 96 * 1024, true, 4)); - mm.Add(new MemoryDomainIntPtr("OAM", l, s.oam, 1024, true, 4)); - - mm.Add(new MemoryDomainIntPtr("ROM", l, s.rom, 32 * 1024 * 1024, true, 4)); - - mm.Add(new MemoryDomainIntPtr("SRAM", l, s.sram, s.sram_size, true, 4)); - - mm.Add(new MemoryDomainDelegate("System Bus", 0x10000000, l, - delegate(long addr) - { - if (addr < 0 || addr >= 0x10000000) - { - throw new ArgumentOutOfRangeException(); - } - - return LibVBANext.SystemBusRead(Core, (int)addr); - }, - delegate(long addr, byte val) - { - if (addr < 0 || addr >= 0x10000000) - { - throw new ArgumentOutOfRangeException(); - } - - LibVBANext.SystemBusWrite(Core, (int)addr, val); - }, 4)); - - // special combined ram memory domain - { - var ew = mm[1]; - var iw = mm[0]; - MemoryDomain cr = new MemoryDomainDelegate("Combined WRAM", (256 + 32) * 1024, MemoryDomain.Endian.Little, - delegate(long addr) - { - if (addr < 0 || addr >= (256 + 32) * 1024) - throw new IndexOutOfRangeException(); - if (addr >= 256 * 1024) - return iw.PeekByte(addr & 32767); - else - return ew.PeekByte(addr); - }, - delegate(long addr, byte val) - { - if (addr < 0 || addr >= (256 + 32) * 1024) - throw new IndexOutOfRangeException(); - if (addr >= 256 * 1024) - iw.PokeByte(addr & 32767, val); - else - ew.PokeByte(addr, val); - }, 4); - mm.Add(cr); - } - - _memoryDomains = new MemoryDomainList(mm); - (ServiceProvider as BasicServiceProvider).Register(_memoryDomains); - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.ISaveRam.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.ISaveRam.cs deleted file mode 100644 index 0f4feb4ac7..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.ISaveRam.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBA -{ - public partial class VBANext : ISaveRam - { - public bool SaveRamModified => LibVBANext.SaveRamSize(Core) != 0; - - public byte[] CloneSaveRam() - { - var data = new byte[LibVBANext.SaveRamSize(Core)]; - if (!LibVBANext.SaveRamSave(Core, data, data.Length)) - { - throw new InvalidOperationException($"{nameof(LibVBANext.SaveRamSave)}() failed!"); - } - - return data; - } - - public void StoreSaveRam(byte[] data) - { - // internally, we try to salvage bad-sized saverams - if (!LibVBANext.SaveRamLoad(Core, data, data.Length)) - { - throw new InvalidOperationException($"{nameof(LibVBANext.SaveRamLoad)}() failed!"); - } - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.ISettings.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.ISettings.cs deleted file mode 100644 index 4e6c6b4065..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.ISettings.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.ComponentModel; - -using BizHawk.Common; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBA -{ - public partial class VBANext : ISettable - { - public object GetSettings() - { - return null; - } - - public SyncSettings GetSyncSettings() - { - return _syncSettings.Clone(); - } - - public PutSettingsDirtyBits PutSettings(object o) - { - return PutSettingsDirtyBits.None; - } - - public PutSettingsDirtyBits PutSyncSettings(SyncSettings o) - { - bool ret = SyncSettings.NeedsReboot(o, _syncSettings); - _syncSettings = o; - return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None; - } - - private SyncSettings _syncSettings; - - public class SyncSettings - { - [DisplayName("Skip BIOS")] - [Description("Skips the BIOS intro. A BIOS file is still required.")] - [DefaultValue(true)] - public bool SkipBios { get; set; } - - [DisplayName("RTC Use Real Time")] - [Description("Causes the internal clock to reflect your system clock. Only relevant when a game has an RTC chip. Forced to false for movie recording.")] - [DefaultValue(true)] - public bool RTCUseRealTime { get; set; } - - [DisplayName("RTC Initial Time")] - [Description("The initial time of emulation. Only relevant when a game has an RTC chip and \"RTC Use Real Time\" is false.")] - [DefaultValue(typeof(DateTime), "2010-01-01")] - public DateTime RTCInitialTime { get; set; } - - public enum DayOfWeek - { - Sunday = 0, - Monday, - Tuesday, - Wednesday, - Thursday, - Friday, - Saturday - } - - [DisplayName("RTC Initial Day")] - [Description("The day of the week to go with \"RTC Initial Time\". Due to peculiarities in the RTC chip, this can be set indepedently of the year, month, and day of month.")] - [DefaultValue(DayOfWeek.Friday)] - public DayOfWeek RTCInitialDay { get; set; } - - public SyncSettings() - { - SettingsUtil.SetDefaultValues(this); - } - - public static bool NeedsReboot(SyncSettings x, SyncSettings y) - { - return !DeepEquality.DeepEquals(x, y); - } - - public SyncSettings Clone() - { - return (SyncSettings)MemberwiseClone(); - } - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.ISoundProvider.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.ISoundProvider.cs deleted file mode 100644 index 02f8b301e9..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.ISoundProvider.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBA -{ - public partial class VBANext : ISoundProvider - { - private readonly short[] _soundbuff = new short[2048]; - private int _numsamp; - - public void GetSamplesSync(out short[] samples, out int nsamp) - { - samples = _soundbuff; - nsamp = _numsamp; - } - - public void DiscardSamples() - { - } - - public bool CanProvideAsync => false; - - public void SetSyncMode(SyncSoundMode mode) - { - if (mode == SyncSoundMode.Async) - { - throw new NotSupportedException("Async mode is not supported."); - } - } - - public SyncSoundMode SyncMode => SyncSoundMode.Sync; - - public void GetSamplesAsync(short[] samples) - { - throw new InvalidOperationException("Async mode is not supported."); - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IStatable.cs deleted file mode 100644 index a2d8d36355..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IStatable.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.IO; -using Newtonsoft.Json; - -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBA -{ - public partial class VBANext : ITextStatable - { - public void SaveStateText(TextWriter writer) - { - var s = new TextState(); - s.Prepare(); - var ff = s.GetFunctionPointersSave(); - LibVBANext.TxtStateSave(Core, ref ff); - s.ExtraData.IsLagFrame = IsLagFrame; - s.ExtraData.LagCount = LagCount; - s.ExtraData.Frame = Frame; - - ser.Serialize(writer, s); - } - - public void LoadStateText(TextReader reader) - { - var s = (TextState)ser.Deserialize(reader, typeof(TextState)); - s.Prepare(); - var ff = s.GetFunctionPointersLoad(); - LibVBANext.TxtStateLoad(Core, ref ff); - IsLagFrame = s.ExtraData.IsLagFrame; - LagCount = s.ExtraData.LagCount; - Frame = s.ExtraData.Frame; - } - - public void SaveStateBinary(BinaryWriter writer) - { - if (!LibVBANext.BinStateSave(Core, _savebuff, _savebuff.Length)) - throw new InvalidOperationException($"Core's {nameof(LibVBANext.BinStateSave)}() returned false!"); - writer.Write(_savebuff.Length); - writer.Write(_savebuff); - - // other variables - writer.Write(IsLagFrame); - writer.Write(LagCount); - writer.Write(Frame); - } - - public void LoadStateBinary(BinaryReader reader) - { - int length = reader.ReadInt32(); - if (length != _savebuff.Length) - throw new InvalidOperationException("Save buffer size mismatch!"); - reader.Read(_savebuff, 0, length); - if (!LibVBANext.BinStateLoad(Core, _savebuff, _savebuff.Length)) - throw new InvalidOperationException($"Core's {nameof(LibVBANext.BinStateLoad)}() returned false!"); - - // other variables - IsLagFrame = reader.ReadBoolean(); - LagCount = reader.ReadInt32(); - Frame = reader.ReadInt32(); - } - - public byte[] SaveStateBinary() - { - var ms = new MemoryStream(_savebuff2, true); - var bw = new BinaryWriter(ms); - SaveStateBinary(bw); - bw.Flush(); - if (ms.Position != _savebuff2.Length) - throw new InvalidOperationException(); - ms.Close(); - return _savebuff2; - } - - private JsonSerializer ser = new JsonSerializer { Formatting = Formatting.Indented }; - private readonly byte[] _savebuff; - private readonly byte[] _savebuff2; - - private class TextStateData - { - public int Frame; - public int LagCount; - public bool IsLagFrame; - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IVideoProvider.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IVideoProvider.cs deleted file mode 100644 index 049cb587ec..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IVideoProvider.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; - -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Nintendo.Gameboy; - -namespace BizHawk.Emulation.Cores.Nintendo.GBA -{ - public partial class VBANext : IVideoProvider - { - public int VirtualWidth => 240; - public int VirtualHeight => 160; - public int BufferWidth => 240; - public int BufferHeight => 160; - - public int BackgroundColor => unchecked((int)0xff000000); - - public int[] GetVideoBuffer() - { - return _videobuff; - } - - public int VsyncNumerator => 262144; - - public int VsyncDenominator => 4389; - - private readonly int[] _videobuff = new int[240 * 160]; - private readonly int[] _videopalette = new int[65536]; - - private void SetupColors() - { - int[] tmp = GBColors.GetLut(GBColors.ColorType.vivid); - - // reorder - for (int i = 0; i < 32768; i++) - { - int j = i & 0x3e0 | (i & 0x1f) << 10 | i >> 10 & 0x1f; - _videopalette[i] = tmp[j]; - } - - // duplicate - Array.Copy(_videopalette, 0, _videopalette, 32768, 32768); - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs deleted file mode 100644 index a2de55bb37..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs +++ /dev/null @@ -1,237 +0,0 @@ -using System; -using System.Linq; -using System.Text; - -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Components.ARM; - -namespace BizHawk.Emulation.Cores.Nintendo.GBA -{ - [Core(CoreNames.VbaNext, "many authors", true, true, "cd508312a29ed8c29dacac1b11c2dce56c338a54", "https://github.com/libretro/vba-next", false)] - [ServiceNotApplicable(new[] { typeof(IDriveLight), typeof(IRegionable) })] - public partial class VBANext : IEmulator, IVideoProvider, ISoundProvider, IInputPollable, - IGBAGPUViewable, ISaveRam, IStatable, IDebuggable, ISettable - { - [CoreConstructor("GBA")] - public VBANext(byte[] file, CoreComm comm, GameInfo game, bool deterministic, object syncsettings) - { - var ser = new BasicServiceProvider(this); - ser.Register(new ArmV4Disassembler()); - ServiceProvider = ser; - - byte[] biosfile = comm.CoreFileProvider.GetFirmware("GBA", "Bios", true, "GBA bios file is mandatory."); - if (file.Length > 32 * 1024 * 1024) - throw new ArgumentException("ROM is too big to be a GBA ROM!"); - if (biosfile.Length != 16 * 1024) - throw new ArgumentException("BIOS file is not exactly 16K!"); - - var FES = new LibVBANext.FrontEndSettings - { - saveType = (LibVBANext.FrontEndSettings.SaveType)game.GetInt("saveType", 0), - flashSize = (LibVBANext.FrontEndSettings.FlashSize)game.GetInt("flashSize", 0x10000), - enableRtc = game.GetInt("rtcEnabled", 0) != 0, - mirroringEnable = game.GetInt("mirroringEnabled", 0) != 0 - }; - Console.WriteLine("GameDB loaded settings: saveType={0}, flashSize={1}, rtcEnabled={2}, mirroringEnabled={3}", - FES.saveType, FES.flashSize, FES.enableRtc, FES.mirroringEnable); - - _syncSettings = (SyncSettings)syncsettings ?? new SyncSettings(); - DeterministicEmulation = deterministic; - - FES.skipBios = _syncSettings.SkipBios; - FES.RTCUseRealTime = _syncSettings.RTCUseRealTime; - FES.RTCwday = (int)_syncSettings.RTCInitialDay; - FES.RTCyear = _syncSettings.RTCInitialTime.Year % 100; - FES.RTCmonth = _syncSettings.RTCInitialTime.Month - 1; - FES.RTCmday = _syncSettings.RTCInitialTime.Day; - FES.RTChour = _syncSettings.RTCInitialTime.Hour; - FES.RTCmin = _syncSettings.RTCInitialTime.Minute; - FES.RTCsec = _syncSettings.RTCInitialTime.Second; - if (DeterministicEmulation) - { - // FES.skipBios = false; // this is OK; it is deterministic and probably accurate - FES.RTCUseRealTime = false; - } - - Core = LibVBANext.Create(); - if (Core == IntPtr.Zero) - throw new InvalidOperationException($"{nameof(LibVBANext.Create)}() returned nullptr!"); - try - { - if (!LibVBANext.LoadRom(Core, file, (uint)file.Length, biosfile, (uint)biosfile.Length, FES)) - throw new InvalidOperationException($"{nameof(LibVBANext.LoadRom)}() returned false!"); - - Tracer = new TraceBuffer() - { - Header = "ARM7: PC, machine code, mnemonic, operands, registers (r0-r16)" - }; - ser.Register(Tracer); - - GameCode = Encoding.ASCII.GetString(file, 0xac, 4); - Console.WriteLine("Game code \"{0}\"", GameCode); - - _savebuff = new byte[LibVBANext.BinStateSize(Core)]; - _savebuff2 = new byte[_savebuff.Length + 13]; - InitMemoryDomains(); - InitRegisters(); - InitCallbacks(); - - // todo: hook me up as a setting - SetupColors(); - } - catch - { - Dispose(); - throw; - } - } - - IntPtr Core; - - public IEmulatorServiceProvider ServiceProvider { get; } - - public bool FrameAdvance(IController controller, bool render, bool rendersound = true) - { - Frame++; - - if (controller.IsPressed("Power")) - LibVBANext.Reset(Core); - - SyncTraceCallback(); - - IsLagFrame = LibVBANext.FrameAdvance(Core, GetButtons(controller), _videobuff, _soundbuff, out _numsamp, _videopalette); - - if (IsLagFrame) - LagCount++; - - return true; - } - - public int Frame { get; private set; } - public int LagCount { get; set; } - public bool IsLagFrame { get; set; } - - private ITraceable Tracer { get; set; } - - public string SystemId => "GBA"; - - public bool DeterministicEmulation { get; } - - public void ResetCounters() - { - Frame = 0; - LagCount = 0; - IsLagFrame = false; - } - - /// - /// set in the ROM internal header - /// - public string GameCode { get; } - - public void Dispose() - { - if (Core != IntPtr.Zero) - { - LibVBANext.Destroy(Core); - Core = IntPtr.Zero; - } - } - - #region Debugging - - LibVBANext.StandardCallback padcb; - LibVBANext.AddressCallback fetchcb; - LibVBANext.AddressCallback readcb; - LibVBANext.AddressCallback writecb; - LibVBANext.TraceCallback tracecb; - - private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem(); - public IInputCallbackSystem InputCallbacks => _inputCallbacks; - - TraceInfo Trace(uint addr, uint opcode) - { - return new TraceInfo - { - Disassembly = $"{addr:X8}: {opcode:X8} {Darm.DisassembleStuff(addr, opcode)}".PadRight(54), - RegisterInfo = regs.TraceString() - }; - } - - void InitCallbacks() - { - padcb = new LibVBANext.StandardCallback(() => InputCallbacks.Call()); - fetchcb = new LibVBANext.AddressCallback((addr) => { - if (MemoryCallbacks.HasExecutes) - { - uint flags = (uint)MemoryCallbackFlags.AccessExecute; - MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "System Bus"); - } - }); - readcb = new LibVBANext.AddressCallback((addr) => - { - if (MemoryCallbacks.HasReads) - { - uint flags = (uint)MemoryCallbackFlags.AccessRead; - MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "System Bus"); - } - }); - writecb = new LibVBANext.AddressCallback((addr) => - { - if (MemoryCallbacks.HasWrites) - { - uint flags = (uint)MemoryCallbackFlags.AccessWrite; - MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "System Bus"); - } - }); - tracecb = new LibVBANext.TraceCallback((addr, opcode) => Tracer.Put(Trace(addr, opcode))); - _inputCallbacks.ActiveChanged += SyncPadCallback; - _memorycallbacks.ActiveChanged += SyncMemoryCallbacks; - } - - void SyncPadCallback() - { - LibVBANext.SetPadCallback(Core, InputCallbacks.Any() ? padcb : null); - } - - void SyncMemoryCallbacks() - { - LibVBANext.SetFetchCallback(Core, MemoryCallbacks.HasExecutes ? fetchcb : null); - LibVBANext.SetReadCallback(Core, MemoryCallbacks.HasReads ? readcb : null); - LibVBANext.SetWriteCallback(Core, MemoryCallbacks.HasWrites ? writecb : null); - } - - void SyncTraceCallback() - { - LibVBANext.SetTraceCallback(Core, Tracer.Enabled ? tracecb : null); - } - - VBARegisterHelper regs; - - void InitRegisters() - { - regs = new VBARegisterHelper(Core); - } - - #endregion - - #region Controller - - public ControllerDefinition ControllerDefinition => GBA.GBAController; - - public static LibVBANext.Buttons GetButtons(IController c) - { - LibVBANext.Buttons ret = 0; - foreach (string s in Enum.GetNames(typeof(LibVBANext.Buttons))) - { - if (c.IsPressed(s)) - { - ret |= (LibVBANext.Buttons)Enum.Parse(typeof(LibVBANext.Buttons), s); - } - } - return ret; - } - - #endregion - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBARegisterHelper.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBARegisterHelper.cs deleted file mode 100644 index d17c116601..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBARegisterHelper.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBA -{ - public unsafe class VBARegisterHelper - { - private readonly IntPtr _origin; - private readonly Dictionary _locs = new Dictionary(); - - public VBARegisterHelper(IntPtr Core) - { - _origin = LibVBANext.GetRegisters(Core); - foreach (var field in typeof(LibVBANext.Registers).GetFields()) - { - var ofs = Marshal.OffsetOf(typeof(LibVBANext.Registers), field.Name); - _locs[field.Name] = IntPtr.Add(_origin, (int)ofs); - } - } - - public int GetRegister(string name) - { - int* p = (int*)_locs[name]; - return *p; - } - - public void SetRegister(string name, int val) - { - int* p = (int*)_locs[name]; - *p = val; - } - - public Dictionary GetAllRegisters() - { - var ret = new Dictionary(); - foreach (var kvp in _locs) - { - ret[kvp.Key] = GetRegister(kvp.Key); - } - - return ret; - } - - public string TraceString() - { - var sb = new StringBuilder(); - int* p = (int*)_origin; - for (int i = 0; i < 17; i++) - { - sb.Append($"r{i}:{p[i]:X8}"); - if (i != 16) - { - sb.Append(' '); - } - } - - return sb.ToString(); - } - } -} diff --git a/BizHawk.Emulation.Cores/CoreNames.cs b/BizHawk.Emulation.Cores/CoreNames.cs index fc2dfbbc86..a8c9e907c0 100644 --- a/BizHawk.Emulation.Cores/CoreNames.cs +++ b/BizHawk.Emulation.Cores/CoreNames.cs @@ -15,7 +15,6 @@ namespace BizHawk.Emulation.Cores public const string Snes9X = "Snes9x"; public const string Bsnes = "BSNES"; public const string Mgba = "mGBA"; - public const string VbaNext = "VBA-Next"; public const string GbHawk = "GBHawk"; public const string Gambatte = "Gambatte"; public const string SubGbHawk = "SubGBHawk"; diff --git a/output/dll/libvbanext.dll b/output/dll/libvbanext.dll deleted file mode 100644 index 3a860e5bb9ad80f96e34aa209e8460ce8e53f787..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1018600 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

QdBdTF~6vorB7 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 Qv3+gFX5#oJqW2*3ztjhKF#rGn diff --git a/vbanext/constarrays.h b/vbanext/constarrays.h deleted file mode 100644 index 4e87a6e33e..0000000000 --- a/vbanext/constarrays.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef CONSTARRAYS_H -#define CONSTARRAYS_H - -static float const apu_vols [4] = { -0.25f, -0.5f, -1.0f, -0.25f }; - -static const int daysinmonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - -static const int table [0x40] = -{ - 0xFF10, 0,0xFF11,0xFF12,0xFF13,0xFF14, 0, 0, - 0xFF16,0xFF17, 0, 0,0xFF18,0xFF19, 0, 0, - 0xFF1A, 0,0xFF1B,0xFF1C,0xFF1D,0xFF1E, 0, 0, - 0xFF20,0xFF21, 0, 0,0xFF22,0xFF23, 0, 0, - 0xFF24,0xFF25, 0, 0,0xFF26, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37, - 0xFF38,0xFF39,0xFF3A,0xFF3B,0xFF3C,0xFF3D,0xFF3E,0xFF3F, -}; - -static const uint32_t TIMER_TICKS[4] = {0, 6, 8, 10}; - -static const uint8_t gamepakRamWaitState[4] = { 4, 3, 2, 8 }; - -static const uint32_t objTilesAddress [3] = {0x010000, 0x014000, 0x014000}; - -static const u32 AlphaClampLUT[64] = -{ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F -}; - -static const u32 map_sizes_rot[] = { 128, 256, 512, 1024 }; - -static const u32 map_widths[] = { 256, 512, 256, 512 }; -static const u32 map_heights[] = { 256, 256, 512, 512 }; - - -static const 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}; - - -static const uint8_t memoryWait_init[16] = - { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 }; -static const uint8_t memoryWaitSeq_init[16] = - { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 }; -static const uint8_t memoryWait32_init[16] = - { 0, 0, 5, 0, 0, 1, 1, 0, 7, 7, 9, 9, 13, 13, 4, 0 }; -static const uint8_t memoryWaitSeq32_init[16] = - { 0, 0, 5, 0, 0, 1, 1, 0, 5, 5, 9, 9, 17, 17, 4, 0 }; - -#endif diff --git a/vbanext/instance.cpp b/vbanext/instance.cpp deleted file mode 100644 index 14ebc4c208..0000000000 --- a/vbanext/instance.cpp +++ /dev/null @@ -1,13699 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -#define LSB_FIRST -#ifdef SPEEDHAX -#error NO SPEEDHAX -#endif -#define HAVE_HLE_BIOS - -#include "port.h" - -#include "instance.h" - -#include "sound_blargg.h" - -#include "constarrays.h" - -#include "newstate.h" - -#define INLINE - -class Gigazoid -{ - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// BEGIN MEMORY.CPP -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/*============================================================ - FLASH -============================================================ */ - - -#define FLASH_READ_ARRAY 0 -#define FLASH_CMD_1 1 -#define FLASH_CMD_2 2 -#define FLASH_AUTOSELECT 3 -#define FLASH_CMD_3 4 -#define FLASH_CMD_4 5 -#define FLASH_CMD_5 6 -#define FLASH_ERASE_COMPLETE 7 -#define FLASH_PROGRAM 8 -#define FLASH_SETBANK 9 - -uint8_t flashSaveMemory[FLASH_128K_SZ]; - -int flashState; // = FLASH_READ_ARRAY; -int flashReadState; // = FLASH_READ_ARRAY; -int flashSize; // = 0x10000; -int flashDeviceID; // = 0x1b; -int flashManufacturerID; // = 0x32; -int flashBank; // = 0; - -void flashInit (void) -{ - memset(flashSaveMemory, 0xff, sizeof(flashSaveMemory)); -} - -void flashReset() -{ - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - flashBank = 0; -} - -uint8_t flashRead(uint32_t address) -{ - address &= 0xFFFF; - - switch(flashReadState) { - case FLASH_READ_ARRAY: - return flashSaveMemory[(flashBank << 16) + address]; - case FLASH_AUTOSELECT: - switch(address & 0xFF) - { - case 0: - // manufacturer ID - return flashManufacturerID; - case 1: - // device ID - return flashDeviceID; - } - break; - case FLASH_ERASE_COMPLETE: - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - return 0xFF; - }; - return 0; -} - -void flashSaveDecide(uint32_t address, uint8_t byte) -{ - if (address == 0x0e005555) - cpuSaveGameFunc = &Gigazoid::flashWrite; - else - cpuSaveGameFunc = &Gigazoid::sramWrite; - - (this->*cpuSaveGameFunc)(address, byte); -} - -void flashWrite(uint32_t address, uint8_t byte) -{ - address &= 0xFFFF; - switch(flashState) { - case FLASH_READ_ARRAY: - if(address == 0x5555 && byte == 0xAA) - flashState = FLASH_CMD_1; - break; - case FLASH_CMD_1: - if(address == 0x2AAA && byte == 0x55) - flashState = FLASH_CMD_2; - else - flashState = FLASH_READ_ARRAY; - break; - case FLASH_CMD_2: - if(address == 0x5555) { - if(byte == 0x90) { - flashState = FLASH_AUTOSELECT; - flashReadState = FLASH_AUTOSELECT; - } else if(byte == 0x80) { - flashState = FLASH_CMD_3; - } else if(byte == 0xF0) { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } else if(byte == 0xA0) { - flashState = FLASH_PROGRAM; - } else if(byte == 0xB0 && flashSize == 0x20000) { - flashState = FLASH_SETBANK; - } else { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - } else { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - break; - case FLASH_CMD_3: - if(address == 0x5555 && byte == 0xAA) { - flashState = FLASH_CMD_4; - } else { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - break; - case FLASH_CMD_4: - if(address == 0x2AAA && byte == 0x55) { - flashState = FLASH_CMD_5; - } else { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - break; - case FLASH_CMD_5: - if(byte == 0x30) { - // SECTOR ERASE - memset(&flashSaveMemory[(flashBank << 16) + (address & 0xF000)], - 0, - 0x1000); - flashReadState = FLASH_ERASE_COMPLETE; - } else if(byte == 0x10) { - // CHIP ERASE - memset(flashSaveMemory, 0, flashSize); - flashReadState = FLASH_ERASE_COMPLETE; - } else { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - break; - case FLASH_AUTOSELECT: - if(byte == 0xF0) { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } else if(address == 0x5555 && byte == 0xAA) - flashState = FLASH_CMD_1; - else { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - break; - case FLASH_PROGRAM: - flashSaveMemory[(flashBank<<16)+address] = byte; - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - break; - case FLASH_SETBANK: - if(address == 0) { - flashBank = (byte & 1); - } - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - break; - } -} - -/*============================================================ - EEPROM -============================================================ */ -int eepromMode; // = EEPROM_IDLE; -int eepromByte; // = 0; -int eepromBits; // = 0; -int eepromAddress; // = 0; - -u8 eepromData[0x2000]; - -u8 eepromBuffer[16]; -bool eepromInUse; // = false; -int eepromSize; // = 512; - -void eepromInit (void) -{ - memset(eepromData, 255, sizeof(eepromData)); -} - -void eepromReset (void) -{ - eepromMode = EEPROM_IDLE; - eepromByte = 0; - eepromBits = 0; - eepromAddress = 0; - eepromInUse = false; - eepromSize = 512; -} - -int eepromRead (void) -{ - switch(eepromMode) - { - case EEPROM_IDLE: - case EEPROM_READADDRESS: - case EEPROM_WRITEDATA: - return 1; - case EEPROM_READDATA: - { - eepromBits++; - if(eepromBits == 4) { - eepromMode = EEPROM_READDATA2; - eepromBits = 0; - eepromByte = 0; - } - return 0; - } - case EEPROM_READDATA2: - { - int data = 0; - int address = eepromAddress << 3; - int mask = 1 << (7 - (eepromBits & 7)); - data = (eepromData[address+eepromByte] & mask) ? 1 : 0; - eepromBits++; - if((eepromBits & 7) == 0) - eepromByte++; - if(eepromBits == 0x40) - eepromMode = EEPROM_IDLE; - return data; - } - default: - return 0; - } - return 1; -} - -void eepromWrite(u8 value) -{ - if(cpuDmaCount == 0) - return; - int bit = value & 1; - switch(eepromMode) { - case EEPROM_IDLE: - eepromByte = 0; - eepromBits = 1; - eepromBuffer[eepromByte] = bit; - eepromMode = EEPROM_READADDRESS; - break; - case EEPROM_READADDRESS: - eepromBuffer[eepromByte] <<= 1; - eepromBuffer[eepromByte] |= bit; - eepromBits++; - if((eepromBits & 7) == 0) { - eepromByte++; - } - if(cpuDmaCount == 0x11 || cpuDmaCount == 0x51) { - if(eepromBits == 0x11) { - eepromInUse = true; - eepromSize = 0x2000; - eepromAddress = ((eepromBuffer[0] & 0x3F) << 8) | - ((eepromBuffer[1] & 0xFF)); - if(!(eepromBuffer[0] & 0x40)) { - eepromBuffer[0] = bit; - eepromBits = 1; - eepromByte = 0; - eepromMode = EEPROM_WRITEDATA; - } else { - eepromMode = EEPROM_READDATA; - eepromByte = 0; - eepromBits = 0; - } - } - } else { - if(eepromBits == 9) { - eepromInUse = true; - eepromAddress = (eepromBuffer[0] & 0x3F); - if(!(eepromBuffer[0] & 0x40)) { - eepromBuffer[0] = bit; - eepromBits = 1; - eepromByte = 0; - eepromMode = EEPROM_WRITEDATA; - } else { - eepromMode = EEPROM_READDATA; - eepromByte = 0; - eepromBits = 0; - } - } - } - break; - case EEPROM_READDATA: - case EEPROM_READDATA2: - // should we reset here? - eepromMode = EEPROM_IDLE; - break; - case EEPROM_WRITEDATA: - eepromBuffer[eepromByte] <<= 1; - eepromBuffer[eepromByte] |= bit; - eepromBits++; - if((eepromBits & 7) == 0) - eepromByte++; - if(eepromBits == 0x40) - { - eepromInUse = true; - // write data; - for(int i = 0; i < 8; i++) - eepromData[(eepromAddress << 3) + i] = eepromBuffer[i]; - } - else if(eepromBits == 0x41) - { - eepromMode = EEPROM_IDLE; - eepromByte = 0; - eepromBits = 0; - } - break; - } -} - -/*============================================================ - SRAM -============================================================ */ - -u8 sramRead(u32 address) -{ - return flashSaveMemory[address & 0xFFFF]; -} - -void sramWrite(u32 address, u8 byte) -{ - flashSaveMemory[address & 0xFFFF] = byte; -} - -void dummyWrite(u32 address, u8 byte) -{ -} - -/*============================================================ - RTC -============================================================ */ - -#define IDLE 0 -#define COMMAND 1 -#define DATA 2 -#define READDATA 3 - -typedef struct -{ - u8 byte0; - u8 byte1; - u8 byte2; - u8 command; - int dataLen; - int bits; - int state; - u8 data[12]; -} RTCCLOCKDATA; - -RTCCLOCKDATA rtcClockData; -bool rtcEnabled; // = false; - -u16 rtcRead(u32 address) -{ - switch(address) - { - case 0x80000c8: - return rtcClockData.byte2; - case 0x80000c6: - return rtcClockData.byte1; - case 0x80000c4: - return rtcClockData.byte0; - default: - return 0; - } -} - -static u8 toBCD(u8 value) -{ - value = value % 100; - int l = value % 10; - int h = value / 10; - return h * 16 + l; -} - -bool rtcWrite(u32 address, u16 value) -{ - if(!rtcEnabled) - return false; - - if(address == 0x80000c8) - rtcClockData.byte2 = (u8)value; // enable ? - else if(address == 0x80000c6) - rtcClockData.byte1 = (u8)value; // read/write - else if(address == 0x80000c4) - { - if(rtcClockData.byte2 & 1) // enable - { - if(rtcClockData.state == IDLE && rtcClockData.byte0 == 1 && value == 5) - { - rtcClockData.state = COMMAND; - rtcClockData.bits = 0; - rtcClockData.command = 0; - } - else if(!(rtcClockData.byte0 & 1) && (value & 1)) - { // bit transfer - rtcClockData.byte0 = (u8)value; - switch(rtcClockData.state) - { - case COMMAND: - rtcClockData.command |= ((value & 2) >> 1) << (7-rtcClockData.bits); - rtcClockData.bits++; - if(rtcClockData.bits == 8) - { - rtcClockData.bits = 0; - switch(rtcClockData.command) - { - case 0x60: - // not sure what this command does but it doesn't take parameters - // maybe it is a reset or stop - rtcClockData.state = IDLE; - rtcClockData.bits = 0; - break; - case 0x62: - // this sets the control state but not sure what those values are - rtcClockData.state = READDATA; - rtcClockData.dataLen = 1; - break; - case 0x63: - rtcClockData.dataLen = 1; - rtcClockData.data[0] = 0x40; - rtcClockData.state = DATA; - break; - case 0x64: - break; - case 0x65: - { - tm newtime; - GetTime(newtime); - rtcClockData.dataLen = 7; - rtcClockData.data[0] = toBCD(newtime.tm_year); - rtcClockData.data[1] = toBCD(newtime.tm_mon+1); - rtcClockData.data[2] = toBCD(newtime.tm_mday); - rtcClockData.data[3] = toBCD(newtime.tm_wday); - rtcClockData.data[4] = toBCD(newtime.tm_hour); - rtcClockData.data[5] = toBCD(newtime.tm_min); - rtcClockData.data[6] = toBCD(newtime.tm_sec); - rtcClockData.state = DATA; - } - break; - case 0x67: - { - tm newtime; - GetTime(newtime); - rtcClockData.dataLen = 3; - rtcClockData.data[0] = toBCD(newtime.tm_hour); - rtcClockData.data[1] = toBCD(newtime.tm_min); - rtcClockData.data[2] = toBCD(newtime.tm_sec); - rtcClockData.state = DATA; - } - break; - default: - //systemMessage(0, "Unknown RTC command %02x", rtcClockData.command); - rtcClockData.state = IDLE; - break; - } - } - break; - case DATA: - if(rtcClockData.byte1 & 2) - { - } - else - { - rtcClockData.byte0 = (rtcClockData.byte0 & ~2) | - ((rtcClockData.data[rtcClockData.bits >> 3] >> - (rtcClockData.bits & 7)) & 1)*2; - rtcClockData.bits++; - if(rtcClockData.bits == 8*rtcClockData.dataLen) - { - rtcClockData.bits = 0; - rtcClockData.state = IDLE; - } - } - break; - case READDATA: - if(!(rtcClockData.byte1 & 2)) { - } else { - rtcClockData.data[rtcClockData.bits >> 3] = - (rtcClockData.data[rtcClockData.bits >> 3] >> 1) | - ((value << 6) & 128); - rtcClockData.bits++; - if(rtcClockData.bits == 8*rtcClockData.dataLen) { - rtcClockData.bits = 0; - rtcClockData.state = IDLE; - } - } - break; - default: - break; - } - } else - rtcClockData.byte0 = (u8)value; - } - } - return true; -} - -void rtcReset (void) -{ - memset(&rtcClockData, 0, sizeof(rtcClockData)); - - rtcClockData.byte0 = 0; - rtcClockData.byte1 = 0; - rtcClockData.byte2 = 0; - rtcClockData.command = 0; - rtcClockData.dataLen = 0; - rtcClockData.bits = 0; - rtcClockData.state = IDLE; -} - -// guarantees predictable results regardless of stdlib -// could be modified later to better match internal quirks of -// the RTC chip actually used -struct -{ - int year; // 00..99 - int month; // 00..11 - int mday; // 01..31 - int wday; // 00..06 - int hour; // 00..23 - int min; // 00..59 - int sec; // 00..59 - - templatevoid SyncState(NewState *ns) - { - NSS(year); - NSS(month); - NSS(mday); - NSS(wday); - NSS(hour); - NSS(min); - NSS(sec); - } - -private: - int DaysInMonth() - { - // gba rtc doesn't understand 100/400 exceptions - int result = daysinmonth[month]; - if (month == 1 && year % 4 == 0) - result++; - return result; - } - -public: - void Increment() - { - sec++; - if (sec >= 60) - { - sec = 0; - min++; - if (min >= 60) - { - min = 0; - hour++; - if (hour >= 24) - { - hour = 0; - wday++; - if (wday >= 7) - wday = 0; - mday++; - if (mday >= DaysInMonth()) - { - mday = 1; - month++; - if (month >= 12) - { - month = 0; - year++; - if (year >= 100) - year = 0; - } - } - } - } - } - } - -} rtcInternalTime; - -void GetTime(tm ×) -{ - if (RTCUseRealTime) - { - time_t t = time(nullptr); - #if defined _MSC_VER - gmtime_s(×, &t); - #elif defined __MINGW32__ - tm *tmp = gmtime(&t); - times = *tmp; - #elif defined __GNUC__ - gmtime_r(&t, ×); - #endif - } - else - { - times.tm_hour = rtcInternalTime.hour; - times.tm_mday = rtcInternalTime.mday; - times.tm_min = rtcInternalTime.min; - times.tm_mon = rtcInternalTime.month; - times.tm_sec = rtcInternalTime.sec; - times.tm_wday = rtcInternalTime.wday; - times.tm_year = rtcInternalTime.year; - } -} - -int RTCTicks; -bool RTCUseRealTime; - -void AdvanceRTC(int ticks) -{ - RTCTicks += ticks; - while (RTCTicks >= 16777216) - { - RTCTicks -= 16777216; - rtcInternalTime.Increment(); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// END MEMORY.CPP -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// BEGIN SOUND.CPP -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define NR10 0x60 -#define NR11 0x62 -#define NR12 0x63 -#define NR13 0x64 -#define NR14 0x65 -#define NR21 0x68 -#define NR22 0x69 -#define NR23 0x6c -#define NR24 0x6d -#define NR30 0x70 -#define NR31 0x72 -#define NR32 0x73 -#define NR33 0x74 -#define NR34 0x75 -#define NR41 0x78 -#define NR42 0x79 -#define NR43 0x7c -#define NR44 0x7d -#define NR50 0x80 -#define NR51 0x81 -#define NR52 0x84 - -/* 1/100th of a second */ -//#define SOUND_CLOCK_TICKS_ 167772 -#define SOUNDVOLUME 0.5f -#define SOUNDVOLUME_ -1 - -/*============================================================ - CLASS DECLS -============================================================ */ - -class Blip_Buffer -{ - public: - templatevoid SyncState(NewState *ns) - { - NSS(clock_rate_); - NSS(length_); - NSS(sample_rate_); - NSS(factor_); - NSS(offset_); - // int32_t *buffer_; shouldn't need to save - NSS(buffer_size_); - NSS(reader_accum_); - - } - - Blip_Buffer::Blip_Buffer() - { - factor_ = INT_MAX; - buffer_ = 0; - buffer_size_ = 0; - sample_rate_ = 0; - clock_rate_ = 0; - length_ = 0; - - clear(); - } - - Blip_Buffer::~Blip_Buffer() - { - free(buffer_); - } - - void Blip_Buffer::clear( void) - { - offset_ = 0; - reader_accum_ = 0; - if (buffer_) - memset( buffer_, 0, (buffer_size_ + BLIP_BUFFER_EXTRA_) * sizeof (int32_t) ); - } - - const char * Blip_Buffer::set_sample_rate( long new_rate, int msec ) - { - /* start with maximum length that resampled time can represent*/ - long new_size = (ULONG_MAX >> BLIP_BUFFER_ACCURACY) - BLIP_BUFFER_EXTRA_ - 64; - if ( msec != 0) - { - long s = (new_rate * (msec + 1) + 999) / 1000; - if ( s < new_size ) - new_size = s; - } - - if ( buffer_size_ != new_size ) - { - void* p = realloc( buffer_, (new_size + BLIP_BUFFER_EXTRA_) * sizeof *buffer_ ); - if ( !p ) - return "Out of memory"; - buffer_ = (int32_t *) p; - } - - buffer_size_ = new_size; - - /* update things based on the sample rate*/ - sample_rate_ = new_rate; - length_ = new_size * 1000 / new_rate - 1; - - /* update these since they depend on sample rate*/ - if ( clock_rate_ ) - factor_ = clock_rate_factor( clock_rate_); - - clear(); - - return 0; - } - - /* Sets number of source time units per second */ - - uint32_t Blip_Buffer::clock_rate_factor( long rate ) const - { - double ratio = (double) sample_rate_ / rate; - int32_t factor = (int32_t) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 ); - return (uint32_t) factor; - } - long clock_rate_; - int length_; /* Length of buffer in milliseconds*/ - long sample_rate_; /* Current output sample rate*/ - uint32_t factor_; - uint32_t offset_; - int32_t *buffer_; - int32_t buffer_size_; - int32_t reader_accum_; - private: - Blip_Buffer( const Blip_Buffer& ); - Blip_Buffer& operator = ( const Blip_Buffer& ); -}; - -class Blip_Synth -{ - public: - int delta_factor; - - templatevoid SyncState(NewState *ns) - { - NSS(delta_factor); - } - - void volume( double v ) { delta_factor = int ((v * 1.0) * (1L << BLIP_SAMPLE_BITS) + 0.5); } - INLINE void Blip_Synth::offset_resampled( uint32_t time, int delta, Blip_Buffer* blip_buf ) const - { - int32_t left, right, phase; - int32_t *buf; - - delta *= delta_factor; - buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY); - phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & BLIP_RES_MIN_ONE); - - left = buf [0] + delta; - - right = (delta >> BLIP_PHASE_BITS) * phase; - - left -= right; - right += buf [1]; - - buf [0] = left; - buf [1] = right; - } - - INLINE void Blip_Synth::offset( int32_t t, int delta, Blip_Buffer* buf ) const - { - offset_resampled( t * buf->factor_ + buf->offset_, delta, buf ); - } - void offset_inline( int32_t t, int delta, Blip_Buffer* buf ) const { - offset_resampled( t * buf->factor_ + buf->offset_, delta, buf ); - } -}; - -#define TRIGGER_MASK 0x80 -#define LENGTH_ENABLED 0x40 - -#define VOLUME_SHIFT_PLUS_FOUR 6 -#define SIZE20_MASK 0x20 - - - -#define reload_sweep_timer() \ - sweep_delay = (regs [0] & PERIOD_MASK) >> 4; \ - if ( !sweep_delay ) \ - sweep_delay = 8; - -class Gb_Osc -{ - public: - Blip_Buffer* outputs [4]; /* NULL, right, left, center*/ - Blip_Buffer* output; /* where to output sound*/ - 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*/ - Blip_Synth const* good_synth; - Blip_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*/ - - templatevoid SyncState(NewState *ns) - { - EBS(output, -1); - EVS(output, outputs[0], 0); - EVS(output, outputs[1], 1); - EVS(output, outputs[2], 2); - EVS(output, outputs[3], 3); - EES(output, nullptr); - - NSS(mode); - NSS(dac_off_amp); - NSS(last_amp); - - NSS(delay); - NSS(length_ctr); - NSS(phase); - NSS(enabled); - } - - void Gb_Osc::clock_length() - { - if ( (regs [4] & LENGTH_ENABLED) && length_ctr ) - { - if ( --length_ctr <= 0 ) - enabled = false; - } - } - void Gb_Osc::reset() - { - output = 0; - last_amp = 0; - delay = 0; - phase = 0; - enabled = false; - } - protected: - INLINE void Gb_Osc::update_amp( int32_t time, int new_amp ) - { - int delta = new_amp - last_amp; - if ( delta ) - { - last_amp = new_amp; - med_synth->offset( time, delta, output ); - } - } - 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)) - 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; - } -}; - -class Gb_Env : public Gb_Osc -{ - public: - int env_delay; - int volume; - bool env_enabled; - - templatevoid SyncState(NewState *ns) - { - Gb_Osc::SyncState(ns); - NSS(env_delay); - NSS(volume); - NSS(env_enabled); - } - - 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; - } - } - 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 ( !GB_ENV_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 ( !GB_ENV_DAC_ENABLED() ) - enabled = false; - return true; - } - } - return false; - } - - void reset() - { - env_delay = 0; - volume = 0; - Gb_Osc::reset(); - } - private: - INLINE void Gb_Env::zombie_volume( int old, int data ) - { - int v = volume; - - // 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++; - volume = v & 0x0F; - } - INLINE int Gb_Env::reload_env_timer() - { - int raw = regs [2] & 7; - env_delay = (raw ? raw : 8); - return raw; - } -}; - -class Gb_Square : public Gb_Env -{ -public: - templatevoid SyncState(NewState *ns) - { - Gb_Env::SyncState(ns); - } - - 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 & (CLK_MUL_MUL_4 - 1)) + period(); - return result; - } - void Gb_Square::run( int32_t time, int32_t end_time ) - { - /* Calc duty and phase*/ - static unsigned char const duty_offsets [4] = { 1, 1, 3, 7 }; - static unsigned char const duties [4] = { 1, 2, 4, 6 }; - int const duty_code = regs [1] >> 6; - int32_t duty_offset = duty_offsets [duty_code]; - int32_t duty = duties [duty_code]; - /* AGB uses inverted duty*/ - duty_offset -= duty; - duty = 8 - duty; - int ph = (phase + duty_offset) & 7; - - /* Determine what will be generated*/ - int vol = 0; - Blip_Buffer* const out = output; - if ( out ) - { - int amp = dac_off_amp; - if ( GB_ENV_DAC_ENABLED() ) - { - if ( enabled ) - vol = volume; - - amp = -(vol >> 1); - - /* Play inaudible frequencies as constant amplitude*/ - if ( GB_OSC_FREQUENCY() >= 0x7FA && delay < CLK_MUL_MUL_32 ) - { - 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 = period(); - if ( !vol ) - { - /* Maintain phase when not playing*/ - int count = (end_time - time + per - 1) / per; - ph += count; /* will be masked below*/ - time += (int32_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; - } - phase = (ph - duty_offset) & 7; - } - delay = time - end_time; - } - - 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 - GB_OSC_FREQUENCY()) * (CLK_MUL_MUL_4); } -}; - -class Gb_Sweep_Square : public Gb_Square -{ - public: - int sweep_freq; - int sweep_delay; - bool sweep_enabled; - bool sweep_neg; - - templatevoid SyncState(NewState *ns) - { - Gb_Square::SyncState(ns); - NSS(sweep_freq); - NSS(sweep_delay); - NSS(sweep_enabled); - NSS(sweep_neg); - } - - 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 ); - } - } - } - 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 = GB_OSC_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 reset() - { - sweep_freq = 0; - sweep_delay = 0; - sweep_enabled = false; - sweep_neg = false; - Gb_Square::reset(); - } - private: - void Gb_Sweep_Square::calc_sweep( bool update ) - { - int shift, delta, freq; - - shift = regs [0] & SHIFT_MASK; - delta = sweep_freq >> shift; - sweep_neg = (regs [0] & 0x08) != 0; - 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); - } - } -}; - -class Gb_Noise : public Gb_Env -{ - public: - int divider; /* noise has more complex frequency divider setup*/ - - templatevoid SyncState(NewState *ns) - { - Gb_Env::SyncState(ns); - NSS(divider); - } - - /* Quickly runs LFSR for a large number of clocks. For use when noise is generating*/ - /* no sound.*/ - unsigned run_lfsr( unsigned s, unsigned mask, int count ) - { - /* optimization used in several places:*/ - /* ((s & (1 << b)) << n) ^ ((s & (1 << b)) << (n + 1)) = (s & (1 << b)) * (3 << n)*/ - - if ( mask == 0x4000 ) - { - 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*/ - do{ - --count; - s = ((s & 2) * (3 << 13)) ^ (s >> 1); - }while(count >= 0); - - /* Convert back to Fibonacci configuration*/ - s &= 0x7FFF; - } - else if ( count < 8) - { - /* won't fully replace upper 8 bits, so have to do the unoptimized way*/ - do{ - --count; - s = (s >> 1 | mask) ^ (mask & -((s - 1) & 2)); - }while(count >= 0); - } - 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) << 7; - - /* 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( int32_t time, int32_t end_time ) - { - /* Determine what will be generated*/ - int vol = 0; - Blip_Buffer* const out = output; - if ( out ) - { - int amp = dac_off_amp; - if ( GB_ENV_DAC_ENABLED() ) - { - if ( enabled ) - vol = volume; - - amp = -(vol >> 1); - - if ( !(phase & 1) ) - { - amp += vol; - vol = -vol; - } - } - - /* AGB negates final output*/ - vol = -vol; - amp = -amp; - - update_amp( time, amp ); - } - - /* Run timer and calculate time of next LFSR clock*/ - static unsigned char 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 = GB_NOISE_PERIOD2(8); - 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 = GB_NOISE_LFSR_MASK(); - unsigned bits = phase; - - int per = GB_NOISE_PERIOD2( period1 * 8 ); - if ( GB_NOISE_PERIOD2_INDEX() >= 0xE ) - { - time = end_time; - } - else if ( !vol ) - { - /* Maintain phase when not playing*/ - int count = (end_time - time + per - 1) / per; - time += (int32_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; - } - phase = bits; - } - } - 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 += CLK_MUL_MUL_8; - } - } - - void reset() - { - divider = 0; - Gb_Env::reset(); - delay = CLK_MUL_MUL_4; /* TODO: remove?*/ - } -}; - -class Gb_Wave : public Gb_Osc -{ - public: - int sample_buf; /* last wave RAM byte read (hardware has this as well)*/ - int agb_mask; /* 0xFF if AGB features enabled, 0 otherwise*/ - uint8_t* wave_ram; /* 32 bytes (64 nybbles), stored in APU*/ - - templatevoid SyncState(NewState *ns) - { - Gb_Osc::SyncState(ns); - NSS(sample_buf); - NSS(agb_mask); - } - - INLINE void Gb_Wave::write_register( int frame_phase, int reg, int old_data, int data ) - { - switch ( reg ) - { - case 0: - if ( !GB_WAVE_DAC_ENABLED() ) - enabled = false; - break; - - case 1: - length_ctr = 256 - data; - break; - - case 4: - bool was_enabled = enabled; - if ( write_trig( frame_phase, 256, old_data ) ) - { - if ( !GB_WAVE_DAC_ENABLED() ) - enabled = false; - phase = 0; - delay = period() + CLK_MUL_MUL_6; - } - } - } - void Gb_Wave::run( int32_t time, int32_t end_time ) - { - /* Calc volume*/ - static unsigned char const volumes [8] = { 0, 4, 2, 1, 3, 3, 3, 3 }; - 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 = output; - if ( out ) - { - int amp = dac_off_amp; - if ( GB_WAVE_DAC_ENABLED() ) - { - /* Play inaudible frequencies as constant amplitude*/ - amp = 128; /* really depends on average of all samples in wave*/ - - /* if delay is larger, constant amplitude won't start yet*/ - if ( GB_OSC_FREQUENCY() <= 0x7FB || delay > CLK_MUL_MUL_15 ) - { - if ( volume_mul ) - playing = (int) enabled; - - amp = (sample_buf << (phase << 2 & 4) & 0xF0) * playing; - } - - amp = ((amp * volume_mul) >> VOLUME_SHIFT_PLUS_FOUR) - DAC_BIAS; - } - update_amp( time, amp ); - } - - /* Generate wave*/ - time += delay; - if ( time < end_time ) - { - unsigned char const* wave = wave_ram; - - /* wave size and bank*/ - 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_DIV_TWO - (swap_banks >> 1); - } - - int ph = phase ^ swap_banks; - ph = (ph + 1) & wave_mask; /* pre-advance*/ - - int const per = period(); - if ( !playing ) - { - /* Maintain phase when not playing*/ - int count = (end_time - time + per - 1) / per; - ph += count; /* will be masked below*/ - time += (int32_t) count * per; - } - else - { - /* Output amplitude transitions*/ - int lamp = 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_PLUS_FOUR; - - int delta = amp - lamp; - if ( delta ) - { - lamp = amp; - med_synth->offset_inline( time, delta, out ); - } - time += per; - } - while ( time < end_time ); - 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]; - - phase = ph ^ swap_banks; /* undo swapped banks*/ - } - delay = time - end_time; - } - - /* Reads/writes wave RAM*/ - INLINE int Gb_Wave::read( unsigned addr ) const - { - int index; - - if(enabled) - index = access( addr ); - else - index = addr & 0x0F; - - unsigned char const * wave_bank = &wave_ram[(~regs[0] & BANK40_MASK) >> 2 & agb_mask]; - - return (index < 0 ? 0xFF : wave_bank[index]); - } - - INLINE void Gb_Wave::write( unsigned addr, int data ) - { - int index; - - if(enabled) - index = access( addr ); - else - index = addr & 0x0F; - - unsigned char * wave_bank = &wave_ram[(~regs[0] & BANK40_MASK) >> 2 & agb_mask]; - - if ( index >= 0 ) - wave_bank[index] = data;; - } - - - void reset() - { - sample_buf = 0; - Gb_Osc::reset(); - } - - private: - friend class Gb_Apu; - - /* Frequency timer period*/ - int period() const { return (2048 - GB_OSC_FREQUENCY()) * (CLK_MUL_MUL_2); } - - void Gb_Wave::corrupt_wave() - { - int pos = ((phase + 1) & BANK_SIZE_MIN_ONE) >> 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]; - } - - /* Wave index that would be accessed, or -1 if no access would occur*/ - int Gb_Wave::access( unsigned addr ) const - { - //if ( mode != MODE_AGB ) - //{ - // addr = (phase & BANK_SIZE_MIN_ONE) >> 1; - //} - return addr & 0x0F; - } -}; - -/*============================================================ - INLINE CLASS FUNCS -============================================================ */ - -int16_t soundFinalWave [2048]; -static const long soundSampleRate = 44100; // = 22050; -//int SOUND_CLOCK_TICKS; // = SOUND_CLOCK_TICKS_; -//int soundTicks; // = SOUND_CLOCK_TICKS_; -int soundTicksUp; // counts up from 0 being the last time the blips were emptied - -int soundEnableFlag; // = 0x3ff; /* emulator channels enabled*/ - -struct gba_pcm_t -{ - int last_amp; - int last_time; - int shift; - Blip_Buffer* output; - - templatevoid SyncState(NewState *ns, Gigazoid *g) - { - NSS(last_amp); - NSS(last_time); - NSS(shift); - - // tricky - EBS(output, -1); - EVS(output, &g->bufs_buffer[0], 0); - EVS(output, &g->bufs_buffer[1], 1); - EVS(output, &g->bufs_buffer[2], 2); - EES(output, nullptr); - } -}; - -struct gba_pcm_fifo_t -{ - bool enabled; - uint8_t fifo [32]; - int count; - int dac; - int readIndex; - int writeIndex; - int which; - int timer; - gba_pcm_t pcm; - - templatevoid SyncState(NewState *ns, Gigazoid *g) - { - NSS(enabled); - NSS(fifo); - NSS(count); - NSS(dac); - NSS(readIndex); - NSS(writeIndex); - NSS(which); - NSS(timer); - SSS_HACKY(pcm, g); - } -}; - -gba_pcm_fifo_t pcm [2]; - - -Blip_Synth pcm_synth; // 32 kHz, 16 kHz, 8 kHz - -Blip_Buffer bufs_buffer [BUFS_SIZE]; -int mixer_samples_read; - -void gba_pcm_init (void) -{ - pcm[0].pcm.output = 0; - pcm[0].pcm.last_time = 0; - pcm[0].pcm.last_amp = 0; - pcm[0].pcm.shift = 0; - - pcm[1].pcm.output = 0; - pcm[1].pcm.last_time = 0; - pcm[1].pcm.last_amp = 0; - pcm[1].pcm.shift = 0; -} - -void gba_pcm_apply_control( int pcm_idx, int idx ) -{ - int ch = 0; - pcm[pcm_idx].pcm.shift = ~ioMem [SGCNT0_H] >> (2 + idx) & 1; - - if ( (ioMem [NR52] & 0x80) ) - ch = ioMem [SGCNT0_H+1] >> (idx << 2) & 3; - - Blip_Buffer* out = 0; - switch ( ch ) - { - case 1: - out = &bufs_buffer[1]; - break; - case 2: - out = &bufs_buffer[0]; - break; - case 3: - out = &bufs_buffer[2]; - break; - } - - if ( pcm[pcm_idx].pcm.output != out ) - { - if ( pcm[pcm_idx].pcm.output ) - pcm_synth.offset( soundTicksUp, -pcm[pcm_idx].pcm.last_amp, pcm[pcm_idx].pcm.output ); - pcm[pcm_idx].pcm.last_amp = 0; - pcm[pcm_idx].pcm.output = out; - } -} - -/*============================================================ - GB APU -============================================================ */ - -/* 0: Square 1, 1: Square 2, 2: Wave, 3: Noise */ -#define OSC_COUNT 4 - -/* Resets hardware to initial power on state BEFORE boot ROM runs. Mode selects*/ -/* sound hardware. Additional AGB wave features are enabled separately.*/ -#define MODE_AGB 2 - -#define START_ADDR 0xFF10 -#define END_ADDR 0xFF3F - -/* 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.*/ -#define REGISTER_COUNT 48 -#define REGS_SIZE 64 - -/* Clock rate that sound hardware runs at. - * formula: 4194304 * 4 - * */ -#define CLOCK_RATE 16777216 - -struct gb_apu_t -{ - bool reduce_clicks_; - uint8_t regs[REGS_SIZE]; // last values written to registers - int32_t last_time; // time sound emulator has been run to - int32_t frame_time; // time of next frame sequencer action - int32_t frame_period; // clocks between each frame sequencer step - int32_t frame_phase; // phase of next frame sequencer step - double volume_; - Gb_Osc* oscs [OSC_COUNT]; - Gb_Sweep_Square square1; - Gb_Square square2; - Gb_Wave wave; - Gb_Noise noise; - Blip_Synth good_synth; - Blip_Synth med_synth; - - templatevoid SyncState(NewState *ns) - { - NSS(reduce_clicks_); - NSS(regs); - NSS(last_time); - NSS(frame_time); - NSS(frame_period); - NSS(frame_phase); - NSS(volume_); - SSS(square1); - SSS(square2); - SSS(wave); - SSS(noise); - - SSS(good_synth); - SSS(med_synth); - } -} gb_apu; - -#define VOL_REG 0xFF24 -#define STEREO_REG 0xFF25 -#define STATUS_REG 0xFF26 -#define WAVE_RAM 0xFF30 -#define POWER_MASK 0x80 - -#define OSC_COUNT 4 - -void gb_apu_reduce_clicks( bool reduce ) -{ - gb_apu.reduce_clicks_ = reduce; - - /* Click reduction makes DAC off generate same output as volume 0*/ - int dac_off_amp = 0; - - gb_apu.oscs[0]->dac_off_amp = dac_off_amp; - gb_apu.oscs[1]->dac_off_amp = dac_off_amp; - gb_apu.oscs[2]->dac_off_amp = dac_off_amp; - gb_apu.oscs[3]->dac_off_amp = dac_off_amp; - - /* AGB always eliminates clicks on wave channel using same method*/ - gb_apu.wave.dac_off_amp = -DAC_BIAS; -} - -void gb_apu_synth_volume( int iv ) -{ - double v = gb_apu.volume_ * 0.60 / OSC_COUNT / 15 /*steps*/ / 8 /*master vol range*/ * iv; - gb_apu.good_synth.volume( v ); - gb_apu.med_synth .volume( v ); -} - -void gb_apu_apply_volume (void) -{ - int data, left, right, vol_tmp; - data = gb_apu.regs [VOL_REG - START_ADDR]; - left = data >> 4 & 7; - right = data & 7; - vol_tmp = left < right ? right : left; - gb_apu_synth_volume( vol_tmp + 1 ); -} - -void gb_apu_silence_osc( Gb_Osc& o ) -{ - int delta; - - delta = -o.last_amp; - if ( delta ) - { - o.last_amp = 0; - if ( o.output ) - { - gb_apu.med_synth.offset( gb_apu.last_time, delta, o.output ); - } - } -} - -void gb_apu_run_until_( int32_t end_time ) -{ - int32_t time; - - do{ - /* run oscillators*/ - time = end_time; - if ( time > gb_apu.frame_time ) - time = gb_apu.frame_time; - - gb_apu.square1.run( gb_apu.last_time, time ); - gb_apu.square2.run( gb_apu.last_time, time ); - gb_apu.wave .run( gb_apu.last_time, time ); - gb_apu.noise .run( gb_apu.last_time, time ); - gb_apu.last_time = time; - - if ( time == end_time ) - break; - - /* run frame sequencer*/ - gb_apu.frame_time += gb_apu.frame_period * CLK_MUL; - switch ( gb_apu.frame_phase++ ) - { - case 2: - case 6: - /* 128 Hz*/ - gb_apu.square1.clock_sweep(); - case 0: - case 4: - /* 256 Hz*/ - gb_apu.square1.clock_length(); - gb_apu.square2.clock_length(); - gb_apu.wave .clock_length(); - gb_apu.noise .clock_length(); - break; - - case 7: - /* 64 Hz*/ - gb_apu.frame_phase = 0; - gb_apu.square1.clock_envelope(); - gb_apu.square2.clock_envelope(); - gb_apu.noise .clock_envelope(); - } - }while(1); -} - -void gb_apu_write_osc( int index, int reg, int old_data, int data ) -{ - reg -= index * 5; - switch ( index ) - { - case 0: - gb_apu.square1.write_register( gb_apu.frame_phase, reg, old_data, data ); - break; - case 1: - gb_apu.square2.write_register( gb_apu.frame_phase, reg, old_data, data ); - break; - case 2: - gb_apu.wave.write_register( gb_apu.frame_phase, reg, old_data, data ); - break; - case 3: - gb_apu.noise.write_register( gb_apu.frame_phase, reg, old_data, data ); - break; - } -} - -INLINE int gb_apu_calc_output( int osc ) -{ - int bits = gb_apu.regs [STEREO_REG - START_ADDR] >> osc; - return (bits >> 3 & 2) | (bits & 1); -} - -void gb_apu_write_register( int32_t time, unsigned addr, int data ) -{ - int reg = addr - START_ADDR; - if ( (unsigned) reg >= REGISTER_COUNT ) - return; - - if ( addr < STATUS_REG && !(gb_apu.regs [STATUS_REG - START_ADDR] & POWER_MASK) ) - return; /* Power is off*/ - - if ( time > gb_apu.last_time ) - gb_apu_run_until_( time ); - - if ( addr >= WAVE_RAM ) - { - gb_apu.wave.write( addr, data ); - } - else - { - int old_data = gb_apu.regs [reg]; - gb_apu.regs [reg] = data; - - if ( addr < VOL_REG ) - gb_apu_write_osc( reg / 5, reg, old_data, data ); /* Oscillator*/ - else if ( addr == VOL_REG && data != old_data ) - { - /* Master volume*/ - for ( int i = OSC_COUNT; --i >= 0; ) - gb_apu_silence_osc( *gb_apu.oscs [i] ); - - gb_apu_apply_volume(); - } - else if ( addr == STEREO_REG ) - { - /* Stereo panning*/ - for ( int i = OSC_COUNT; --i >= 0; ) - { - Gb_Osc& o = *gb_apu.oscs [i]; - Blip_Buffer* out = o.outputs [gb_apu_calc_output( i )]; - if ( o.output != out ) - { - gb_apu_silence_osc( o ); - o.output = out; - } - } } - else if ( addr == STATUS_REG && (data ^ old_data) & POWER_MASK ) - { - /* Power control*/ - gb_apu.frame_phase = 0; - for ( int i = OSC_COUNT; --i >= 0; ) - gb_apu_silence_osc( *gb_apu.oscs [i] ); - - for ( int i = 0; i < 32; i++ ) - gb_apu.regs [i] = 0; - - gb_apu.square1.reset(); - gb_apu.square2.reset(); - gb_apu.wave .reset(); - gb_apu.noise .reset(); - - gb_apu_apply_volume(); - - gb_apu.square1.length_ctr = 64; - gb_apu.square2.length_ctr = 64; - gb_apu.wave .length_ctr = 256; - gb_apu.noise .length_ctr = 64; - - gb_apu.regs [STATUS_REG - START_ADDR] = data; - } - } -} - -void gb_apu_reset( uint32_t mode, bool agb_wave ) -{ - /* Hardware mode*/ - mode = MODE_AGB; /* using AGB wave features implies AGB hardware*/ - gb_apu.wave.agb_mask = 0xFF; - gb_apu.oscs [0]->mode = mode; - gb_apu.oscs [1]->mode = mode; - gb_apu.oscs [2]->mode = mode; - gb_apu.oscs [3]->mode = mode; - gb_apu_reduce_clicks( gb_apu.reduce_clicks_ ); - - /* Reset state*/ - gb_apu.frame_time = 0; - gb_apu.last_time = 0; - gb_apu.frame_phase = 0; - - for ( int i = 0; i < 32; i++ ) - gb_apu.regs [i] = 0; - - gb_apu.square1.reset(); - gb_apu.square2.reset(); - gb_apu.wave .reset(); - gb_apu.noise .reset(); - - gb_apu_apply_volume(); - - gb_apu.square1.length_ctr = 64; - gb_apu.square2.length_ctr = 64; - gb_apu.wave .length_ctr = 256; - gb_apu.noise .length_ctr = 64; - - /* Load initial wave RAM*/ - static unsigned char 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)*/ - gb_apu_write_register( 0, 0xFF1A, b * 0x40 ); - for ( unsigned i = 0; i < sizeof initial_wave [0]; i++ ) - gb_apu_write_register( 0, i + WAVE_RAM, initial_wave [1] [i] ); - } -} - -void gb_apu_new(void) -{ - int i; - - gb_apu.wave.wave_ram = &gb_apu.regs [WAVE_RAM - START_ADDR]; - - gb_apu.oscs [0] = &gb_apu.square1; - gb_apu.oscs [1] = &gb_apu.square2; - gb_apu.oscs [2] = &gb_apu.wave; - gb_apu.oscs [3] = &gb_apu.noise; - - for ( i = OSC_COUNT; --i >= 0; ) - { - Gb_Osc& o = *gb_apu.oscs [i]; - o.regs = &gb_apu.regs [i * 5]; - o.output = 0; - o.outputs [0] = 0; - o.outputs [1] = 0; - o.outputs [2] = 0; - o.outputs [3] = 0; - o.good_synth = &gb_apu.good_synth; - o.med_synth = &gb_apu.med_synth; - } - - gb_apu.reduce_clicks_ = false; - gb_apu.frame_period = 4194304 / 512; /* 512 Hz*/ - - gb_apu.volume_ = 1.0; - gb_apu_reset(MODE_AGB, false); -} - - - -void gb_apu_set_output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right, int osc ) -{ - int i; - - i = osc; - do - { - Gb_Osc& o = *gb_apu.oscs [i]; - o.outputs [1] = right; - o.outputs [2] = left; - o.outputs [3] = center; - o.output = o.outputs [gb_apu_calc_output( i )]; - ++i; - } - while ( i < osc ); -} - -void gb_apu_volume( double v ) -{ - if ( gb_apu.volume_ != v ) - { - gb_apu.volume_ = v; - gb_apu_apply_volume(); - } -} - -void gb_apu_apply_stereo (void) -{ - int i; - - for ( i = OSC_COUNT; --i >= 0; ) - { - Gb_Osc& o = *gb_apu.oscs [i]; - Blip_Buffer* out = o.outputs [gb_apu_calc_output( i )]; - if ( o.output != out ) - { - gb_apu_silence_osc( o ); - o.output = out; - } - } -} - - -/*============================================================ - GB OSCS -============================================================ */ - - -/*============================================================ - BLIP BUFFER -============================================================ */ - -/* Blip_Buffer 0.4.1. http://www.slack.net/~ant */ - -#define FIXED_SHIFT 12 -#define SAL_FIXED_SHIFT 4096 -#define TO_FIXED( f ) int ((f) * SAL_FIXED_SHIFT) -#define FROM_FIXED( f ) ((f) >> FIXED_SHIFT) - - - -/*============================================================ - STEREO BUFFER -============================================================ */ - -/* Uses three buffers (one for center) and outputs stereo sample pairs. */ - -#define STEREO_BUFFER_SAMPLES_AVAILABLE() ((long)(bufs_buffer[0].offset_ - mixer_samples_read) << 1) -#define stereo_buffer_samples_avail() ((((bufs_buffer [0].offset_ >> BLIP_BUFFER_ACCURACY) - mixer_samples_read) << 1)) - - -const char * stereo_buffer_set_sample_rate( long rate, int msec ) -{ - mixer_samples_read = 0; - for ( int i = BUFS_SIZE; --i >= 0; ) - RETURN_ERR( bufs_buffer [i].set_sample_rate( rate, msec ) ); - return 0; -} - -void stereo_buffer_clock_rate( long rate ) -{ - bufs_buffer[2].factor_ = bufs_buffer [2].clock_rate_factor( rate ); - bufs_buffer[1].factor_ = bufs_buffer [1].clock_rate_factor( rate ); - bufs_buffer[0].factor_ = bufs_buffer [0].clock_rate_factor( rate ); -} - -void stereo_buffer_clear (void) -{ - mixer_samples_read = 0; - bufs_buffer [2].clear(); - bufs_buffer [1].clear(); - bufs_buffer [0].clear(); -} - -/* mixers use a single index value to improve performance on register-challenged processors - * offset goes from negative to zero*/ - -INLINE void stereo_buffer_mixer_read_pairs( int16_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.*/ - mixer_samples_read += count; - int16_t* outtemp = out + count * STEREO; - - /* do left + center and right + center separately to reduce register load*/ - Blip_Buffer* buf = &bufs_buffer [2]; - { - --buf; - --outtemp; - - BLIP_READER_BEGIN( side, *buf ); - BLIP_READER_BEGIN( center, bufs_buffer[2] ); - - BLIP_READER_ADJ_( side, mixer_samples_read ); - BLIP_READER_ADJ_( center, mixer_samples_read ); - - int offset = -count; - do - { - int s = (center_reader_accum + side_reader_accum) >> 14; - BLIP_READER_NEXT_IDX_( side, offset ); - BLIP_READER_NEXT_IDX_( center, offset ); - BLIP_CLAMP( s, s ); - - ++offset; /* before write since out is decremented to slightly before end*/ - outtemp [offset * STEREO] = (int16_t) s; - }while ( offset ); - - BLIP_READER_END( side, *buf ); - } - { - --buf; - --outtemp; - - BLIP_READER_BEGIN( side, *buf ); - BLIP_READER_BEGIN( center, bufs_buffer[2] ); - - BLIP_READER_ADJ_( side, mixer_samples_read ); - BLIP_READER_ADJ_( center, mixer_samples_read ); - - int offset = -count; - do - { - int s = (center_reader_accum + side_reader_accum) >> 14; - BLIP_READER_NEXT_IDX_( side, offset ); - BLIP_READER_NEXT_IDX_( center, offset ); - BLIP_CLAMP( s, s ); - - ++offset; /* before write since out is decremented to slightly before end*/ - outtemp [offset * STEREO] = (int16_t) s; - }while ( offset ); - - BLIP_READER_END( side, *buf ); - - /* only end center once*/ - BLIP_READER_END( center, bufs_buffer[2] ); - } -} - -void blip_buffer_remove_all_samples( long count ) -{ - uint32_t new_offset = (uint32_t)count << BLIP_BUFFER_ACCURACY; - /* BLIP BUFFER #1 */ - bufs_buffer[0].offset_ -= new_offset; - bufs_buffer[1].offset_ -= new_offset; - bufs_buffer[2].offset_ -= new_offset; - - /* copy remaining samples to beginning and clear old samples*/ - long remain = (bufs_buffer[0].offset_ >> BLIP_BUFFER_ACCURACY) + BLIP_BUFFER_EXTRA_; - memmove( bufs_buffer[0].buffer_, bufs_buffer[0].buffer_ + count, remain * sizeof *bufs_buffer[0].buffer_ ); - memset( bufs_buffer[0].buffer_ + remain, 0, count * sizeof(*bufs_buffer[0].buffer_)); - - remain = (bufs_buffer[1].offset_ >> BLIP_BUFFER_ACCURACY) + BLIP_BUFFER_EXTRA_; - memmove( bufs_buffer[1].buffer_, bufs_buffer[1].buffer_ + count, remain * sizeof *bufs_buffer[1].buffer_ ); - memset( bufs_buffer[1].buffer_ + remain, 0, count * sizeof(*bufs_buffer[1].buffer_)); - - remain = (bufs_buffer[2].offset_ >> BLIP_BUFFER_ACCURACY) + BLIP_BUFFER_EXTRA_; - memmove( bufs_buffer[2].buffer_, bufs_buffer[2].buffer_ + count, remain * sizeof *bufs_buffer[2].buffer_ ); - memset( bufs_buffer[2].buffer_ + remain, 0, count * sizeof(*bufs_buffer[2].buffer_)); -} - -long stereo_buffer_read_samples( int16_t * out, long out_size ) -{ - int pair_count; - - out_size = (STEREO_BUFFER_SAMPLES_AVAILABLE() < out_size) ? STEREO_BUFFER_SAMPLES_AVAILABLE() : out_size; - - pair_count = int (out_size >> 1); - if ( pair_count ) - { - stereo_buffer_mixer_read_pairs( out, pair_count ); - blip_buffer_remove_all_samples( mixer_samples_read ); - mixer_samples_read = 0; - } - return out_size; -} - -void gba_to_gb_sound_parallel( int * __restrict addr, int * __restrict addr2 ) -{ - uint32_t addr1_table = *addr - 0x60; - uint32_t addr2_table = *addr2 - 0x60; - *addr = table [addr1_table]; - *addr2 = table [addr2_table]; -} - -void pcm_fifo_write_control( int data, int data2) -{ - pcm[0].enabled = (data & 0x0300) ? true : false; - pcm[0].timer = (data & 0x0400) ? 1 : 0; - - if ( data & 0x0800 ) - { - // Reset - pcm[0].writeIndex = 0; - pcm[0].readIndex = 0; - pcm[0].count = 0; - pcm[0].dac = 0; - memset(pcm[0].fifo, 0, sizeof(pcm[0].fifo)); - } - - gba_pcm_apply_control( 0, pcm[0].which ); - - if(pcm[0].pcm.output) - { - int time = soundTicksUp; - - pcm[0].dac = (int8_t)pcm[0].dac >> pcm[0].pcm.shift; - int delta = pcm[0].dac - pcm[0].pcm.last_amp; - if ( delta ) - { - pcm[0].pcm.last_amp = pcm[0].dac; - pcm_synth.offset( time, delta, pcm[0].pcm.output ); - } - pcm[0].pcm.last_time = time; - } - - pcm[1].enabled = (data2 & 0x0300) ? true : false; - pcm[1].timer = (data2 & 0x0400) ? 1 : 0; - - if ( data2 & 0x0800 ) - { - // Reset - pcm[1].writeIndex = 0; - pcm[1].readIndex = 0; - pcm[1].count = 0; - pcm[1].dac = 0; - memset( pcm[1].fifo, 0, sizeof(pcm[1].fifo)); - } - - gba_pcm_apply_control( 1, pcm[1].which ); - - if(pcm[1].pcm.output) - { - int time = soundTicksUp; - - pcm[1].dac = (int8_t)pcm[1].dac >> pcm[1].pcm.shift; - int delta = pcm[1].dac - pcm[1].pcm.last_amp; - if ( delta ) - { - pcm[1].pcm.last_amp = pcm[1].dac; - pcm_synth.offset( time, delta, pcm[1].pcm.output ); - } - pcm[1].pcm.last_time = time; - } -} - -void soundEvent_u16_parallel(uint32_t address[]) -{ - for(int i = 0; i < 8; i++) - { - switch ( address[i] ) - { - case SGCNT0_H: - //Begin of Write SGCNT0_H - WRITE16LE( &ioMem [SGCNT0_H], 0 & 0x770F ); - pcm_fifo_write_control(0, 0); - - gb_apu_volume( apu_vols [ioMem [SGCNT0_H] & 3] ); - //End of SGCNT0_H - break; - - case FIFOA_L: - case FIFOA_H: - pcm[0].fifo [pcm[0].writeIndex ] = 0; - pcm[0].fifo [pcm[0].writeIndex+1] = 0; - pcm[0].count += 2; - pcm[0].writeIndex = (pcm[0].writeIndex + 2) & 31; - WRITE16LE( &ioMem[address[i]], 0 ); - break; - - case FIFOB_L: - case FIFOB_H: - pcm[1].fifo [pcm[1].writeIndex ] = 0; - pcm[1].fifo [pcm[1].writeIndex+1] = 0; - pcm[1].count += 2; - pcm[1].writeIndex = (pcm[1].writeIndex + 2) & 31; - WRITE16LE( &ioMem[address[i]], 0 ); - break; - - case 0x88: - WRITE16LE( &ioMem[address[i]], 0 ); - break; - - default: - { - int gb_addr[2] = {address[i] & ~1, address[i] | 1}; - uint32_t address_array[2] = {address[i] & ~ 1, address[i] | 1}; - uint8_t data_array[2] = {0}; - gba_to_gb_sound_parallel(&gb_addr[0], &gb_addr[1]); - soundEvent_u8_parallel(gb_addr, address_array, data_array); - break; - } - } - } -} - -void gba_pcm_fifo_timer_overflowed( unsigned pcm_idx ) -{ - if ( pcm[pcm_idx].count <= 16 ) - { - // Need to fill FIFO - CPUCheckDMA( 3, pcm[pcm_idx].which ? 4 : 2 ); - - if ( pcm[pcm_idx].count <= 16 ) - { - // Not filled by DMA, so fill with 16 bytes of silence - int reg = pcm[pcm_idx].which ? FIFOB_L : FIFOA_L; - - uint32_t address_array[8] = {reg, reg+2, reg, reg+2, reg, reg+2, reg, reg+2}; - soundEvent_u16_parallel(address_array); - } - } - - // Read next sample from FIFO - pcm[pcm_idx].count--; - pcm[pcm_idx].dac = pcm[pcm_idx].fifo [pcm[pcm_idx].readIndex]; - pcm[pcm_idx].readIndex = (pcm[pcm_idx].readIndex + 1) & 31; - - if(pcm[pcm_idx].pcm.output) - { - int time = soundTicksUp; - - pcm[pcm_idx].dac = (int8_t)pcm[pcm_idx].dac >> pcm[pcm_idx].pcm.shift; - int delta = pcm[pcm_idx].dac - pcm[pcm_idx].pcm.last_amp; - if ( delta ) - { - pcm[pcm_idx].pcm.last_amp = pcm[pcm_idx].dac; - pcm_synth.offset( time, delta, pcm[pcm_idx].pcm.output ); - } - pcm[pcm_idx].pcm.last_time = time; - } -} - -void soundEvent_u8_parallel(int gb_addr[], uint32_t address[], uint8_t data[]) -{ - for(uint32_t i = 0; i < 2; i++) - { - ioMem[address[i]] = data[i]; - gb_apu_write_register( soundTicksUp, gb_addr[i], data[i] ); - - if ( address[i] == NR52 ) - { - gba_pcm_apply_control(0, 0 ); - gba_pcm_apply_control(1, 1 ); - } - // TODO: what about byte writes to SGCNT0_H etc.? - } -} - -void soundEvent_u8(int gb_addr, uint32_t address, uint8_t data) -{ - ioMem[address] = data; - gb_apu_write_register( soundTicksUp, gb_addr, data ); - - if ( address == NR52 ) - { - gba_pcm_apply_control(0, 0 ); - gba_pcm_apply_control(1, 1 ); - } - // TODO: what about byte writes to SGCNT0_H etc.? -} - - -void soundEvent_u16(uint32_t address, uint16_t data) -{ - switch ( address ) - { - case SGCNT0_H: - //Begin of Write SGCNT0_H - WRITE16LE( &ioMem [SGCNT0_H], data & 0x770F ); - pcm_fifo_write_control( data, data >> 4); - - gb_apu_volume( apu_vols [ioMem [SGCNT0_H] & 3] ); - //End of SGCNT0_H - break; - - case FIFOA_L: - case FIFOA_H: - pcm[0].fifo [pcm[0].writeIndex ] = data & 0xFF; - pcm[0].fifo [pcm[0].writeIndex+1] = data >> 8; - pcm[0].count += 2; - pcm[0].writeIndex = (pcm[0].writeIndex + 2) & 31; - WRITE16LE( &ioMem[address], data ); - break; - - case FIFOB_L: - case FIFOB_H: - pcm[1].fifo [pcm[1].writeIndex ] = data & 0xFF; - pcm[1].fifo [pcm[1].writeIndex+1] = data >> 8; - pcm[1].count += 2; - pcm[1].writeIndex = (pcm[1].writeIndex + 2) & 31; - WRITE16LE( &ioMem[address], data ); - break; - - case 0x88: - data &= 0xC3FF; - WRITE16LE( &ioMem[address], data ); - break; - - default: - { - int gb_addr[2] = {address & ~1, address | 1}; - uint32_t address_array[2] = {address & ~ 1, address | 1}; - uint8_t data_array[2] = {(uint8_t)data, (uint8_t)(data >> 8)}; - gba_to_gb_sound_parallel(&gb_addr[0], &gb_addr[1]); - soundEvent_u8_parallel(gb_addr, address_array, data_array); - break; - } - } -} - -void soundTimerOverflow(int timer) -{ - if ( timer == pcm[0].timer && pcm[0].enabled ) - gba_pcm_fifo_timer_overflowed(0); - if ( timer == pcm[1].timer && pcm[1].enabled ) - gba_pcm_fifo_timer_overflowed(1); -} - -void process_sound_tick_fn (void) -{ - // Run sound hardware to present - pcm[0].pcm.last_time -= soundTicksUp; - if ( pcm[0].pcm.last_time < -2048 ) - pcm[0].pcm.last_time = -2048; - - pcm[1].pcm.last_time -= soundTicksUp; - if ( pcm[1].pcm.last_time < -2048 ) - pcm[1].pcm.last_time = -2048; - - /* Emulates sound hardware up to a specified time, ends current time - frame, then starts a new frame at time 0 */ - - if(soundTicksUp > gb_apu.last_time) - gb_apu_run_until_( soundTicksUp ); - - gb_apu.frame_time -= soundTicksUp; - gb_apu.last_time -= soundTicksUp; - - bufs_buffer[2].offset_ += soundTicksUp * bufs_buffer[2].factor_; - bufs_buffer[1].offset_ += soundTicksUp * bufs_buffer[1].factor_; - bufs_buffer[0].offset_ += soundTicksUp * bufs_buffer[0].factor_; - - - // dump all the samples available - // VBA will only ever store 1 frame worth of samples - int numSamples = stereo_buffer_read_samples( (int16_t*) soundFinalWave, stereo_buffer_samples_avail()); - systemOnWriteDataToSoundBuffer(soundFinalWave, numSamples); - - soundTicksUp = 0; -} - -void apply_muting (void) -{ - // PCM - gba_pcm_apply_control(1, 0 ); - gba_pcm_apply_control(1, 1 ); - - // APU - gb_apu_set_output( &bufs_buffer[2], &bufs_buffer[0], &bufs_buffer[1], 0 ); - gb_apu_set_output( &bufs_buffer[2], &bufs_buffer[0], &bufs_buffer[1], 1 ); - gb_apu_set_output( &bufs_buffer[2], &bufs_buffer[0], &bufs_buffer[1], 2 ); - gb_apu_set_output( &bufs_buffer[2], &bufs_buffer[0], &bufs_buffer[1], 3 ); -} - - -void remake_stereo_buffer (void) -{ - if ( !ioMem ) - return; - - // Clears pointers kept to old stereo_buffer - gba_pcm_init(); - - // Stereo_Buffer - - mixer_samples_read = 0; - stereo_buffer_set_sample_rate( soundSampleRate, BLIP_DEFAULT_LENGTH ); - stereo_buffer_clock_rate( CLOCK_RATE ); - - // PCM - pcm [0].which = 0; - pcm [1].which = 1; - - // APU - gb_apu_new(); - gb_apu_reset( MODE_AGB, true ); - - stereo_buffer_clear(); - - soundTicksUp = 0; - - apply_muting(); - - gb_apu_volume(apu_vols [ioMem [SGCNT0_H] & 3] ); - - pcm_synth.volume( 0.66 / 256 * SOUNDVOLUME_ ); -} - -void soundReset (void) -{ - remake_stereo_buffer(); - //Begin of Reset APU - gb_apu_reset( MODE_AGB, true ); - - stereo_buffer_clear(); - - soundTicksUp = 0; - - // Sound Event (NR52) - int gb_addr = table[NR52 - 0x60]; - if ( gb_addr ) - { - ioMem[NR52] = 0x80; - gb_apu_write_register( soundTicksUp, gb_addr, 0x80 ); - - gba_pcm_apply_control(0, 0 ); - gba_pcm_apply_control(1, 1 ); - } - - // TODO: what about byte writes to SGCNT0_H etc.? - // End of Sound Event (NR52) -} -/* -void soundSetSampleRate(long sampleRate) -{ - if ( soundSampleRate != sampleRate ) - { - soundSampleRate = sampleRate; - remake_stereo_buffer(); - } -} -*/ - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// END SOUND.CPP -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// BEGIN GBA.CPP -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/*============================================================ - GBA INLINE -============================================================ */ - -#define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]),value); -#define ARM_PREFETCH_NEXT cpuPrefetch[1] = CPUReadMemoryQuick(bus.armNextPC+4); -#define THUMB_PREFETCH_NEXT cpuPrefetch[1] = CPUReadHalfWordQuick(bus.armNextPC+2); - -#define ARM_PREFETCH \ - {\ - cpuPrefetch[0] = CPUReadMemoryQuick(bus.armNextPC);\ - cpuPrefetch[1] = CPUReadMemoryQuick(bus.armNextPC+4);\ - } - -#define THUMB_PREFETCH \ - {\ - cpuPrefetch[0] = CPUReadHalfWordQuick(bus.armNextPC);\ - cpuPrefetch[1] = CPUReadHalfWordQuick(bus.armNextPC+2);\ - } - -int cpuNextEvent; // = 0; -bool holdState; // = false; -uint32_t cpuPrefetch[2]; -int cpuTotalTicks; // = 0; -uint8_t memoryWait[16]; -uint8_t memoryWaitSeq[16]; -uint8_t memoryWait32[16]; -uint8_t memoryWaitSeq32[16]; - -uint8_t biosProtected[4]; -uint8_t cpuBitsSet[256]; - -bool N_FLAG; // = 0; -bool C_FLAG; // = 0; -bool Z_FLAG; // = 0; -bool V_FLAG; // = 0; -bool armState; // = true; -bool armIrqEnable; // = true; -int armMode; // = 0x1f; - -typedef enum -{ - REG_DISPCNT = 0x000, - REG_DISPSTAT = 0x002, - REG_VCOUNT = 0x003, - REG_BG0CNT = 0x004, - REG_BG1CNT = 0x005, - REG_BG2CNT = 0x006, - REG_BG3CNT = 0x007, - REG_BG0HOFS = 0x08, - REG_BG0VOFS = 0x09, - REG_BG1HOFS = 0x0A, - REG_BG1VOFS = 0x0B, - REG_BG2HOFS = 0x0C, - REG_BG2VOFS = 0x0D, - REG_BG3HOFS = 0x0E, - REG_BG3VOFS = 0x0F, - REG_BG2PA = 0x10, - REG_BG2PB = 0x11, - REG_BG2PC = 0x12, - REG_BG2PD = 0x13, - REG_BG2X_L = 0x14, - REG_BG2X_H = 0x15, - REG_BG2Y_L = 0x16, - REG_BG2Y_H = 0x17, - REG_BG3PA = 0x18, - REG_BG3PB = 0x19, - REG_BG3PC = 0x1A, - REG_BG3PD = 0x1B, - REG_BG3X_L = 0x1C, - REG_BG3X_H = 0x1D, - REG_BG3Y_L = 0x1E, - REG_BG3Y_H = 0x1F, - REG_WIN0H = 0x20, - REG_WIN1H = 0x21, - REG_WIN0V = 0x22, - REG_WIN1V = 0x23, - REG_WININ = 0x24, - REG_WINOUT = 0x25, - REG_BLDCNT = 0x28, - REG_BLDALPHA = 0x29, - REG_BLDY = 0x2A, - REG_TM0D = 0x80, - REG_TM0CNT = 0x81, - REG_TM1D = 0x82, - REG_TM1CNT = 0x83, - REG_TM2D = 0x84, - REG_TM2CNT = 0x85, - REG_TM3D = 0x86, - REG_TM3CNT = 0x87, - REG_P1 = 0x098, - REG_P1CNT = 0x099, - REG_RCNT = 0x9A, - REG_IE = 0x100, - REG_IF = 0x101, - REG_IME = 0x104, - REG_HALTCNT = 0x180 -} hardware_register; - -uint16_t io_registers[1024 * 16]; - -u16 MOSAIC; - -uint16_t BG2X_L ; -uint16_t BG2X_H ; -uint16_t BG2Y_L ; -uint16_t BG2Y_H ; -uint16_t BG3X_L ; -uint16_t BG3X_H ; -uint16_t BG3Y_L ; -uint16_t BG3Y_H ; -uint16_t BLDMOD ; -uint16_t COLEV ; -uint16_t COLY ; -uint16_t DM0SAD_L ; -uint16_t DM0SAD_H ; -uint16_t DM0DAD_L ; -uint16_t DM0DAD_H ; -uint16_t DM0CNT_L ; -uint16_t DM0CNT_H ; -uint16_t DM1SAD_L ; -uint16_t DM1SAD_H ; -uint16_t DM1DAD_L ; -uint16_t DM1DAD_H ; -uint16_t DM1CNT_L ; -uint16_t DM1CNT_H ; -uint16_t DM2SAD_L ; -uint16_t DM2SAD_H ; -uint16_t DM2DAD_L ; -uint16_t DM2DAD_H ; -uint16_t DM2CNT_L ; -uint16_t DM2CNT_H ; -uint16_t DM3SAD_L ; -uint16_t DM3SAD_H ; -uint16_t DM3DAD_L ; -uint16_t DM3DAD_H ; -uint16_t DM3CNT_L ; -uint16_t DM3CNT_H ; - -uint8_t timerOnOffDelay ; -uint16_t timer0Value ; -uint32_t dma0Source ; -uint32_t dma0Dest ; -uint32_t dma1Source ; -uint32_t dma1Dest ; -uint32_t dma2Source ; -uint32_t dma2Dest ; -uint32_t dma3Source ; -uint32_t dma3Dest ; -void (Gigazoid::*cpuSaveGameFunc)(uint32_t,uint8_t); -bool fxOn ; -bool windowOn ; - -int cpuDmaTicksToUpdate; - -int IRQTicks; -bool intState; - -bus_t bus; -graphics_t graphics; - -memoryMap map[256]; -int clockTicks; - -int romSize; // = 0x2000000; -uint32_t line[6][240]; -bool gfxInWin[2][240]; -int lineOBJpixleft[128]; -int joy; - -int gfxBG2Changed; -int gfxBG3Changed; - -int gfxBG2X; -int gfxBG2Y; -int gfxBG3X; -int gfxBG3Y; - -bool ioReadable[0x400]; - -//int gfxLastVCOUNT = 0; - -// Waitstates when accessing data - -#define DATATICKS_ACCESS_BUS_PREFETCH(address, value) \ - int addr = (address >> 24) & 15; \ - if ((addr>=0x08) || (addr < 0x02)) \ - { \ - bus.busPrefetchCount=0; \ - bus.busPrefetch=false; \ - } \ - else if (bus.busPrefetch) \ - { \ - int waitState = value; \ - waitState = (1 & ~waitState) | (waitState & waitState); \ - bus.busPrefetchCount = ((bus.busPrefetchCount+1)<> 24) & 15]) -#define DATATICKS_ACCESS_32BIT_SEQ(address) (memoryWaitSeq32[(address >> 24) & 15]) -#define DATATICKS_ACCESS_16BIT(address) (memoryWait[(address >> 24) & 15]) -#define DATATICKS_ACCESS_16BIT_SEQ(address) (memoryWaitSeq[(address >> 24) & 15]) - -// Waitstates when executing opcode -INLINE int codeTicksAccess(u32 address, u8 bit32) // THUMB NON SEQ -{ - int addr, ret; - - addr = (address>>24) & 15; - - if (unsigned(addr - 0x08) <= 5) - { - if (bus.busPrefetchCount&0x1) - { - if (bus.busPrefetchCount&0x2) - { - bus.busPrefetchCount = ((bus.busPrefetchCount&0xFF)>>2) | (bus.busPrefetchCount&0xFFFFFF00); - return 0; - } - bus.busPrefetchCount = ((bus.busPrefetchCount&0xFF)>>1) | (bus.busPrefetchCount&0xFFFFFF00); - return memoryWaitSeq[addr]-1; - } - } - bus.busPrefetchCount = 0; - - if(bit32) /* ARM NON SEQ */ - ret = memoryWait32[addr]; - else /* THUMB NON SEQ */ - ret = memoryWait[addr]; - - return ret; -} - -INLINE int codeTicksAccessSeq16(u32 address) // THUMB SEQ -{ - int addr = (address>>24) & 15; - - if (unsigned(addr - 0x08) <= 5) - { - if (bus.busPrefetchCount&0x1) - { - bus.busPrefetchCount = ((bus.busPrefetchCount&0xFF)>>1) | (bus.busPrefetchCount&0xFFFFFF00); - return 0; - } - else if (bus.busPrefetchCount>0xFF) - { - bus.busPrefetchCount=0; - return memoryWait[addr]; - } - } - else - bus.busPrefetchCount = 0; - - return memoryWaitSeq[addr]; -} - -INLINE int codeTicksAccessSeq32(u32 address) // ARM SEQ -{ - int addr = (address>>24)&15; - - if (unsigned(addr - 0x08) <= 5) - { - if (bus.busPrefetchCount&0x1) - { - if (bus.busPrefetchCount&0x2) - { - bus.busPrefetchCount = ((bus.busPrefetchCount&0xFF)>>2) | (bus.busPrefetchCount&0xFFFFFF00); - return 0; - } - bus.busPrefetchCount = ((bus.busPrefetchCount&0xFF)>>1) | (bus.busPrefetchCount&0xFFFFFF00); - return memoryWaitSeq[addr]; - } - else if (bus.busPrefetchCount > 0xFF) - { - bus.busPrefetchCount=0; - return memoryWait32[addr]; - } - } - return memoryWaitSeq32[addr]; -} - -#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])) - -bool stopState; -#ifdef USE_MOTION_SENSOR -extern bool cpuEEPROMSensorEnabled; -#endif -bool timer0On ; -int timer0Ticks ; -int timer0Reload ; -int timer0ClockReload ; -uint16_t timer1Value ; -bool timer1On ; -int timer1Ticks ; -int timer1Reload ; -int timer1ClockReload ; -uint16_t timer2Value ; -bool timer2On ; -int timer2Ticks ; -int timer2Reload ; -int timer2ClockReload ; -uint16_t timer3Value ; -bool timer3On ; -int timer3Ticks ; -int timer3Reload ; -int timer3ClockReload ; - -INLINE u32 CPUReadMemory(u32 address) -{ - if (readCallback) - readCallback(address); - - u32 value; - switch(address >> 24) - { - case 0: - /* BIOS */ - if(bus.reg[15].I >> 24) - { - if(address < 0x4000) - value = READ32LE(((u32 *)&biosProtected)); - else goto unreadable; - } - else - value = READ32LE(((u32 *)&bios[address & 0x3FFC])); - break; - case 0x02: - /* external work RAM */ - value = READ32LE(((u32 *)&workRAM[address & 0x3FFFC])); - break; - case 0x03: - /* internal work RAM */ - value = READ32LE(((u32 *)&internalRAM[address & 0x7ffC])); - break; - case 0x04: - /* I/O registers */ - if (address == 0x4000130) - { - if (padCallback) - padCallback(); - lagged = false; - } - 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 0x05: - /* palette RAM */ - value = READ32LE(((u32 *)&graphics.paletteRAM[address & 0x3fC])); - break; - case 0x06: - /* VRAM */ - address = (address & 0x1fffc); - if (((io_registers[REG_DISPCNT] & 7) >2) && ((address & 0x1C000) == 0x18000)) - { - value = 0; - break; - } - if ((address & 0x18000) == 0x18000) - address &= 0x17fff; - value = READ32LE(((u32 *)&vram[address])); - break; - case 0x07: - /* OAM RAM */ - value = READ32LE(((u32 *)&oam[address & 0x3FC])); - break; - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - /* gamepak ROM */ - value = READ32LE(((u32 *)&rom[address&0x1FFFFFC])); - break; - case 0x0D: - value = eepromRead(); - break; - case 14: - case 15: - value = flashRead(address) * 0x01010101; - break; - default: -unreadable: - if(armState) - value = CPUReadHalfWordQuick(bus.reg[15].I + (address & 2)); - else - value = CPUReadHalfWordQuick(bus.reg[15].I); - } - - if(address & 3) { - int shift = (address & 3) << 3; - value = (value >> shift) | (value << (32 - shift)); - } - return value; -} - -INLINE u32 CPUReadHalfWord(u32 address) -{ - if (readCallback) - readCallback(address); - - u32 value; - switch(address >> 24) - { - case 0: - if (bus.reg[15].I >> 24) - { - if(address < 0x4000) - 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 == 0x4000130) - { - if (padCallback) - padCallback(); - lagged = false; - } - - 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 && !(io_registers[REG_TM1CNT] & 4)) - value = 0xFFFF - ((timer1Ticks-cpuTotalTicks) >> timer1ClockReload); - else - if (((address & 0x3fe) == 0x108) && timer2On && !(io_registers[REG_TM2CNT] & 4)) - value = 0xFFFF - ((timer2Ticks-cpuTotalTicks) >> timer2ClockReload); - else - if (((address & 0x3fe) == 0x10C) && timer3On && !(io_registers[REG_TM3CNT] & 4)) - value = 0xFFFF - ((timer3Ticks-cpuTotalTicks) >> timer3ClockReload); - } - } - else goto unreadable; - break; - case 5: - value = READ16LE(((u16 *)&graphics.paletteRAM[address & 0x3fe])); - break; - case 6: - address = (address & 0x1fffe); - if (((io_registers[REG_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(rtcEnabled && (address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8)) - value = rtcRead(address); - else - value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE])); - break; - case 13: - value = eepromRead(); - break; - case 14: - value = flashRead(address) * 0x0101; - break; - default: -unreadable: - { - int param = bus.reg[15].I; - if(armState) - param += (address & 2); - value = CPUReadHalfWordQuick(param); - } - break; - } - - if(address & 1) - value = (value >> 8) | (value << 24); - - return value; -} - -INLINE u16 CPUReadHalfWordSigned(u32 address) -{ - u16 value = CPUReadHalfWord(address); - if((address & 1)) - value = (s8)value; - return value; -} - -INLINE u8 CPUReadByte(u32 address) -{ - if (readCallback) - readCallback(address); - - switch(address >> 24) - { - case 0: - if (bus.reg[15].I >> 24) - { - if(address < 0x4000) - 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 == 0x4000130 || address == 0x4000131) - { - if (padCallback) - padCallback(); - lagged = false; - } - - if((address < 0x4000400) && ioReadable[address & 0x3ff]) - return ioMem[address & 0x3ff]; - else goto unreadable; - case 5: - return graphics.paletteRAM[address & 0x3ff]; - case 6: - address = (address & 0x1ffff); - if (((io_registers[REG_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: - return eepromRead(); - case 14: -#ifdef USE_MOTION_SENSOR - 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; - } - } -#endif - return flashRead(address); - default: -unreadable: - if(armState) - return CPUReadByteQuick(bus.reg[15].I+(address & 3)); - else - return CPUReadByteQuick(bus.reg[15].I+(address & 1)); - } -} - -INLINE void CPUWriteMemory(u32 address, u32 value) -{ - if (writeCallback) - writeCallback(address); - - switch(address >> 24) - { - case 0x02: - WRITE32LE(((u32 *)&workRAM[address & 0x3FFFC]), value); - break; - case 0x03: - WRITE32LE(((u32 *)&internalRAM[address & 0x7ffC]), value); - break; - case 0x04: - if(address < 0x4000400) - { - CPUUpdateRegister((address & 0x3FC), value & 0xFFFF); - CPUUpdateRegister((address & 0x3FC) + 2, (value >> 16)); - } - break; - case 0x05: - WRITE32LE(((u32 *)&graphics.paletteRAM[address & 0x3FC]), value); - break; - case 0x06: - address = (address & 0x1fffc); - if (((io_registers[REG_DISPCNT] & 7) >2) && ((address & 0x1C000) == 0x18000)) - return; - if ((address & 0x18000) == 0x18000) - address &= 0x17fff; - - - WRITE32LE(((u32 *)&vram[address]), value); - break; - case 0x07: - WRITE32LE(((u32 *)&oam[address & 0x3fc]), value); - break; - case 0x0D: - if (cpuEEPROMEnabled) - eepromWrite(value); - break; - case 0x0E: - (this->*cpuSaveGameFunc)(address, (u8)value); - break; - default: - break; - } -} - -INLINE void CPUWriteHalfWord(u32 address, u16 value) -{ - if (writeCallback) - writeCallback(address); - - switch(address >> 24) - { - case 2: - WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]),value); - break; - case 3: - WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value); - break; - case 4: - if(address < 0x4000400) - CPUUpdateRegister(address & 0x3fe, value); - break; - case 5: - WRITE16LE(((u16 *)&graphics.paletteRAM[address & 0x3fe]), value); - break; - case 6: - address = (address & 0x1fffe); - if (((io_registers[REG_DISPCNT] & 7) >2) && ((address & 0x1C000) == 0x18000)) - return; - if ((address & 0x18000) == 0x18000) - address &= 0x17fff; - WRITE16LE(((u16 *)&vram[address]), value); - break; - case 7: - WRITE16LE(((u16 *)&oam[address & 0x3fe]), value); - break; - case 8: - case 9: - if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) - if(!rtcWrite(address, value)) - break; - break; - case 13: - if(cpuEEPROMEnabled) - eepromWrite((u8)value); - break; - case 14: - (this->*cpuSaveGameFunc)(address, (u8)value); - break; - default: - break; - } -} - -INLINE void CPUWriteByte(u32 address, u8 b) -{ - if (writeCallback) - writeCallback(address); - - switch(address >> 24) - { - case 2: - workRAM[address & 0x3FFFF] = b; - break; - case 3: - internalRAM[address & 0x7fff] = b; - break; - case 4: - if(address < 0x4000400) - { - switch(address & 0x3FF) - { - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x68: - case 0x69: - case 0x6c: - case 0x6d: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x78: - case 0x79: - case 0x7c: - case 0x7d: - case 0x80: - case 0x81: - case 0x84: - case 0x85: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9a: - case 0x9b: - case 0x9c: - case 0x9d: - case 0x9e: - case 0x9f: - { - int gb_addr = table[(address & 0xFF) - 0x60]; - soundEvent_u8(gb_addr, address&0xFF, b); - } - break; - case 0x301: // HALTCNT, undocumented - if(b == 0x80) - stopState = true; - holdState = 1; - cpuNextEvent = cpuTotalTicks; - break; - default: // every other register - { - u32 lowerBits = address & 0x3fe; - uint16_t param; - if(address & 1) - param = (READ16LE(&ioMem[lowerBits]) & 0x00FF) | (b << 8); - else - param = (READ16LE(&ioMem[lowerBits]) & 0xFF00) | b; - - CPUUpdateRegister(lowerBits, param); - } - break; - } - } - break; - case 5: - // no need to switch - *((u16 *)&graphics.paletteRAM[address & 0x3FE]) = (b << 8) | b; - break; - case 6: - address = (address & 0x1fffe); - if (((io_registers[REG_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[((io_registers[REG_DISPCNT] & 7)+1)>>2]) - *((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(b); - break; - case 14: - (this->*cpuSaveGameFunc)(address, b); - break; - default: - break; - } -} - - -/*============================================================ - BIOS -============================================================ */ - -void BIOS_RegisterRamReset(u32 flags) -{ - // no need to trace here. this is only called directly from GBA.cpp - // to emulate bios initialization - - CPUUpdateRegister(0x0, 0x80); - - if(flags) - { - if(flags & 0x01) - memset(workRAM, 0, 0x40000); // clear work RAM - - if(flags & 0x02) - memset(internalRAM, 0, 0x7e00); // don't clear 0x7e00-0x7fff, clear internal RAM - - if(flags & 0x04) - memset(graphics.paletteRAM, 0, 0x400); // clear palette RAM - - if(flags & 0x08) - memset(vram, 0, 0x18000); // clear VRAM - - if(flags & 0x10) - memset(oam, 0, 0x400); // clean OAM - - if(flags & 0x80) { - int i; - for(i = 0; i < 0x10; i++) - CPUUpdateRegister(0x200+i*2, 0); - - for(i = 0; i < 0xF; i++) - CPUUpdateRegister(0x4+i*2, 0); - - for(i = 0; i < 0x20; i++) - CPUUpdateRegister(0x20+i*2, 0); - - for(i = 0; i < 0x18; i++) - CPUUpdateRegister(0xb0+i*2, 0); - - CPUUpdateRegister(0x130, 0); - CPUUpdateRegister(0x20, 0x100); - CPUUpdateRegister(0x30, 0x100); - CPUUpdateRegister(0x26, 0x100); - CPUUpdateRegister(0x36, 0x100); - } - - if(flags & 0x20) { - int i; - for(i = 0; i < 8; i++) - CPUUpdateRegister(0x110+i*2, 0); - CPUUpdateRegister(0x134, 0x8000); - for(i = 0; i < 7; i++) - CPUUpdateRegister(0x140+i*2, 0); - } - - if(flags & 0x40) { - int i; - CPUWriteByte(0x4000084, 0); - CPUWriteByte(0x4000084, 0x80); - CPUWriteMemory(0x4000080, 0x880e0000); - CPUUpdateRegister(0x88, CPUReadHalfWord(0x4000088)&0x3ff); - CPUWriteByte(0x4000070, 0x70); - for(i = 0; i < 8; i++) - CPUUpdateRegister(0x90+i*2, 0); - CPUWriteByte(0x4000070, 0); - for(i = 0; i < 8; i++) - CPUUpdateRegister(0x90+i*2, 0); - CPUWriteByte(0x4000084, 0); - } - } -} - -void BIOS_SoftReset (void) -{ - armState = true; - armMode = 0x1F; - armIrqEnable = false; - C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false; - bus.reg[13].I = 0x03007F00; - bus.reg[14].I = 0x00000000; - bus.reg[16].I = 0x00000000; - bus.reg[R13_IRQ].I = 0x03007FA0; - bus.reg[R14_IRQ].I = 0x00000000; - bus.reg[SPSR_IRQ].I = 0x00000000; - bus.reg[R13_SVC].I = 0x03007FE0; - bus.reg[R14_SVC].I = 0x00000000; - bus.reg[SPSR_SVC].I = 0x00000000; - u8 b = internalRAM[0x7ffa]; - - memset(&internalRAM[0x7e00], 0, 0x200); - - if(b) { - bus.armNextPC = 0x02000000; - bus.reg[15].I = 0x02000004; - } else { - bus.armNextPC = 0x08000000; - bus.reg[15].I = 0x08000004; - } -} - -#define BIOS_REGISTER_RAM_RESET() BIOS_RegisterRamReset(bus.reg[0].I); - -#define CPU_UPDATE_CPSR() \ -{ \ - uint32_t CPSR; \ - CPSR = bus.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); \ - bus.reg[16].I = CPSR; \ -} - -#define CPU_SOFTWARE_INTERRUPT() \ -{ \ - uint32_t PC = bus.reg[15].I; \ - bool savedArmState = armState; \ - if(armMode != 0x13) \ - CPUSwitchMode(0x13, true, false); \ - bus.reg[14].I = PC - (savedArmState ? 4 : 2); \ - bus.reg[15].I = 0x08; \ - armState = true; \ - armIrqEnable = false; \ - bus.armNextPC = 0x08; \ - ARM_PREFETCH; \ - bus.reg[15].I += 4; \ -} - -void CPUUpdateFlags(bool breakLoop) -{ - uint32_t CPSR = bus.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 && armIrqEnable && (io_registers[REG_IF] & io_registers[REG_IE]) && (io_registers[REG_IME] & 1)) - cpuNextEvent = cpuTotalTicks; -} - -void CPUSoftwareInterrupt(int comment) -{ - if(armState) - comment >>= 16; - - CPU_SOFTWARE_INTERRUPT(); -} - - -/*============================================================ - GBA ARM CORE -============================================================ */ - -#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 - -void armUnknownInsn(u32 opcode) -{ - u32 PC = bus.reg[15].I; - bool savedArmState = armState; - if(armMode != 0x1b ) - CPUSwitchMode(0x1b, true, false); - bus.reg[14].I = PC - (savedArmState ? 4 : 2); - bus.reg[15].I = 0x04; - armState = true; - armIrqEnable = false; - bus.armNextPC = 0x04; - ARM_PREFETCH; - bus.reg[15].I += 4; -} - -// Common macros ////////////////////////////////////////////////////////// - -#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. -// 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. - -// 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 (!shift) { /* LSL #0 most common? */ \ - value = bus.reg[opcode & 0x0F].I; \ - } else { \ - u32 v = bus.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 = bus.reg[(opcode >> 8)&15].B.B0; \ - if (shift) { \ - if (shift == 32) { \ - value = 0; \ - C_OUT = (bus.reg[opcode & 0x0F].I & 1 ? true : false);\ - } else if (shift < 32) { \ - u32 v = bus.reg[opcode & 0x0F].I; \ - C_OUT = (v >> (32 - shift)) & 1 ? true : false;\ - value = v << shift; \ - } else { \ - value = 0; \ - C_OUT = false; \ - } \ - } else { \ - value = bus.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 (shift) { \ - u32 v = bus.reg[opcode & 0x0F].I; \ - C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ - value = v >> shift; \ - } else { \ - value = 0; \ - C_OUT = (bus.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 = bus.reg[(opcode >> 8)&15].B.B0; \ - if (shift) { \ - if (shift == 32) { \ - value = 0; \ - C_OUT = (bus.reg[opcode & 0x0F].I & 0x80000000 ? true : false);\ - } else if (shift < 32) { \ - u32 v = bus.reg[opcode & 0x0F].I; \ - C_OUT = (v >> (shift - 1)) & 1 ? true : false;\ - value = v >> shift; \ - } else { \ - value = 0; \ - C_OUT = false; \ - } \ - } else { \ - value = bus.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 (shift) { \ - s32 v = bus.reg[opcode & 0x0F].I; \ - C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\ - value = v >> (int)shift; \ - } else { \ - if (bus.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 = bus.reg[(opcode >> 8)&15].B.B0; \ - if (shift < 32) { \ - if (shift) { \ - s32 v = bus.reg[opcode & 0x0F].I; \ - C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\ - value = v >> (int)shift; \ - } else { \ - value = bus.reg[opcode & 0x0F].I; \ - } \ - } else { \ - if (bus.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 (shift) { \ - u32 v = bus.reg[opcode & 0x0F].I; \ - C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ - value = ((v << (32 - shift)) | \ - (v >> shift)); \ - } else { \ - u32 v = bus.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 = bus.reg[(opcode >> 8)&15].B.B0; \ - if (shift & 0x1F) { \ - u32 v = bus.reg[opcode & 0x0F].I; \ - C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ - value = ((v << (32 - shift)) | \ - (v >> shift)); \ - } else { \ - value = bus.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 (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 (dest != 15) { SETCOND } -#ifndef OP_AND - #define OP_AND \ - u32 res = bus.reg[(opcode>>16)&15].I & value; \ - bus.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 = bus.reg[(opcode>>16)&15].I ^ value; \ - bus.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 = bus.reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = lhs - rhs; \ - bus.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 = bus.reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = rhs - lhs; \ - bus.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 = bus.reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = lhs + rhs; \ - bus.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 = bus.reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = lhs + rhs + (u32)C_FLAG; \ - bus.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 = bus.reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = lhs - rhs - !((u32)C_FLAG); \ - bus.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 = bus.reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = rhs - lhs - !((u32)C_FLAG); \ - bus.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 = bus.reg[(opcode >> 16) & 0x0F].I & value; \ - C_SETCOND_LOGICAL; -#endif -#ifndef OP_TEQ - #define OP_TEQ \ - u32 res = bus.reg[(opcode >> 16) & 0x0F].I ^ value; \ - C_SETCOND_LOGICAL; -#endif -#ifndef OP_CMP - #define OP_CMP \ - u32 lhs = bus.reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = lhs - rhs; \ - C_SETCOND_SUB; -#endif -#ifndef OP_CMN - #define OP_CMN \ - u32 lhs = bus.reg[(opcode>>16)&15].I; \ - u32 rhs = value; \ - u32 res = lhs + rhs; \ - C_SETCOND_ADD; -#endif -#ifndef OP_ORR - #define OP_ORR \ - u32 res = bus.reg[(opcode >> 16) & 0x0F].I | value; \ - bus.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; \ - bus.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 = bus.reg[(opcode >> 16) & 0x0F].I & (~value); \ - bus.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; \ - bus.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)bus.reg[dest].I < 0) ? true : false; \ - Z_FLAG = bus.reg[dest].I ? false : true; -#endif -#ifndef SETCOND_MULL - #define SETCOND_MULL \ - N_FLAG = (bus.reg[dest].I & 0x80000000) ? true : false;\ - Z_FLAG = bus.reg[dest].I || bus.reg[acc].I ? false : true; -#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 and OP are concatenated in order. -#define ALU_INSN(ALU_INIT, GETVALUE, OP, MODECHANGE, ISREGSHIFT) \ - ALU_INIT GETVALUE OP; \ - if ((opcode & 0x0000F000) != 0x0000F000) { \ - clockTicks = 1 + ISREGSHIFT \ - + codeTicksAccessSeq32(bus.armNextPC); \ - } else { \ - MODECHANGE; \ - if (armState) { \ - bus.reg[15].I &= 0xFFFFFFFC; \ - bus.armNextPC = bus.reg[15].I; \ - bus.reg[15].I += 4; \ - ARM_PREFETCH; \ - } else { \ - bus.reg[15].I &= 0xFFFFFFFE; \ - bus.armNextPC = bus.reg[15].I; \ - bus.reg[15].I += 2; \ - THUMB_PREFETCH; \ - } \ - clockTicks = 3 + ISREGSHIFT \ - + codeTicksAccess(bus.armNextPC, BITS_32) \ - + ((codeTicksAccessSeq32(bus.armNextPC)) << 1); \ - } - -#define MODECHANGE_NO /*nothing*/ -#define MODECHANGE_YES if(armMode != (bus.reg[17].I & 0x1f)) CPUSwitchMode(bus.reg[17].I & 0x1f, false, true); - -#define DEFINE_ALU_INSN_C(CODE1, CODE2, OP, MODECHANGE) \ - void arm##CODE1##0(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSL_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - void arm##CODE1##1(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSL_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - void arm##CODE1##2(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - void arm##CODE1##3(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - void arm##CODE1##4(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ASR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - void arm##CODE1##5(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ASR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - void arm##CODE1##6(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ROR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - void arm##CODE1##7(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ROR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - 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) \ - void arm##CODE1##0(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSL_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - void arm##CODE1##1(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSL_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - void arm##CODE1##2(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - void arm##CODE1##3(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - void arm##CODE1##4(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ASR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - void arm##CODE1##5(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ASR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - void arm##CODE1##6(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ROR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ - void arm##CODE1##7(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ROR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ - 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 = bus.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 & 0xFFFF0000) == 0) \ - clockTicks += 1; \ - else if ((rs & 0xFF000000) == 0) \ - clockTicks += 2; \ - else \ - clockTicks += 3; \ - if (bus.busPrefetchCount == 0) \ - bus.busPrefetchCount = ((bus.busPrefetchCount+1)<> 32); -#define OP_MLAL(SIGN) \ - SIGN##64 res = ((SIGN##64)bus.reg[dest].I<<32 | bus.reg[acc].I)\ - + ((SIGN##64)(SIGN##32)bus.reg[mult].I \ - * (SIGN##64)(SIGN##32)rs); \ - bus.reg[acc].I = (u32)res; \ - bus.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 - void arm009(u32 opcode) { MUL_INSN(OP_MUL, SETCOND_NONE, 1); } -// MULS Rd, Rm, Rs - void arm019(u32 opcode) { MUL_INSN(OP_MUL, SETCOND_MUL, 1); } - -// MLA Rd, Rm, Rs, Rn - void arm029(u32 opcode) { MUL_INSN(OP_MLA, SETCOND_NONE, 2); } -// MLAS Rd, Rm, Rs, Rn - void arm039(u32 opcode) { MUL_INSN(OP_MLA, SETCOND_MUL, 2); } - -// UMULL RdLo, RdHi, Rn, Rs - void arm089(u32 opcode) { MUL_INSN(OP_UMULL, SETCOND_NONE, 2); } -// UMULLS RdLo, RdHi, Rn, Rs - void arm099(u32 opcode) { MUL_INSN(OP_UMULL, SETCOND_MULL, 2); } - -// UMLAL RdLo, RdHi, Rn, Rs - void arm0A9(u32 opcode) { MUL_INSN(OP_UMLAL, SETCOND_NONE, 3); } -// UMLALS RdLo, RdHi, Rn, Rs - void arm0B9(u32 opcode) { MUL_INSN(OP_UMLAL, SETCOND_MULL, 3); } - -// SMULL RdLo, RdHi, Rm, Rs - void arm0C9(u32 opcode) { MUL_INSN(OP_SMULL, SETCOND_NONE, 2); } -// SMULLS RdLo, RdHi, Rm, Rs - void arm0D9(u32 opcode) { MUL_INSN(OP_SMULL, SETCOND_MULL, 2); } - -// SMLAL RdLo, RdHi, Rm, Rs - void arm0E9(u32 opcode) { MUL_INSN(OP_SMLAL, SETCOND_NONE, 3); } -// SMLALS RdLo, RdHi, Rm, Rs - void arm0F9(u32 opcode) { MUL_INSN(OP_SMLAL, SETCOND_MULL, 3); } - -// Misc instructions ////////////////////////////////////////////////////// - -// SWP Rd, Rm, [Rn] - void arm109(u32 opcode) -{ - u32 address = bus.reg[(opcode >> 16) & 15].I; - u32 temp = CPUReadMemory(address); - CPUWriteMemory(address, bus.reg[opcode&15].I); - bus.reg[(opcode >> 12) & 15].I = temp; - int dataticks_value = DATATICKS_ACCESS_32BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = 4 + (dataticks_value << 1) + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// SWPB Rd, Rm, [Rn] - void arm149(u32 opcode) -{ - u32 address = bus.reg[(opcode >> 16) & 15].I; - u32 temp = CPUReadByte(address); - CPUWriteByte(address, bus.reg[opcode&15].B.B0); - bus.reg[(opcode>>12)&15].I = temp; - u32 dataticks_value = DATATICKS_ACCESS_32BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = 4 + (dataticks_value << 1) + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// MRS Rd, CPSR - void arm100(u32 opcode) -{ - if ((opcode & 0x0FFF0FFF) == 0x010F0000) - { - CPU_UPDATE_CPSR(); - bus.reg[(opcode >> 12) & 0x0F].I = bus.reg[16].I; - } - else - armUnknownInsn(opcode); -} - -// MRS Rd, SPSR - void arm140(u32 opcode) -{ - if ((opcode & 0x0FFF0FFF) == 0x014F0000) - bus.reg[(opcode >> 12) & 0x0F].I = bus.reg[17].I; - else - armUnknownInsn(opcode); -} - -// MSR CPSR_fields, Rm - void arm120(u32 opcode) -{ - if ((opcode & 0x0FF0FFF0) == 0x0120F000) - { - CPU_UPDATE_CPSR(); - u32 value = bus.reg[opcode & 15].I; - u32 newValue = bus.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; - if(armMode != (newValue & 0x1F)) - CPUSwitchMode(newValue & 0x1F, false, true); - bus.reg[16].I = newValue; - CPUUpdateFlags(1); - if (!armState) { // this should not be allowed, but it seems to work - THUMB_PREFETCH; - bus.reg[15].I = bus.armNextPC + 2; - } - } - else - armUnknownInsn(opcode); -} - -// MSR SPSR_fields, Rm - void arm160(u32 opcode) -{ - if ((opcode & 0x0FF0FFF0) == 0x0160F000) - { - u32 value = bus.reg[opcode & 15].I; - if (armMode > 0x10 && armMode < 0x1F) - { - if (opcode & 0x00010000) - bus.reg[17].I = (bus.reg[17].I & 0xFFFFFF00) | (value & 0x000000FF); - if (opcode & 0x00020000) - bus.reg[17].I = (bus.reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00); - if (opcode & 0x00040000) - bus.reg[17].I = (bus.reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000); - if (opcode & 0x00080000) - bus.reg[17].I = (bus.reg[17].I & 0x00FFFFFF) | (value & 0xFF000000); - } - } - else - armUnknownInsn(opcode); -} - -// MSR CPSR_fields, # - void arm320(u32 opcode) -{ - if ((opcode & 0x0FF0F000) == 0x0320F000) - { - CPU_UPDATE_CPSR(); - u32 value = opcode & 0xFF; - int shift = (opcode & 0xF00) >> 7; - if (shift) { - ROR_IMM_MSR; - } - u32 newValue = bus.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; - - if(armMode != (newValue & 0x1F)) - CPUSwitchMode(newValue & 0x1F, false, true); - bus.reg[16].I = newValue; - CPUUpdateFlags(1); - if (!armState) { // this should not be allowed, but it seems to work - THUMB_PREFETCH; - bus.reg[15].I = bus.armNextPC + 2; - } - } - else - armUnknownInsn(opcode); -} - -// MSR SPSR_fields, # - void arm360(u32 opcode) -{ - if ((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) - bus.reg[17].I = (bus.reg[17].I & 0xFFFFFF00) | (value & 0x000000FF); - if (opcode & 0x00020000) - bus.reg[17].I = (bus.reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00); - if (opcode & 0x00040000) - bus.reg[17].I = (bus.reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000); - if (opcode & 0x00080000) - bus.reg[17].I = (bus.reg[17].I & 0x00FFFFFF) | (value & 0xFF000000); - } - } - else - armUnknownInsn(opcode); -} - -// BX Rm - void arm121(u32 opcode) -{ - if ((opcode & 0x0FFFFFF0) == 0x012FFF10) { - int base = opcode & 0x0F; - bus.busPrefetchCount = 0; - armState = bus.reg[base].I & 1 ? false : true; - if (armState) { - bus.reg[15].I = bus.reg[base].I & 0xFFFFFFFC; - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 4; - ARM_PREFETCH; - clockTicks = 3 + (codeTicksAccessSeq32(bus.armNextPC)<<1) - + codeTicksAccess(bus.armNextPC, BITS_32); - } else { - bus.reg[15].I = bus.reg[base].I & 0xFFFFFFFE; - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 2; - THUMB_PREFETCH; - clockTicks = 3 + (codeTicksAccessSeq16(bus.armNextPC)<<1) - + codeTicksAccess(bus.armNextPC, BITS_16); - } - } - 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 = bus.reg[opcode & 15].I; -#define OFFSET_LSL \ - int offset = bus.reg[opcode & 15].I << ((opcode>>7) & 31); -#define OFFSET_LSR \ - int shift = (opcode >> 7) & 31; \ - int offset = shift ? bus.reg[opcode & 15].I >> shift : 0; -#define OFFSET_ASR \ - int shift = (opcode >> 7) & 31; \ - int offset; \ - if (shift) \ - offset = (int)((s32)bus.reg[opcode & 15].I >> shift);\ - else if (bus.reg[opcode & 15].I & 0x80000000) \ - offset = 0xFFFFFFFF; \ - else \ - offset = 0; -#define OFFSET_ROR \ - int shift = (opcode >> 7) & 31; \ - u32 offset = bus.reg[opcode & 15].I; \ - if (shift) { \ - ROR_OFFSET; \ - } else { \ - RRX_OFFSET; \ - } - -#define ADDRESS_POST (bus.reg[base].I) -#define ADDRESS_PREDEC (bus.reg[base].I - offset) -#define ADDRESS_PREINC (bus.reg[base].I + offset) - -#define OP_STR CPUWriteMemory(address, bus.reg[dest].I) -#define OP_STRH CPUWriteHalfWord(address, bus.reg[dest].W.W0) -#define OP_STRB CPUWriteByte(address, bus.reg[dest].B.B0) -#define OP_LDR bus.reg[dest].I = CPUReadMemory(address) -#define OP_LDRH bus.reg[dest].I = CPUReadHalfWord(address) -#define OP_LDRB bus.reg[dest].I = CPUReadByte(address) -#define OP_LDRSH bus.reg[dest].I = (s16)CPUReadHalfWordSigned(address) -#define OP_LDRSB bus.reg[dest].I = (s8)CPUReadByte(address) - -#define WRITEBACK_NONE /*nothing*/ -#define WRITEBACK_PRE bus.reg[base].I = address -#define WRITEBACK_POSTDEC bus.reg[base].I = address - offset -#define WRITEBACK_POSTINC bus.reg[base].I = address + offset - -#define LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS) \ - if (bus.busPrefetchCount == 0) \ - bus.busPrefetch = bus.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; \ - int dataticks_val; \ - if(SIZE == 32) \ - dataticks_val = DATATICKS_ACCESS_32BIT(address); \ - else \ - dataticks_val = DATATICKS_ACCESS_16BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_val); \ - clockTicks = 2 + dataticks_val + codeTicksAccess(bus.armNextPC, BITS_32); - -#define LDR(CALC_OFFSET, CALC_ADDRESS, LOAD_DATA, WRITEBACK, SIZE) \ - LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS); \ - LOAD_DATA; \ - if (dest != base) \ - { \ - WRITEBACK; \ - } \ - clockTicks = 0; \ - int dataticks_value; \ - if (dest == 15) { \ - bus.reg[15].I &= 0xFFFFFFFC; \ - bus.armNextPC = bus.reg[15].I; \ - bus.reg[15].I += 4; \ - ARM_PREFETCH; \ - dataticks_value = DATATICKS_ACCESS_32BIT_SEQ(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); \ - clockTicks += 2 + (dataticks_value << 1);\ - } \ - if(SIZE == 32) \ - dataticks_value = DATATICKS_ACCESS_32BIT(address); \ - else \ - dataticks_value = DATATICKS_ACCESS_16BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); \ - clockTicks += 3 + dataticks_value + codeTicksAccess(bus.armNextPC, BITS_32); -#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 - void arm00B(u32 opcode) { STR_POSTDEC(OFFSET_REG, OP_STRH, 16); } -// STRH Rd, [Rn], #-offset - void arm04B(u32 opcode) { STR_POSTDEC(OFFSET_IMM8, OP_STRH, 16); } -// STRH Rd, [Rn], Rm - void arm08B(u32 opcode) { STR_POSTINC(OFFSET_REG, OP_STRH, 16); } -// STRH Rd, [Rn], #offset - void arm0CB(u32 opcode) { STR_POSTINC(OFFSET_IMM8, OP_STRH, 16); } -// STRH Rd, [Rn, -Rm] - void arm10B(u32 opcode) { STR_PREDEC(OFFSET_REG, OP_STRH, 16); } -// STRH Rd, [Rn, -Rm]! - void arm12B(u32 opcode) { STR_PREDEC_WB(OFFSET_REG, OP_STRH, 16); } -// STRH Rd, [Rn, -#offset] - void arm14B(u32 opcode) { STR_PREDEC(OFFSET_IMM8, OP_STRH, 16); } -// STRH Rd, [Rn, -#offset]! - void arm16B(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM8, OP_STRH, 16); } -// STRH Rd, [Rn, Rm] - void arm18B(u32 opcode) { STR_PREINC(OFFSET_REG, OP_STRH, 16); } -// STRH Rd, [Rn, Rm]! - void arm1AB(u32 opcode) { STR_PREINC_WB(OFFSET_REG, OP_STRH, 16); } -// STRH Rd, [Rn, #offset] - void arm1CB(u32 opcode) { STR_PREINC(OFFSET_IMM8, OP_STRH, 16); } -// STRH Rd, [Rn, #offset]! - void arm1EB(u32 opcode) { STR_PREINC_WB(OFFSET_IMM8, OP_STRH, 16); } - -// LDRH Rd, [Rn], -Rm - void arm01B(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRH, 16); } -// LDRH Rd, [Rn], #-offset - void arm05B(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRH, 16); } -// LDRH Rd, [Rn], Rm - void arm09B(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRH, 16); } -// LDRH Rd, [Rn], #offset - void arm0DB(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRH, 16); } -// LDRH Rd, [Rn, -Rm] - void arm11B(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRH, 16); } -// LDRH Rd, [Rn, -Rm]! - void arm13B(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRH, 16); } -// LDRH Rd, [Rn, -#offset] - void arm15B(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRH, 16); } -// LDRH Rd, [Rn, -#offset]! - void arm17B(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRH, 16); } -// LDRH Rd, [Rn, Rm] - void arm19B(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRH, 16); } -// LDRH Rd, [Rn, Rm]! - void arm1BB(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRH, 16); } -// LDRH Rd, [Rn, #offset] - void arm1DB(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRH, 16); } -// LDRH Rd, [Rn, #offset]! - void arm1FB(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRH, 16); } - -// LDRSB Rd, [Rn], -Rm - void arm01D(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRSB, 16); } -// LDRSB Rd, [Rn], #-offset - void arm05D(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRSB, 16); } -// LDRSB Rd, [Rn], Rm - void arm09D(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRSB, 16); } -// LDRSB Rd, [Rn], #offset - void arm0DD(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, -Rm] - void arm11D(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, -Rm]! - void arm13D(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, -#offset] - void arm15D(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, -#offset]! - void arm17D(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, Rm] - void arm19D(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, Rm]! - void arm1BD(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, #offset] - void arm1DD(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRSB, 16); } -// LDRSB Rd, [Rn, #offset]! - void arm1FD(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRSB, 16); } - -// LDRSH Rd, [Rn], -Rm - void arm01F(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRSH, 16); } -// LDRSH Rd, [Rn], #-offset - void arm05F(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRSH, 16); } -// LDRSH Rd, [Rn], Rm - void arm09F(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRSH, 16); } -// LDRSH Rd, [Rn], #offset - void arm0DF(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, -Rm] - void arm11F(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, -Rm]! - void arm13F(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, -#offset] - void arm15F(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, -#offset]! - void arm17F(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, Rm] - void arm19F(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, Rm]! - void arm1BF(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, #offset] - void arm1DF(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRSH, 16); } -// LDRSH Rd, [Rn, #offset]! - 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) - void arm400(u32 opcode) { STR_POSTDEC(OFFSET_IMM, OP_STR, 32); } -// LDR[T] Rd, [Rn], -# - void arm410(u32 opcode) { LDR_POSTDEC(OFFSET_IMM, OP_LDR, 32); } -// STRB[T] Rd, [Rn], -# - void arm440(u32 opcode) { STR_POSTDEC(OFFSET_IMM, OP_STRB, 16); } -// LDRB[T] Rd, [Rn], -# - void arm450(u32 opcode) { LDR_POSTDEC(OFFSET_IMM, OP_LDRB, 16); } -// STR[T] Rd, [Rn], # - void arm480(u32 opcode) { STR_POSTINC(OFFSET_IMM, OP_STR, 32); } -// LDR Rd, [Rn], # - void arm490(u32 opcode) { LDR_POSTINC(OFFSET_IMM, OP_LDR, 32); } -// STRB[T] Rd, [Rn], # - void arm4C0(u32 opcode) { STR_POSTINC(OFFSET_IMM, OP_STRB, 16); } -// LDRB[T] Rd, [Rn], # - void arm4D0(u32 opcode) { LDR_POSTINC(OFFSET_IMM, OP_LDRB, 16); } -// STR Rd, [Rn, -#] - void arm500(u32 opcode) { STR_PREDEC(OFFSET_IMM, OP_STR, 32); } -// LDR Rd, [Rn, -#] - void arm510(u32 opcode) { LDR_PREDEC(OFFSET_IMM, OP_LDR, 32); } -// STR Rd, [Rn, -#]! - void arm520(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM, OP_STR, 32); } -// LDR Rd, [Rn, -#]! - void arm530(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM, OP_LDR, 32); } -// STRB Rd, [Rn, -#] - void arm540(u32 opcode) { STR_PREDEC(OFFSET_IMM, OP_STRB, 16); } -// LDRB Rd, [Rn, -#] - void arm550(u32 opcode) { LDR_PREDEC(OFFSET_IMM, OP_LDRB, 16); } -// STRB Rd, [Rn, -#]! - void arm560(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM, OP_STRB, 16); } -// LDRB Rd, [Rn, -#]! - void arm570(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM, OP_LDRB, 16); } -// STR Rd, [Rn, #] - void arm580(u32 opcode) { STR_PREINC(OFFSET_IMM, OP_STR, 32); } -// LDR Rd, [Rn, #] - void arm590(u32 opcode) { LDR_PREINC(OFFSET_IMM, OP_LDR, 32); } -// STR Rd, [Rn, #]! - void arm5A0(u32 opcode) { STR_PREINC_WB(OFFSET_IMM, OP_STR, 32); } -// LDR Rd, [Rn, #]! - void arm5B0(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM, OP_LDR, 32); } -// STRB Rd, [Rn, #] - void arm5C0(u32 opcode) { STR_PREINC(OFFSET_IMM, OP_STRB, 16); } -// LDRB Rd, [Rn, #] - void arm5D0(u32 opcode) { LDR_PREINC(OFFSET_IMM, OP_LDRB, 16); } -// STRB Rd, [Rn, #]! - void arm5E0(u32 opcode) { STR_PREINC_WB(OFFSET_IMM, OP_STRB, 16); } -// LDRB Rd, [Rn, #]! - void arm5F0(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM, OP_LDRB, 16); } - -// STR[T] Rd, [Rn], -Rm, LSL # - void arm600(u32 opcode) { STR_POSTDEC(OFFSET_LSL, OP_STR, 32); } -// STR[T] Rd, [Rn], -Rm, LSR # - void arm602(u32 opcode) { STR_POSTDEC(OFFSET_LSR, OP_STR, 32); } -// STR[T] Rd, [Rn], -Rm, ASR # - void arm604(u32 opcode) { STR_POSTDEC(OFFSET_ASR, OP_STR, 32); } -// STR[T] Rd, [Rn], -Rm, ROR # - void arm606(u32 opcode) { STR_POSTDEC(OFFSET_ROR, OP_STR, 32); } -// LDR[T] Rd, [Rn], -Rm, LSL # - void arm610(u32 opcode) { LDR_POSTDEC(OFFSET_LSL, OP_LDR, 32); } -// LDR[T] Rd, [Rn], -Rm, LSR # - void arm612(u32 opcode) { LDR_POSTDEC(OFFSET_LSR, OP_LDR, 32); } -// LDR[T] Rd, [Rn], -Rm, ASR # - void arm614(u32 opcode) { LDR_POSTDEC(OFFSET_ASR, OP_LDR, 32); } -// LDR[T] Rd, [Rn], -Rm, ROR # - void arm616(u32 opcode) { LDR_POSTDEC(OFFSET_ROR, OP_LDR, 32); } -// STRB[T] Rd, [Rn], -Rm, LSL # - void arm640(u32 opcode) { STR_POSTDEC(OFFSET_LSL, OP_STRB, 16); } -// STRB[T] Rd, [Rn], -Rm, LSR # - void arm642(u32 opcode) { STR_POSTDEC(OFFSET_LSR, OP_STRB, 16); } -// STRB[T] Rd, [Rn], -Rm, ASR # - void arm644(u32 opcode) { STR_POSTDEC(OFFSET_ASR, OP_STRB, 16); } -// STRB[T] Rd, [Rn], -Rm, ROR # - void arm646(u32 opcode) { STR_POSTDEC(OFFSET_ROR, OP_STRB, 16); } -// LDRB[T] Rd, [Rn], -Rm, LSL # - void arm650(u32 opcode) { LDR_POSTDEC(OFFSET_LSL, OP_LDRB, 16); } -// LDRB[T] Rd, [Rn], -Rm, LSR # - void arm652(u32 opcode) { LDR_POSTDEC(OFFSET_LSR, OP_LDRB, 16); } -// LDRB[T] Rd, [Rn], -Rm, ASR # - void arm654(u32 opcode) { LDR_POSTDEC(OFFSET_ASR, OP_LDRB, 16); } -// LDRB Rd, [Rn], -Rm, ROR # - void arm656(u32 opcode) { LDR_POSTDEC(OFFSET_ROR, OP_LDRB, 16); } -// STR[T] Rd, [Rn], Rm, LSL # - void arm680(u32 opcode) { STR_POSTINC(OFFSET_LSL, OP_STR, 32); } -// STR[T] Rd, [Rn], Rm, LSR # - void arm682(u32 opcode) { STR_POSTINC(OFFSET_LSR, OP_STR, 32); } -// STR[T] Rd, [Rn], Rm, ASR # - void arm684(u32 opcode) { STR_POSTINC(OFFSET_ASR, OP_STR, 32); } -// STR[T] Rd, [Rn], Rm, ROR # - void arm686(u32 opcode) { STR_POSTINC(OFFSET_ROR, OP_STR, 32); } -// LDR[T] Rd, [Rn], Rm, LSL # - void arm690(u32 opcode) { LDR_POSTINC(OFFSET_LSL, OP_LDR, 32); } -// LDR[T] Rd, [Rn], Rm, LSR # - void arm692(u32 opcode) { LDR_POSTINC(OFFSET_LSR, OP_LDR, 32); } -// LDR[T] Rd, [Rn], Rm, ASR # - void arm694(u32 opcode) { LDR_POSTINC(OFFSET_ASR, OP_LDR, 32); } -// LDR[T] Rd, [Rn], Rm, ROR # - void arm696(u32 opcode) { LDR_POSTINC(OFFSET_ROR, OP_LDR, 32); } -// STRB[T] Rd, [Rn], Rm, LSL # - void arm6C0(u32 opcode) { STR_POSTINC(OFFSET_LSL, OP_STRB, 16); } -// STRB[T] Rd, [Rn], Rm, LSR # - void arm6C2(u32 opcode) { STR_POSTINC(OFFSET_LSR, OP_STRB, 16); } -// STRB[T] Rd, [Rn], Rm, ASR # - void arm6C4(u32 opcode) { STR_POSTINC(OFFSET_ASR, OP_STRB, 16); } -// STRB[T] Rd, [Rn], Rm, ROR # - void arm6C6(u32 opcode) { STR_POSTINC(OFFSET_ROR, OP_STRB, 16); } -// LDRB[T] Rd, [Rn], Rm, LSL # - void arm6D0(u32 opcode) { LDR_POSTINC(OFFSET_LSL, OP_LDRB, 16); } -// LDRB[T] Rd, [Rn], Rm, LSR # - void arm6D2(u32 opcode) { LDR_POSTINC(OFFSET_LSR, OP_LDRB, 16); } -// LDRB[T] Rd, [Rn], Rm, ASR # - void arm6D4(u32 opcode) { LDR_POSTINC(OFFSET_ASR, OP_LDRB, 16); } -// LDRB[T] Rd, [Rn], Rm, ROR # - void arm6D6(u32 opcode) { LDR_POSTINC(OFFSET_ROR, OP_LDRB, 16); } -// STR Rd, [Rn, -Rm, LSL #] - void arm700(u32 opcode) { STR_PREDEC(OFFSET_LSL, OP_STR, 32); } -// STR Rd, [Rn, -Rm, LSR #] - void arm702(u32 opcode) { STR_PREDEC(OFFSET_LSR, OP_STR, 32); } -// STR Rd, [Rn, -Rm, ASR #] - void arm704(u32 opcode) { STR_PREDEC(OFFSET_ASR, OP_STR, 32); } -// STR Rd, [Rn, -Rm, ROR #] - void arm706(u32 opcode) { STR_PREDEC(OFFSET_ROR, OP_STR, 32); } -// LDR Rd, [Rn, -Rm, LSL #] - void arm710(u32 opcode) { LDR_PREDEC(OFFSET_LSL, OP_LDR, 32); } -// LDR Rd, [Rn, -Rm, LSR #] - void arm712(u32 opcode) { LDR_PREDEC(OFFSET_LSR, OP_LDR, 32); } -// LDR Rd, [Rn, -Rm, ASR #] - void arm714(u32 opcode) { LDR_PREDEC(OFFSET_ASR, OP_LDR, 32); } -// LDR Rd, [Rn, -Rm, ROR #] - void arm716(u32 opcode) { LDR_PREDEC(OFFSET_ROR, OP_LDR, 32); } -// STR Rd, [Rn, -Rm, LSL #]! - void arm720(u32 opcode) { STR_PREDEC_WB(OFFSET_LSL, OP_STR, 32); } -// STR Rd, [Rn, -Rm, LSR #]! - void arm722(u32 opcode) { STR_PREDEC_WB(OFFSET_LSR, OP_STR, 32); } -// STR Rd, [Rn, -Rm, ASR #]! - void arm724(u32 opcode) { STR_PREDEC_WB(OFFSET_ASR, OP_STR, 32); } -// STR Rd, [Rn, -Rm, ROR #]! - void arm726(u32 opcode) { STR_PREDEC_WB(OFFSET_ROR, OP_STR, 32); } -// LDR Rd, [Rn, -Rm, LSL #]! - void arm730(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSL, OP_LDR, 32); } -// LDR Rd, [Rn, -Rm, LSR #]! - void arm732(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSR, OP_LDR, 32); } -// LDR Rd, [Rn, -Rm, ASR #]! - void arm734(u32 opcode) { LDR_PREDEC_WB(OFFSET_ASR, OP_LDR, 32); } -// LDR Rd, [Rn, -Rm, ROR #]! - void arm736(u32 opcode) { LDR_PREDEC_WB(OFFSET_ROR, OP_LDR, 32); } -// STRB Rd, [Rn, -Rm, LSL #] - void arm740(u32 opcode) { STR_PREDEC(OFFSET_LSL, OP_STRB, 16); } -// STRB Rd, [Rn, -Rm, LSR #] - void arm742(u32 opcode) { STR_PREDEC(OFFSET_LSR, OP_STRB, 16); } -// STRB Rd, [Rn, -Rm, ASR #] - void arm744(u32 opcode) { STR_PREDEC(OFFSET_ASR, OP_STRB, 16); } -// STRB Rd, [Rn, -Rm, ROR #] - void arm746(u32 opcode) { STR_PREDEC(OFFSET_ROR, OP_STRB, 16); } -// LDRB Rd, [Rn, -Rm, LSL #] - void arm750(u32 opcode) { LDR_PREDEC(OFFSET_LSL, OP_LDRB, 16); } -// LDRB Rd, [Rn, -Rm, LSR #] - void arm752(u32 opcode) { LDR_PREDEC(OFFSET_LSR, OP_LDRB, 16); } -// LDRB Rd, [Rn, -Rm, ASR #] - void arm754(u32 opcode) { LDR_PREDEC(OFFSET_ASR, OP_LDRB, 16); } -// LDRB Rd, [Rn, -Rm, ROR #] - void arm756(u32 opcode) { LDR_PREDEC(OFFSET_ROR, OP_LDRB, 16); } -// STRB Rd, [Rn, -Rm, LSL #]! - void arm760(u32 opcode) { STR_PREDEC_WB(OFFSET_LSL, OP_STRB, 16); } -// STRB Rd, [Rn, -Rm, LSR #]! - void arm762(u32 opcode) { STR_PREDEC_WB(OFFSET_LSR, OP_STRB, 16); } -// STRB Rd, [Rn, -Rm, ASR #]! - void arm764(u32 opcode) { STR_PREDEC_WB(OFFSET_ASR, OP_STRB, 16); } -// STRB Rd, [Rn, -Rm, ROR #]! - void arm766(u32 opcode) { STR_PREDEC_WB(OFFSET_ROR, OP_STRB, 16); } -// LDRB Rd, [Rn, -Rm, LSL #]! - void arm770(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSL, OP_LDRB, 16); } -// LDRB Rd, [Rn, -Rm, LSR #]! - void arm772(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSR, OP_LDRB, 16); } -// LDRB Rd, [Rn, -Rm, ASR #]! - void arm774(u32 opcode) { LDR_PREDEC_WB(OFFSET_ASR, OP_LDRB, 16); } -// LDRB Rd, [Rn, -Rm, ROR #]! - void arm776(u32 opcode) { LDR_PREDEC_WB(OFFSET_ROR, OP_LDRB, 16); } -// STR Rd, [Rn, Rm, LSL #] - void arm780(u32 opcode) { STR_PREINC(OFFSET_LSL, OP_STR, 32); } -// STR Rd, [Rn, Rm, LSR #] - void arm782(u32 opcode) { STR_PREINC(OFFSET_LSR, OP_STR, 32); } -// STR Rd, [Rn, Rm, ASR #] - void arm784(u32 opcode) { STR_PREINC(OFFSET_ASR, OP_STR, 32); } -// STR Rd, [Rn, Rm, ROR #] - void arm786(u32 opcode) { STR_PREINC(OFFSET_ROR, OP_STR, 32); } -// LDR Rd, [Rn, Rm, LSL #] - void arm790(u32 opcode) { LDR_PREINC(OFFSET_LSL, OP_LDR, 32); } -// LDR Rd, [Rn, Rm, LSR #] - void arm792(u32 opcode) { LDR_PREINC(OFFSET_LSR, OP_LDR, 32); } -// LDR Rd, [Rn, Rm, ASR #] - void arm794(u32 opcode) { LDR_PREINC(OFFSET_ASR, OP_LDR, 32); } -// LDR Rd, [Rn, Rm, ROR #] - void arm796(u32 opcode) { LDR_PREINC(OFFSET_ROR, OP_LDR, 32); } -// STR Rd, [Rn, Rm, LSL #]! - void arm7A0(u32 opcode) { STR_PREINC_WB(OFFSET_LSL, OP_STR, 32); } -// STR Rd, [Rn, Rm, LSR #]! - void arm7A2(u32 opcode) { STR_PREINC_WB(OFFSET_LSR, OP_STR, 32); } -// STR Rd, [Rn, Rm, ASR #]! - void arm7A4(u32 opcode) { STR_PREINC_WB(OFFSET_ASR, OP_STR, 32); } -// STR Rd, [Rn, Rm, ROR #]! - void arm7A6(u32 opcode) { STR_PREINC_WB(OFFSET_ROR, OP_STR, 32); } -// LDR Rd, [Rn, Rm, LSL #]! - void arm7B0(u32 opcode) { LDR_PREINC_WB(OFFSET_LSL, OP_LDR, 32); } -// LDR Rd, [Rn, Rm, LSR #]! - void arm7B2(u32 opcode) { LDR_PREINC_WB(OFFSET_LSR, OP_LDR, 32); } -// LDR Rd, [Rn, Rm, ASR #]! - void arm7B4(u32 opcode) { LDR_PREINC_WB(OFFSET_ASR, OP_LDR, 32); } -// LDR Rd, [Rn, Rm, ROR #]! - void arm7B6(u32 opcode) { LDR_PREINC_WB(OFFSET_ROR, OP_LDR, 32); } -// STRB Rd, [Rn, Rm, LSL #] - void arm7C0(u32 opcode) { STR_PREINC(OFFSET_LSL, OP_STRB, 16); } -// STRB Rd, [Rn, Rm, LSR #] - void arm7C2(u32 opcode) { STR_PREINC(OFFSET_LSR, OP_STRB, 16); } -// STRB Rd, [Rn, Rm, ASR #] - void arm7C4(u32 opcode) { STR_PREINC(OFFSET_ASR, OP_STRB, 16); } -// STRB Rd, [Rn, Rm, ROR #] - void arm7C6(u32 opcode) { STR_PREINC(OFFSET_ROR, OP_STRB, 16); } -// LDRB Rd, [Rn, Rm, LSL #] - void arm7D0(u32 opcode) { LDR_PREINC(OFFSET_LSL, OP_LDRB, 16); } -// LDRB Rd, [Rn, Rm, LSR #] - void arm7D2(u32 opcode) { LDR_PREINC(OFFSET_LSR, OP_LDRB, 16); } -// LDRB Rd, [Rn, Rm, ASR #] - void arm7D4(u32 opcode) { LDR_PREINC(OFFSET_ASR, OP_LDRB, 16); } -// LDRB Rd, [Rn, Rm, ROR #] - void arm7D6(u32 opcode) { LDR_PREINC(OFFSET_ROR, OP_LDRB, 16); } -// STRB Rd, [Rn, Rm, LSL #]! - void arm7E0(u32 opcode) { STR_PREINC_WB(OFFSET_LSL, OP_STRB, 16); } -// STRB Rd, [Rn, Rm, LSR #]! - void arm7E2(u32 opcode) { STR_PREINC_WB(OFFSET_LSR, OP_STRB, 16); } -// STRB Rd, [Rn, Rm, ASR #]! - void arm7E4(u32 opcode) { STR_PREINC_WB(OFFSET_ASR, OP_STRB, 16); } -// STRB Rd, [Rn, Rm, ROR #]! - void arm7E6(u32 opcode) { STR_PREINC_WB(OFFSET_ROR, OP_STRB, 16); } -// LDRB Rd, [Rn, Rm, LSL #]! - void arm7F0(u32 opcode) { LDR_PREINC_WB(OFFSET_LSL, OP_LDRB, 16); } -// LDRB Rd, [Rn, Rm, LSR #]! - void arm7F2(u32 opcode) { LDR_PREINC_WB(OFFSET_LSR, OP_LDRB, 16); } -// LDRB Rd, [Rn, Rm, ASR #]! - void arm7F4(u32 opcode) { LDR_PREINC_WB(OFFSET_ASR, OP_LDRB, 16); } -// LDRB Rd, [Rn, Rm, ROR #]! - 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, bus.reg[(num)].I); \ - int dataticks_value = count ? DATATICKS_ACCESS_32BIT_SEQ(address) : DATATICKS_ACCESS_32BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); \ - clockTicks += 1 + dataticks_value; \ - count++; \ - address += 4; \ - } -#define STMW_REG(bit,num) \ - if (opcode & (1U<<(bit))) { \ - CPUWriteMemory(address, bus.reg[(num)].I); \ - int dataticks_value = count ? DATATICKS_ACCESS_32BIT_SEQ(address) : DATATICKS_ACCESS_32BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); \ - clockTicks += 1 + dataticks_value; \ - bus.reg[base].I = temp; \ - count++; \ - address += 4; \ - } -#define LDM_REG(bit,num) \ - if (opcode & (1U<<(bit))) { \ - int dataticks_value; \ - bus.reg[(num)].I = CPUReadMemory(address); \ - dataticks_value = count ? DATATICKS_ACCESS_32BIT_SEQ(address) : DATATICKS_ACCESS_32BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); \ - clockTicks += 1 + dataticks_value; \ - 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, bus.reg[15].I+4); \ - int dataticks_value = count ? DATATICKS_ACCESS_32BIT_SEQ(address) : DATATICKS_ACCESS_32BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); \ - clockTicks += 1 + dataticks_value; \ - count++; \ - } -#define STMW_PC \ - if (opcode & (1U<<15)) { \ - CPUWriteMemory(address, bus.reg[15].I+4); \ - int dataticks_value = count ? DATATICKS_ACCESS_32BIT_SEQ(address) : DATATICKS_ACCESS_32BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); \ - clockTicks += 1 + dataticks_value; \ - bus.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)) { \ - bus.reg[15].I = CPUReadMemory(address); \ - int dataticks_value = count ? DATATICKS_ACCESS_32BIT_SEQ(address) : DATATICKS_ACCESS_32BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); \ - clockTicks += 1 + dataticks_value; \ - count++; \ - } \ - if (opcode & (1U<<15)) { \ - bus.armNextPC = bus.reg[15].I; \ - bus.reg[15].I += 4; \ - ARM_PREFETCH; \ - clockTicks += 1 + codeTicksAccessSeq32(bus.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; \ - bus.reg[15].I = CPUReadMemory(address); \ - int dataticks_value = count ? DATATICKS_ACCESS_32BIT_SEQ(address) : DATATICKS_ACCESS_32BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); \ - clockTicks += 1 + dataticks_value; \ - count++; \ - } else { \ - LDM_HIGH_2; \ - } -#define LDM_ALL_2B \ - if (opcode & (1U<<15)) { \ - if(armMode != (bus.reg[17].I & 0x1F)) \ - CPUSwitchMode(bus.reg[17].I & 0x1F, false, true); \ - if (armState) { \ - bus.armNextPC = bus.reg[15].I & 0xFFFFFFFC; \ - bus.reg[15].I = bus.armNextPC + 4; \ - ARM_PREFETCH; \ - } else { \ - bus.armNextPC = bus.reg[15].I & 0xFFFFFFFE; \ - bus.reg[15].I = bus.armNextPC + 2; \ - THUMB_PREFETCH; \ - } \ - clockTicks += 1 + codeTicksAccessSeq32(bus.armNextPC);\ - } - - -// STMDA Rn, {Rlist} - void arm800(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - int count = 0; - STM_ALL; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMDA Rn, {Rlist} - void arm810(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// STMDA Rn!, {Rlist} - void arm820(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp+4) & 0xFFFFFFFC; - int count = 0; - STMW_ALL; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMDA Rn!, {Rlist} - void arm830(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); - if (!(opcode & (1U << base))) - bus.reg[base].I = temp; -} - -// STMDA Rn, {Rlist}^ - void arm840(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp+4) & 0xFFFFFFFC; - int count = 0; - STM_ALL_2; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMDA Rn, {Rlist}^ - void arm850(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.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 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// STMDA Rn!, {Rlist}^ - void arm860(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp+4) & 0xFFFFFFFC; - int count = 0; - STMW_ALL_2; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMDA Rn!, {Rlist}^ - void arm870(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.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))) - bus.reg[base].I = temp; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// STMIA Rn, {Rlist} - void arm880(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = bus.reg[base].I & 0xFFFFFFFC; - int count = 0; - STM_ALL; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMIA Rn, {Rlist} - void arm890(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = bus.reg[base].I & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// STMIA Rn!, {Rlist} - void arm8A0(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = bus.reg[base].I & 0xFFFFFFFC; - int count = 0; - u32 temp = bus.reg[base].I + - 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); - STMW_ALL; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMIA Rn!, {Rlist} - void arm8B0(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I + - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = bus.reg[base].I & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); - if (!(opcode & (1U << base))) - bus.reg[base].I = temp; -} - -// STMIA Rn, {Rlist}^ - void arm8C0(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = bus.reg[base].I & 0xFFFFFFFC; - int count = 0; - STM_ALL_2; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMIA Rn, {Rlist}^ - void arm8D0(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = bus.reg[base].I & 0xFFFFFFFC; - int count = 0; - LDM_ALL_2; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// STMIA Rn!, {Rlist}^ - void arm8E0(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = bus.reg[base].I & 0xFFFFFFFC; - int count = 0; - u32 temp = bus.reg[base].I + - 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); - STMW_ALL_2; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMIA Rn!, {Rlist}^ - void arm8F0(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I + - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = bus.reg[base].I & 0xFFFFFFFC; - int count = 0; - LDM_ALL_2; - if (!(opcode & (1U << base))) - bus.reg[base].I = temp; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// STMDB Rn, {Rlist} - void arm900(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - STM_ALL; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMDB Rn, {Rlist} - void arm910(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// STMDB Rn!, {Rlist} - void arm920(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - STMW_ALL; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMDB Rn!, {Rlist} - void arm930(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); - if (!(opcode & (1U << base))) - bus.reg[base].I = temp; -} - -// STMDB Rn, {Rlist}^ - void arm940(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - STM_ALL_2; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMDB Rn, {Rlist}^ - void arm950(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.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 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// STMDB Rn!, {Rlist}^ - void arm960(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - int count = 0; - STMW_ALL_2; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMDB Rn!, {Rlist}^ - void arm970(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.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))) - bus.reg[base].I = temp; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// STMIB Rn, {Rlist} - void arm980(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = (bus.reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - STM_ALL; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMIB Rn, {Rlist} - void arm990(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = (bus.reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// STMIB Rn!, {Rlist} - void arm9A0(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = (bus.reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - u32 temp = bus.reg[base].I + - 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); - STMW_ALL; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMIB Rn!, {Rlist} - void arm9B0(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I + - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (bus.reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); - if (!(opcode & (1U << base))) - bus.reg[base].I = temp; -} - -// STMIB Rn, {Rlist}^ - void arm9C0(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = (bus.reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - STM_ALL_2; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMIB Rn, {Rlist}^ - void arm9D0(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = (bus.reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL_2; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// STMIB Rn!, {Rlist}^ - void arm9E0(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 address = (bus.reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - u32 temp = bus.reg[base].I + - 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); - STMW_ALL_2; - clockTicks += 1 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// LDMIB Rn!, {Rlist}^ - void arm9F0(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int base = (opcode & 0x000F0000) >> 16; - u32 temp = bus.reg[base].I + - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (bus.reg[base].I+4) & 0xFFFFFFFC; - int count = 0; - LDM_ALL_2; - if (!(opcode & (1U << base))) - bus.reg[base].I = temp; - LDM_ALL_2B; - clockTicks += 2 + codeTicksAccess(bus.armNextPC, BITS_32); -} - -// B/BL/SWI and (unimplemented) coproc support //////////////////////////// - -// B - void armA00(u32 opcode) -{ - int codeTicksVal = 0; - int ct = 0; - int offset = opcode & 0x00FFFFFF; - if (offset & 0x00800000) - offset |= 0xFF000000; // negative offset - bus.reg[15].I += offset<<2; - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 4; - ARM_PREFETCH; - - codeTicksVal = codeTicksAccessSeq32(bus.armNextPC); - ct = codeTicksVal + 3; - ct += 2 + codeTicksAccess(bus.armNextPC, BITS_32) + codeTicksVal; - - bus.busPrefetchCount = 0; - clockTicks = ct; -} - -// BL - void armB00(u32 opcode) -{ - int codeTicksVal = 0; - int ct = 0; - - int offset = opcode & 0x00FFFFFF; - if (offset & 0x00800000) - offset |= 0xFF000000; // negative offset - bus.reg[14].I = bus.reg[15].I - 4; - bus.reg[15].I += offset<<2; - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 4; - ARM_PREFETCH; - - codeTicksVal = codeTicksAccessSeq32(bus.armNextPC); - ct = codeTicksVal + 3; - ct += 2 + codeTicksAccess(bus.armNextPC, BITS_32) + codeTicksVal; - - bus.busPrefetchCount = 0; - clockTicks = ct; -} - -#define armE01 armUnknownInsn - -// SWI - void armF00(u32 opcode) -{ - int codeTicksVal = 0; - int ct = 0; - - codeTicksVal = codeTicksAccessSeq32(bus.armNextPC); - ct = codeTicksVal + 3; - ct += 2 + codeTicksAccess(bus.armNextPC, BITS_32) + codeTicksVal; - - bus.busPrefetchCount = 0; - - clockTicks = ct; - CPUSoftwareInterrupt(opcode & 0x00FFFFFF); - -} - -// Instruction table ////////////////////////////////////////////////////// - -static void (Gigazoid::*const armInsnTable[4096])(u32 opcode); - -// Wrapper routine (execution loop) /////////////////////////////////////// -int armExecute (void) -{ - CACHE_PREFETCH(clockTicks); - - u32 cond1; - u32 cond2; - - int ct = 0; - - do - { - - clockTicks = 0; - - if ((bus.armNextPC & 0x0803FFFF) == 0x08020000) - bus.busPrefetchCount = 0x100; - - u32 opcode = cpuPrefetch[0]; - cpuPrefetch[0] = cpuPrefetch[1]; - - bus.busPrefetch = false; - int32_t busprefetch_mask = ((bus.busPrefetchCount & 0xFFFFFE00) | -(bus.busPrefetchCount & 0xFFFFFE00)) >> 31; - bus.busPrefetchCount = (0x100 | (bus.busPrefetchCount & 0xFF) & busprefetch_mask) | (bus.busPrefetchCount & ~busprefetch_mask); -#if 0 - if (bus.busPrefetchCount & 0xFFFFFE00) - bus.busPrefetchCount = 0x100 | (bus.busPrefetchCount & 0xFF); -#endif - - - int oldArmNextPC = bus.armNextPC; - - bus.armNextPC = bus.reg[15].I; - if (traceCallback) - traceCallback(bus.armNextPC, opcode); - if (fetchCallback) - fetchCallback(bus.armNextPC); - bus.reg[15].I += 4; - ARM_PREFETCH_NEXT; - - int cond = opcode >> 28; - bool cond_res = true; - if (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) - { - cond1 = (opcode>>16)&0xFF0; - cond2 = (opcode>>4)&0x0F; - - (this->*armInsnTable[(cond1| cond2)])(opcode); - - } - ct = clockTicks; - - if (ct < 0) - return 0; - - /// better pipelining - - if (ct == 0) - clockTicks = 1 + codeTicksAccessSeq32(oldArmNextPC); - - cpuTotalTicks += clockTicks; - -} while ((cpuTotalTicks < cpuNextEvent) & armState & ~holdState); - return 1; -} - - -/*============================================================ - GBA THUMB CORE -============================================================ */ - - void thumbUnknownInsn(u32 opcode) -{ - u32 PC = bus.reg[15].I; - bool savedArmState = armState; - if(armMode != 0x1b) - CPUSwitchMode(0x1b, true, false); - bus.reg[14].I = PC - (savedArmState ? 4 : 2); - bus.reg[15].I = 0x04; - armState = true; - armIrqEnable = false; - bus.armNextPC = 0x04; - ARM_PREFETCH; - bus.reg[15].I += 4; -} - -#define NEG(i) ((i) >> 31) -#define POS(i) ((~(i)) >> 31) - -// 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 = bus.reg[source].I;\ - u32 rhs = bus.reg[N].I;\ - u32 res = lhs + rhs;\ - bus.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 = bus.reg[source].I;\ - u32 rhs = N;\ - u32 res = lhs + rhs;\ - bus.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 = bus.reg[(d)].I;\ - u32 rhs = (opcode & 255);\ - u32 res = lhs + rhs;\ - bus.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 = bus.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 = bus.reg[dest].I;\ - u32 rhs = value;\ - u32 res = lhs + rhs + (u32)C_FLAG;\ - bus.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 = bus.reg[source].I;\ - u32 rhs = bus.reg[N].I;\ - u32 res = lhs - rhs;\ - bus.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 = bus.reg[source].I;\ - u32 rhs = N;\ - u32 res = lhs - rhs;\ - bus.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 = bus.reg[(d)].I;\ - u32 rhs = (opcode & 255);\ - u32 res = lhs - rhs;\ - bus.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) \ - {\ - u32 val;\ - val = (opcode & 255);\ - bus.reg[d].I = val;\ - N_FLAG = false;\ - Z_FLAG = (val ? false : true);\ - } -#endif -#ifndef CMP_RN_O8 - #define CMP_RN_O8(d) \ - {\ - u32 lhs = bus.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 = bus.reg[dest].I;\ - u32 rhs = value;\ - u32 res = lhs - rhs - !((u32)C_FLAG);\ - bus.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 = (bus.reg[source].I >> (32 - shift)) & 1 ? true : false;\ - value = bus.reg[source].I << shift;\ - } -#endif -#ifndef LSL_RD_RS - #define LSL_RD_RS \ - {\ - C_FLAG = (bus.reg[dest].I >> (32 - value)) & 1 ? true : false;\ - value = bus.reg[dest].I << value;\ - } -#endif -#ifndef LSR_RD_RM_I5 - #define LSR_RD_RM_I5 \ - {\ - C_FLAG = (bus.reg[source].I >> (shift - 1)) & 1 ? true : false;\ - value = bus.reg[source].I >> shift;\ - } -#endif -#ifndef LSR_RD_RS - #define LSR_RD_RS \ - {\ - C_FLAG = (bus.reg[dest].I >> (value - 1)) & 1 ? true : false;\ - value = bus.reg[dest].I >> value;\ - } -#endif -#ifndef ASR_RD_RM_I5 - #define ASR_RD_RM_I5 \ - {\ - C_FLAG = ((s32)bus.reg[source].I >> (int)(shift - 1)) & 1 ? true : false;\ - value = (s32)bus.reg[source].I >> (int)shift;\ - } -#endif -#ifndef ASR_RD_RS - #define ASR_RD_RS \ - {\ - C_FLAG = ((s32)bus.reg[dest].I >> (int)(value - 1)) & 1 ? true : false;\ - value = (s32)bus.reg[dest].I >> (int)value;\ - } -#endif -#ifndef ROR_RD_RS - #define ROR_RD_RS \ - {\ - C_FLAG = (bus.reg[dest].I >> (value - 1)) & 1 ? true : false;\ - value = ((bus.reg[dest].I << (32 - value)) |\ - (bus.reg[dest].I >> value));\ - } -#endif -#ifndef NEG_RD_RS - #define NEG_RD_RS \ - {\ - u32 lhs = bus.reg[source].I;\ - u32 rhs = 0;\ - u32 res = rhs - lhs;\ - bus.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 = bus.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);\ - bus.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;\ - bus.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 = bus.reg[source].I; - #define IMM5_LSR(N) \ - int shift = N;\ - LSR_RD_RM_I5; - #define IMM5_LSR_0 \ - C_FLAG = bus.reg[source].I & 0x80000000 ? true : false;\ - value = 0; - #define IMM5_ASR(N) \ - int shift = N;\ - ASR_RD_RM_I5; - #define IMM5_ASR_0 \ - if(bus.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) \ - void thumb##BASE##_00(u32 opcode) { IMM5_INSN_0(OP##_0); } \ - void thumb##BASE##_01(u32 opcode) { IMM5_INSN(OP, 1); } \ - void thumb##BASE##_02(u32 opcode) { IMM5_INSN(OP, 2); } \ - void thumb##BASE##_03(u32 opcode) { IMM5_INSN(OP, 3); } \ - void thumb##BASE##_04(u32 opcode) { IMM5_INSN(OP, 4); } \ - void thumb##BASE##_05(u32 opcode) { IMM5_INSN(OP, 5); } \ - void thumb##BASE##_06(u32 opcode) { IMM5_INSN(OP, 6); } \ - void thumb##BASE##_07(u32 opcode) { IMM5_INSN(OP, 7); } \ - void thumb##BASE##_08(u32 opcode) { IMM5_INSN(OP, 8); } \ - void thumb##BASE##_09(u32 opcode) { IMM5_INSN(OP, 9); } \ - void thumb##BASE##_0A(u32 opcode) { IMM5_INSN(OP,10); } \ - void thumb##BASE##_0B(u32 opcode) { IMM5_INSN(OP,11); } \ - void thumb##BASE##_0C(u32 opcode) { IMM5_INSN(OP,12); } \ - void thumb##BASE##_0D(u32 opcode) { IMM5_INSN(OP,13); } \ - void thumb##BASE##_0E(u32 opcode) { IMM5_INSN(OP,14); } \ - void thumb##BASE##_0F(u32 opcode) { IMM5_INSN(OP,15); } \ - void thumb##BASE##_10(u32 opcode) { IMM5_INSN(OP,16); } \ - void thumb##BASE##_11(u32 opcode) { IMM5_INSN(OP,17); } \ - void thumb##BASE##_12(u32 opcode) { IMM5_INSN(OP,18); } \ - void thumb##BASE##_13(u32 opcode) { IMM5_INSN(OP,19); } \ - void thumb##BASE##_14(u32 opcode) { IMM5_INSN(OP,20); } \ - void thumb##BASE##_15(u32 opcode) { IMM5_INSN(OP,21); } \ - void thumb##BASE##_16(u32 opcode) { IMM5_INSN(OP,22); } \ - void thumb##BASE##_17(u32 opcode) { IMM5_INSN(OP,23); } \ - void thumb##BASE##_18(u32 opcode) { IMM5_INSN(OP,24); } \ - void thumb##BASE##_19(u32 opcode) { IMM5_INSN(OP,25); } \ - void thumb##BASE##_1A(u32 opcode) { IMM5_INSN(OP,26); } \ - void thumb##BASE##_1B(u32 opcode) { IMM5_INSN(OP,27); } \ - void thumb##BASE##_1C(u32 opcode) { IMM5_INSN(OP,28); } \ - void thumb##BASE##_1D(u32 opcode) { IMM5_INSN(OP,29); } \ - void thumb##BASE##_1E(u32 opcode) { IMM5_INSN(OP,30); } \ - 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) \ - void thumb##BASE##_0(u32 opcode) { THREEARG_INSN(OP,0); } \ - void thumb##BASE##_1(u32 opcode) { THREEARG_INSN(OP,1); } \ - void thumb##BASE##_2(u32 opcode) { THREEARG_INSN(OP,2); } \ - void thumb##BASE##_3(u32 opcode) { THREEARG_INSN(OP,3); } \ - void thumb##BASE##_4(u32 opcode) { THREEARG_INSN(OP,4); } \ - void thumb##BASE##_5(u32 opcode) { THREEARG_INSN(OP,5); } \ - void thumb##BASE##_6(u32 opcode) { THREEARG_INSN(OP,6); } \ - void thumb##BASE##_7(u32 opcode) { THREEARG_INSN(OP,7); } - -#define DEFINE_IMM3_INSN(OP,BASE) \ - void thumb##BASE##_0(u32 opcode) { THREEARG_INSN(OP##_0,0); } \ - void thumb##BASE##_1(u32 opcode) { THREEARG_INSN(OP,1); } \ - void thumb##BASE##_2(u32 opcode) { THREEARG_INSN(OP,2); } \ - void thumb##BASE##_3(u32 opcode) { THREEARG_INSN(OP,3); } \ - void thumb##BASE##_4(u32 opcode) { THREEARG_INSN(OP,4); } \ - void thumb##BASE##_5(u32 opcode) { THREEARG_INSN(OP,5); } \ - void thumb##BASE##_6(u32 opcode) { THREEARG_INSN(OP,6); } \ - 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 - void thumb20(u32 opcode) { MOV_RN_O8(0); } -// MOV R1, #Offset8 - void thumb21(u32 opcode) { MOV_RN_O8(1); } -// MOV R2, #Offset8 - void thumb22(u32 opcode) { MOV_RN_O8(2); } -// MOV R3, #Offset8 - void thumb23(u32 opcode) { MOV_RN_O8(3); } -// MOV R4, #Offset8 - void thumb24(u32 opcode) { MOV_RN_O8(4); } -// MOV R5, #Offset8 - void thumb25(u32 opcode) { MOV_RN_O8(5); } -// MOV R6, #Offset8 - void thumb26(u32 opcode) { MOV_RN_O8(6); } -// MOV R7, #Offset8 - void thumb27(u32 opcode) { MOV_RN_O8(7); } - -// CMP R0, #Offset8 - void thumb28(u32 opcode) { CMP_RN_O8(0); } -// CMP R1, #Offset8 - void thumb29(u32 opcode) { CMP_RN_O8(1); } -// CMP R2, #Offset8 - void thumb2A(u32 opcode) { CMP_RN_O8(2); } -// CMP R3, #Offset8 - void thumb2B(u32 opcode) { CMP_RN_O8(3); } -// CMP R4, #Offset8 - void thumb2C(u32 opcode) { CMP_RN_O8(4); } -// CMP R5, #Offset8 - void thumb2D(u32 opcode) { CMP_RN_O8(5); } -// CMP R6, #Offset8 - void thumb2E(u32 opcode) { CMP_RN_O8(6); } -// CMP R7, #Offset8 - void thumb2F(u32 opcode) { CMP_RN_O8(7); } - -// ADD R0,#Offset8 - void thumb30(u32 opcode) { ADD_RN_O8(0); } -// ADD R1,#Offset8 - void thumb31(u32 opcode) { ADD_RN_O8(1); } -// ADD R2,#Offset8 - void thumb32(u32 opcode) { ADD_RN_O8(2); } -// ADD R3,#Offset8 - void thumb33(u32 opcode) { ADD_RN_O8(3); } -// ADD R4,#Offset8 - void thumb34(u32 opcode) { ADD_RN_O8(4); } -// ADD R5,#Offset8 - void thumb35(u32 opcode) { ADD_RN_O8(5); } -// ADD R6,#Offset8 - void thumb36(u32 opcode) { ADD_RN_O8(6); } -// ADD R7,#Offset8 - void thumb37(u32 opcode) { ADD_RN_O8(7); } - -// SUB R0,#Offset8 - void thumb38(u32 opcode) { SUB_RN_O8(0); } -// SUB R1,#Offset8 - void thumb39(u32 opcode) { SUB_RN_O8(1); } -// SUB R2,#Offset8 - void thumb3A(u32 opcode) { SUB_RN_O8(2); } -// SUB R3,#Offset8 - void thumb3B(u32 opcode) { SUB_RN_O8(3); } -// SUB R4,#Offset8 - void thumb3C(u32 opcode) { SUB_RN_O8(4); } -// SUB R5,#Offset8 - void thumb3D(u32 opcode) { SUB_RN_O8(5); } -// SUB R6,#Offset8 - void thumb3E(u32 opcode) { SUB_RN_O8(6); } -// SUB R7,#Offset8 - void thumb3F(u32 opcode) { SUB_RN_O8(7); } - -// ALU operations ///////////////////////////////////////////////////////// - -// AND Rd, Rs - void thumb40_0(u32 opcode) -{ - int dest = opcode & 7; - u32 val = (bus.reg[dest].I & bus.reg[(opcode >> 3)&7].I); - - //bus.reg[dest].I &= bus.reg[(opcode >> 3)&7].I; - N_FLAG = val & 0x80000000 ? true : false; - Z_FLAG = val ? false : true; - - bus.reg[dest].I = val; - -} - -// EOR Rd, Rs - void thumb40_1(u32 opcode) -{ - int dest = opcode & 7; - bus.reg[dest].I ^= bus.reg[(opcode >> 3)&7].I; - N_FLAG = bus.reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = bus.reg[dest].I ? false : true; -} - -// LSL Rd, Rs - void thumb40_2(u32 opcode) -{ - int dest = opcode & 7; - u32 value = bus.reg[(opcode >> 3)&7].B.B0; - u32 val = value; - if(val) { - if(val == 32) { - value = 0; - C_FLAG = (bus.reg[dest].I & 1 ? true : false); - } else if(val < 32) { - LSL_RD_RS; - } else { - value = 0; - C_FLAG = false; - } - bus.reg[dest].I = value; - } - N_FLAG = bus.reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = bus.reg[dest].I ? false : true; - clockTicks = codeTicksAccess(bus.armNextPC, BITS_16)+2; -} - -// LSR Rd, Rs - void thumb40_3(u32 opcode) -{ - int dest = opcode & 7; - u32 value = bus.reg[(opcode >> 3)&7].B.B0; - u32 val = value; - if(val) { - if(val == 32) { - value = 0; - C_FLAG = (bus.reg[dest].I & 0x80000000 ? true : false); - } else if(val < 32) { - LSR_RD_RS; - } else { - value = 0; - C_FLAG = false; - } - bus.reg[dest].I = value; - } - N_FLAG = bus.reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = bus.reg[dest].I ? false : true; - clockTicks = codeTicksAccess(bus.armNextPC, BITS_16)+2; -} - -// ASR Rd, Rs - void thumb41_0(u32 opcode) -{ - int dest = opcode & 7; - u32 value = bus.reg[(opcode >> 3)&7].B.B0; - - if(value) { - if(value < 32) { - ASR_RD_RS; - bus.reg[dest].I = value; - } else { - if(bus.reg[dest].I & 0x80000000){ - bus.reg[dest].I = 0xFFFFFFFF; - C_FLAG = true; - } else { - bus.reg[dest].I = 0x00000000; - C_FLAG = false; - } - } - } - N_FLAG = bus.reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = bus.reg[dest].I ? false : true; - clockTicks = codeTicksAccess(bus.armNextPC, BITS_16)+2; -} - -// ADC Rd, Rs - void thumb41_1(u32 opcode) -{ - int dest = opcode & 0x07; - u32 value = bus.reg[(opcode >> 3)&7].I; - ADC_RD_RS; -} - -// SBC Rd, Rs - void thumb41_2(u32 opcode) -{ - int dest = opcode & 0x07; - u32 value = bus.reg[(opcode >> 3)&7].I; - SBC_RD_RS; -} - -// ROR Rd, Rs - void thumb41_3(u32 opcode) -{ - int dest = opcode & 7; - u32 value = bus.reg[(opcode >> 3)&7].B.B0; - u32 val = value; - if(val) { - value = value & 0x1f; - if(val == 0) { - C_FLAG = (bus.reg[dest].I & 0x80000000 ? true : false); - } else { - ROR_RD_RS; - bus.reg[dest].I = value; - } - } - clockTicks = codeTicksAccess(bus.armNextPC, BITS_16)+2; - N_FLAG = bus.reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = bus.reg[dest].I ? false : true; -} - -// TST Rd, Rs - void thumb42_0(u32 opcode) -{ - u32 value = bus.reg[opcode & 7].I & bus.reg[(opcode >> 3) & 7].I; - N_FLAG = value & 0x80000000 ? true : false; - Z_FLAG = value ? false : true; -} - -// NEG Rd, Rs - void thumb42_1(u32 opcode) -{ - int dest = opcode & 7; - int source = (opcode >> 3) & 7; - NEG_RD_RS; -} - -// CMP Rd, Rs - void thumb42_2(u32 opcode) -{ - int dest = opcode & 7; - u32 value = bus.reg[(opcode >> 3)&7].I; - CMP_RD_RS; -} - -// CMN Rd, Rs - void thumb42_3(u32 opcode) -{ - int dest = opcode & 7; - u32 value = bus.reg[(opcode >> 3)&7].I; - CMN_RD_RS; -} - -// ORR Rd, Rs - void thumb43_0(u32 opcode) -{ - int dest = opcode & 7; - bus.reg[dest].I |= bus.reg[(opcode >> 3) & 7].I; - Z_FLAG = bus.reg[dest].I ? false : true; - N_FLAG = bus.reg[dest].I & 0x80000000 ? true : false; -} - -// MUL Rd, Rs - void thumb43_1(u32 opcode) -{ - clockTicks = 1; - int dest = opcode & 7; - u32 rm = bus.reg[dest].I; - bus.reg[dest].I = bus.reg[(opcode >> 3) & 7].I * rm; - if (((s32)rm) < 0) - rm = ~rm; - if ((rm & 0xFFFF0000) == 0) - clockTicks += 1; - else if ((rm & 0xFF000000) == 0) - clockTicks += 2; - else - clockTicks += 3; - bus.busPrefetchCount = (bus.busPrefetchCount<>(8-clockTicks)); - clockTicks += codeTicksAccess(bus.armNextPC, BITS_16) + 1; - Z_FLAG = bus.reg[dest].I ? false : true; - N_FLAG = bus.reg[dest].I & 0x80000000 ? true : false; -} - -// BIC Rd, Rs - void thumb43_2(u32 opcode) -{ - int dest = opcode & 7; - bus.reg[dest].I &= (~bus.reg[(opcode >> 3) & 7].I); - Z_FLAG = bus.reg[dest].I ? false : true; - N_FLAG = bus.reg[dest].I & 0x80000000 ? true : false; -} - -// MVN Rd, Rs - void thumb43_3(u32 opcode) -{ - int dest = opcode & 7; - bus.reg[dest].I = ~bus.reg[(opcode >> 3) & 7].I; - Z_FLAG = bus.reg[dest].I ? false : true; - N_FLAG = bus.reg[dest].I & 0x80000000 ? true : false; -} - -// High-register instructions and BX ////////////////////////////////////// - -// ADD Rd, Hs - void thumb44_1(u32 opcode) -{ - bus.reg[opcode&7].I += bus.reg[((opcode>>3)&7)+8].I; -} - -// ADD Hd, Rs - void thumb44_2(u32 opcode) -{ - bus.reg[(opcode&7)+8].I += bus.reg[(opcode>>3)&7].I; - if((opcode&7) == 7) { - bus.reg[15].I &= 0xFFFFFFFE; - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 2; - THUMB_PREFETCH; - clockTicks = codeTicksAccessSeq16(bus.armNextPC)<<1 - + codeTicksAccess(bus.armNextPC, BITS_16) + 3; - } -} - -// ADD Hd, Hs - void thumb44_3(u32 opcode) -{ - bus.reg[(opcode&7)+8].I += bus.reg[((opcode>>3)&7)+8].I; - if((opcode&7) == 7) { - bus.reg[15].I &= 0xFFFFFFFE; - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 2; - THUMB_PREFETCH; - clockTicks = codeTicksAccessSeq16(bus.armNextPC)<<1 - + codeTicksAccess(bus.armNextPC, BITS_16) + 3; - } -} - -// CMP Rd, Hs - void thumb45_1(u32 opcode) -{ - int dest = opcode & 7; - u32 value = bus.reg[((opcode>>3)&7)+8].I; - CMP_RD_RS; -} - -// CMP Hd, Rs - void thumb45_2(u32 opcode) -{ - int dest = (opcode & 7) + 8; - u32 value = bus.reg[(opcode>>3)&7].I; - CMP_RD_RS; -} - -// CMP Hd, Hs - void thumb45_3(u32 opcode) -{ - int dest = (opcode & 7) + 8; - u32 value = bus.reg[((opcode>>3)&7)+8].I; - CMP_RD_RS; -} - -// MOV Rd, Hs - void thumb46_1(u32 opcode) -{ - bus.reg[opcode&7].I = bus.reg[((opcode>>3)&7)+8].I; -} - -// MOV Hd, Rs - void thumb46_2(u32 opcode) -{ - bus.reg[(opcode&7)+8].I = bus.reg[(opcode>>3)&7].I; - if((opcode&7) == 7) { - bus.reg[15].I &= 0xFFFFFFFE; - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 2; - THUMB_PREFETCH; - clockTicks = codeTicksAccessSeq16(bus.armNextPC)<<1 - + codeTicksAccess(bus.armNextPC, BITS_16) + 3; - } -} - -// MOV Hd, Hs - void thumb46_3(u32 opcode) -{ - bus.reg[(opcode&7)+8].I = bus.reg[((opcode>>3)&7)+8].I; - if((opcode&7) == 7) { - bus.reg[15].I &= 0xFFFFFFFE; - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 2; - THUMB_PREFETCH; - clockTicks = codeTicksAccessSeq16(bus.armNextPC)<<1 - + codeTicksAccess(bus.armNextPC, BITS_16) + 3; - } -} - - -// BX Rs - void thumb47(u32 opcode) -{ - int base = (opcode >> 3) & 15; - bus.busPrefetchCount=0; - bus.reg[15].I = bus.reg[base].I; - if(bus.reg[base].I & 1) { - armState = false; - bus.reg[15].I &= 0xFFFFFFFE; - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 2; - THUMB_PREFETCH; - clockTicks = ((codeTicksAccessSeq16(bus.armNextPC)) << 1) - + codeTicksAccess(bus.armNextPC, BITS_16) + 3; - } else { - armState = true; - bus.reg[15].I &= 0xFFFFFFFC; - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 4; - ARM_PREFETCH; - clockTicks = ((codeTicksAccessSeq32(bus.armNextPC)) << 1) - + codeTicksAccess(bus.armNextPC, BITS_32) + 3; - } -} - -// Load/store instructions //////////////////////////////////////////////// - -// LDR R0~R7,[PC, #Imm] - void thumb48(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = (bus.reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); - // why quick? - // bus.reg[regist].I = CPUReadMemoryQuick(address); - bus.reg[regist].I = CPUReadMemory(address); - bus.busPrefetchCount=0; - int dataticks_value = DATATICKS_ACCESS_32BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = 3 + dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16); -} - -// STR Rd, [Rs, Rn] - void thumb50(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + bus.reg[(opcode>>6)&7].I; - CPUWriteMemory(address, bus.reg[opcode & 7].I); - int dataticks_value = DATATICKS_ACCESS_32BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16) + 2; -} - -// STRH Rd, [Rs, Rn] - void thumb52(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + bus.reg[(opcode>>6)&7].I; - CPUWriteHalfWord(address, bus.reg[opcode&7].W.W0); - int dataticks_value = DATATICKS_ACCESS_16BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16) + 2; -} - -// STRB Rd, [Rs, Rn] - void thumb54(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + bus.reg[(opcode >>6)&7].I; - CPUWriteByte(address, bus.reg[opcode & 7].B.B0); - int dataticks_value = DATATICKS_ACCESS_16BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16) + 2; -} - -// LDSB Rd, [Rs, Rn] - void thumb56(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + bus.reg[(opcode>>6)&7].I; - bus.reg[opcode&7].I = (s8)CPUReadByte(address); - int dataticks_value = DATATICKS_ACCESS_16BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = 3 + dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16); -} - -// LDR Rd, [Rs, Rn] - void thumb58(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + bus.reg[(opcode>>6)&7].I; - bus.reg[opcode&7].I = CPUReadMemory(address); - int dataticks_value = DATATICKS_ACCESS_32BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = 3 + dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16); -} - -// LDRH Rd, [Rs, Rn] - void thumb5A(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + bus.reg[(opcode>>6)&7].I; - bus.reg[opcode&7].I = CPUReadHalfWord(address); - int dataticks_value = DATATICKS_ACCESS_32BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = 3 + dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16); -} - -// LDRB Rd, [Rs, Rn] - void thumb5C(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + bus.reg[(opcode>>6)&7].I; - bus.reg[opcode&7].I = CPUReadByte(address); - int dataticks_value = DATATICKS_ACCESS_16BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = 3 + dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16); -} - -// LDSH Rd, [Rs, Rn] - void thumb5E(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + bus.reg[(opcode>>6)&7].I; - bus.reg[opcode&7].I = (s16)CPUReadHalfWordSigned(address); - int dataticks_value = DATATICKS_ACCESS_16BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = 3 + dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16); -} - -// STR Rd, [Rs, #Imm] - void thumb60(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2); - CPUWriteMemory(address, bus.reg[opcode&7].I); - int dataticks_value = DATATICKS_ACCESS_32BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16) + 2; -} - -// LDR Rd, [Rs, #Imm] - void thumb68(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2); - bus.reg[opcode&7].I = CPUReadMemory(address); - int dataticks_value = DATATICKS_ACCESS_32BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = 3 + dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16); -} - -// STRB Rd, [Rs, #Imm] - void thumb70(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + (((opcode>>6)&31)); - CPUWriteByte(address, bus.reg[opcode&7].B.B0); - int dataticks_value = DATATICKS_ACCESS_16BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16) + 2; -} - -// LDRB Rd, [Rs, #Imm] - void thumb78(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + (((opcode>>6)&31)); - bus.reg[opcode&7].I = CPUReadByte(address); - int dataticks_value = DATATICKS_ACCESS_16BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = 3 + dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16); -} - -// STRH Rd, [Rs, #Imm] - void thumb80(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1); - CPUWriteHalfWord(address, bus.reg[opcode&7].W.W0); - int dataticks_value = DATATICKS_ACCESS_16BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16) + 2; -} - -// LDRH Rd, [Rs, #Imm] - void thumb88(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1); - bus.reg[opcode&7].I = CPUReadHalfWord(address); - int dataticks_value = DATATICKS_ACCESS_16BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = 3 + dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16); -} - -// STR R0~R7, [SP, #Imm] - void thumb90(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[13].I + ((opcode&255)<<2); - CPUWriteMemory(address, bus.reg[regist].I); - int dataticks_value = DATATICKS_ACCESS_32BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16) + 2; -} - -// LDR R0~R7, [SP, #Imm] - void thumb98(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[13].I + ((opcode&255)<<2); - // why quick? - // bus.reg[regist].I = CPUReadMemoryQuick(address); - bus.reg[regist].I = CPUReadMemory(address); - int dataticks_value = DATATICKS_ACCESS_32BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks = 3 + dataticks_value + codeTicksAccess(bus.armNextPC, BITS_16); -} - -// PC/stack-related /////////////////////////////////////////////////////// - -// ADD R0~R7, PC, Imm - void thumbA0(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - bus.reg[regist].I = (bus.reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); -} - -// ADD R0~R7, SP, Imm - void thumbA8(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - bus.reg[regist].I = bus.reg[13].I + ((opcode&255)<<2); -} - -// ADD SP, Imm - void thumbB0(u32 opcode) -{ - int offset = (opcode & 127) << 2; - if(opcode & 0x80) - offset = -offset; - bus.reg[13].I += offset; -} - -// Push and pop /////////////////////////////////////////////////////////// - -#define PUSH_REG(val, r) \ - if (opcode & (val)) { \ - CPUWriteMemory(address, bus.reg[(r)].I); \ - int dataticks_value = count ? DATATICKS_ACCESS_32BIT_SEQ(address) : DATATICKS_ACCESS_32BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); \ - clockTicks += 1 + dataticks_value; \ - count++; \ - address += 4; \ - } - -#define POP_REG(val, r) \ - if (opcode & (val)) { \ - bus.reg[(r)].I = CPUReadMemory(address); \ -int dataticks_value = count ? DATATICKS_ACCESS_32BIT_SEQ(address) : DATATICKS_ACCESS_32BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); \ - clockTicks += 1 + dataticks_value; \ - count++; \ - address += 4; \ - } - -// PUSH {Rlist} - void thumbB4(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int count = 0; - u32 temp = bus.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 + codeTicksAccess(bus.armNextPC, BITS_16); - bus.reg[13].I = temp; -} - -// PUSH {Rlist, LR} - void thumbB5(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int count = 0; - u32 temp = bus.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 + codeTicksAccess(bus.armNextPC, BITS_16); - bus.reg[13].I = temp; -} - -// POP {Rlist} - void thumbBC(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int count = 0; - u32 address = bus.reg[13].I & 0xFFFFFFFC; - u32 temp = bus.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); - bus.reg[13].I = temp; - clockTicks = 2 + codeTicksAccess(bus.armNextPC, BITS_16); -} - -// POP {Rlist, PC} - void thumbBD(u32 opcode) -{ - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - int count = 0; - u32 address = bus.reg[13].I & 0xFFFFFFFC; - u32 temp = bus.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); - bus.reg[15].I = (CPUReadMemory(address) & 0xFFFFFFFE); - int dataticks_value = count ? DATATICKS_ACCESS_32BIT_SEQ(address) : DATATICKS_ACCESS_32BIT(address); - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_value); - clockTicks += 1 + dataticks_value; - count++; - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 2; - bus.reg[13].I = temp; - THUMB_PREFETCH; - bus.busPrefetchCount = 0; - clockTicks += 3 + ((codeTicksAccess(bus.armNextPC, BITS_16)) << 1); -} - -// Load/store multiple //////////////////////////////////////////////////// - -#define THUMB_STM_REG(val,r,b) \ - if(opcode & (val)) { \ - CPUWriteMemory(address, bus.reg[(r)].I); \ - bus.reg[(b)].I = temp; \ - int dataticks_val = count ? DATATICKS_ACCESS_32BIT_SEQ(address) : DATATICKS_ACCESS_32BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_val); \ - clockTicks += 1 + dataticks_val; \ - count++; \ - address += 4; \ - } - -#define THUMB_LDM_REG(val,r) \ - if(opcode & (val)) { \ - bus.reg[(r)].I = CPUReadMemory(address); \ - int dataticks_val = count ? DATATICKS_ACCESS_32BIT_SEQ(address) : DATATICKS_ACCESS_32BIT(address); \ - DATATICKS_ACCESS_BUS_PREFETCH(address, dataticks_val); \ - clockTicks += 1 + dataticks_val; \ - count++; \ - address += 4; \ - } - -// STM R0~7!, {Rlist} - void thumbC0(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[regist].I & 0xFFFFFFFC; - u32 temp = bus.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 + codeTicksAccess(bus.armNextPC, BITS_16); -} - -// LDM R0~R7!, {Rlist} - void thumbC8(u32 opcode) -{ - u8 regist = (opcode >> 8) & 7; - if (bus.busPrefetchCount == 0) - bus.busPrefetch = bus.busPrefetchEnable; - u32 address = bus.reg[regist].I & 0xFFFFFFFC; - u32 temp = bus.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 + codeTicksAccess(bus.armNextPC, BITS_16); - if(!(opcode & (1<*thumbInsnTable[opcode>>6])(opcode); - - ct = clockTicks; - - if (ct < 0) - return 0; - - /// better pipelining - if (ct==0) - clockTicks = codeTicksAccessSeq16(oldArmNextPC) + 1; - - cpuTotalTicks += clockTicks; - -} while ((cpuTotalTicks < cpuNextEvent) & ~armState & ~holdState); - return 1; -} - - -/*============================================================ - GBA GFX -============================================================ */ - -#ifdef TILED_RENDERING -#ifdef _MSC_VER -union u8h -{ - __pragma( pack(push, 1)); - struct -#ifdef LSB_FIRST - { - /* 0*/ unsigned char lo:4; - /* 4*/ unsigned char hi:4; -#else - { - /* 4*/ unsigned char hi:4; - /* 0*/ unsigned char lo:4; -#endif - } - __pragma(pack(pop)); - u8 val; -}; -#else -union u8h -{ - struct -#ifdef LSB_FIRST - { - /* 0*/ unsigned char lo:4; - /* 4*/ unsigned char hi:4; -#else - { - /* 4*/ unsigned char hi:4; - /* 0*/ unsigned char lo:4; -#endif - } __attribute__ ((packed)); - u8 val; -}; -#endif - -union TileEntry -{ -#ifdef LSB_FIRST - struct - { - /* 0*/ unsigned tileNum:10; - /*12*/ unsigned hFlip:1; - /*13*/ unsigned vFlip:1; - /*14*/ unsigned palette:4; - }; -#else - struct - { - /*14*/ unsigned palette:4; - /*13*/ unsigned vFlip:1; - /*12*/ unsigned hFlip:1; - /* 0*/ unsigned tileNum:10; - }; -#endif - u16 val; -}; - -struct TileLine -{ - u32 pixels[8]; -}; - -typedef const TileLine (*TileReader) (const u16 *, const int, const u8 *, u16 *, const u32); - -static inline void gfxDrawPixel(u32 *dest, const u8 color, const u16 *palette, const u32 prio) -{ - *dest = color ? (READ16LE(&palette[color]) | prio): 0x80000000; -} - -static inline const TileLine gfxReadTile(const u16 *screenSource, const int yyy, const u8 *charBase, u16 *palette, const u32 prio) -{ - TileEntry tile; - tile.val = READ16LE(screenSource); - - int tileY = yyy & 7; - if (tile.vFlip) tileY = 7 - tileY; - TileLine tileLine; - - const u8 *tileBase = &charBase[tile.tileNum * 64 + tileY * 8]; - - if (!tile.hFlip) - { - gfxDrawPixel(&tileLine.pixels[0], tileBase[0], palette, prio); - gfxDrawPixel(&tileLine.pixels[1], tileBase[1], palette, prio); - gfxDrawPixel(&tileLine.pixels[2], tileBase[2], palette, prio); - gfxDrawPixel(&tileLine.pixels[3], tileBase[3], palette, prio); - gfxDrawPixel(&tileLine.pixels[4], tileBase[4], palette, prio); - gfxDrawPixel(&tileLine.pixels[5], tileBase[5], palette, prio); - gfxDrawPixel(&tileLine.pixels[6], tileBase[6], palette, prio); - gfxDrawPixel(&tileLine.pixels[7], tileBase[7], palette, prio); - } - else - { - gfxDrawPixel(&tileLine.pixels[0], tileBase[7], palette, prio); - gfxDrawPixel(&tileLine.pixels[1], tileBase[6], palette, prio); - gfxDrawPixel(&tileLine.pixels[2], tileBase[5], palette, prio); - gfxDrawPixel(&tileLine.pixels[3], tileBase[4], palette, prio); - gfxDrawPixel(&tileLine.pixels[4], tileBase[3], palette, prio); - gfxDrawPixel(&tileLine.pixels[5], tileBase[2], palette, prio); - gfxDrawPixel(&tileLine.pixels[6], tileBase[1], palette, prio); - gfxDrawPixel(&tileLine.pixels[7], tileBase[0], palette, prio); - } - - return tileLine; -} - -static inline const TileLine gfxReadTilePal(const u16 *screenSource, const int yyy, const u8 *charBase, u16 *palette, const u32 prio) -{ - TileEntry tile; - tile.val = READ16LE(screenSource); - - int tileY = yyy & 7; - if (tile.vFlip) tileY = 7 - tileY; - palette += tile.palette * 16; - TileLine tileLine; - - const u8h *tileBase = (u8h*) &charBase[tile.tileNum * 32 + tileY * 4]; - - if (!tile.hFlip) - { - gfxDrawPixel(&tileLine.pixels[0], tileBase[0].lo, palette, prio); - gfxDrawPixel(&tileLine.pixels[1], tileBase[0].hi, palette, prio); - gfxDrawPixel(&tileLine.pixels[2], tileBase[1].lo, palette, prio); - gfxDrawPixel(&tileLine.pixels[3], tileBase[1].hi, palette, prio); - gfxDrawPixel(&tileLine.pixels[4], tileBase[2].lo, palette, prio); - gfxDrawPixel(&tileLine.pixels[5], tileBase[2].hi, palette, prio); - gfxDrawPixel(&tileLine.pixels[6], tileBase[3].lo, palette, prio); - gfxDrawPixel(&tileLine.pixels[7], tileBase[3].hi, palette, prio); - } - else - { - gfxDrawPixel(&tileLine.pixels[0], tileBase[3].hi, palette, prio); - gfxDrawPixel(&tileLine.pixels[1], tileBase[3].lo, palette, prio); - gfxDrawPixel(&tileLine.pixels[2], tileBase[2].hi, palette, prio); - gfxDrawPixel(&tileLine.pixels[3], tileBase[2].lo, palette, prio); - gfxDrawPixel(&tileLine.pixels[4], tileBase[1].hi, palette, prio); - gfxDrawPixel(&tileLine.pixels[5], tileBase[1].lo, palette, prio); - gfxDrawPixel(&tileLine.pixels[6], tileBase[0].hi, palette, prio); - gfxDrawPixel(&tileLine.pixels[7], tileBase[0].lo, palette, prio); - } - - return tileLine; -} - -static inline void gfxDrawTile(const TileLine &tileLine, u32 *line) -{ - memcpy(line, tileLine.pixels, sizeof(tileLine.pixels)); -} - -static inline void gfxDrawTileClipped(const TileLine &tileLine, u32 *line, const int start, int w) -{ - memcpy(line, tileLine.pixels + start, w * sizeof(u32)); -} - -template -void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs, - u32 *line) -{ - u16 *palette = (u16 *)graphics.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 + io_registers[REG_VCOUNT]) & maskY; - int mosaicX = (MOSAIC & 0x000F)+1; - int mosaicY = ((MOSAIC & 0x00F0)>>4)+1; - - if (mosaicOn) - { - if ((io_registers[REG_VCOUNT] % mosaicY) != 0) - { - mosaicY = io_registers[REG_VCOUNT] - (io_registers[REG_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); - - u16 *screenSource = screenBase + 0x400 * (xxx>>8) + ((xxx & 255)>>3) + yshift; - int x = 0; - const int firstTileX = xxx & 7; - - // First tile, if clipped - if (firstTileX) - { - gfxDrawTileClipped(readTile(screenSource, yyy, charBase, palette, prio), &line[x], firstTileX, 8 - firstTileX); - screenSource++; - x += 8 - firstTileX; - xxx += 8 - firstTileX; - - if (xxx == 256 && sizeX > 256) - { - screenSource = screenBase + 0x400 + yshift; - } - else if (xxx >= sizeX) - { - xxx = 0; - screenSource = screenBase + yshift; - } - } - - // Middle tiles, full - while (x < 240 - firstTileX) - { - gfxDrawTile(readTile(screenSource, yyy, charBase, palette, prio), &line[x]); - screenSource++; - xxx += 8; - x += 8; - - if (xxx == 256 && sizeX > 256) - { - screenSource = screenBase + 0x400 + yshift; - } - else if (xxx >= sizeX) - { - xxx = 0; - screenSource = screenBase + yshift; - } - } - - // Last tile, if clipped - if (firstTileX) - { - gfxDrawTileClipped(readTile(screenSource, yyy, charBase, palette, prio), &line[x], 0, firstTileX); - } - - 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++; - } - } - } - } -} - -void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs, u32 *line) -{ - if (control & 0x80) // 1 pal / 256 col - gfxDrawTextScreen(control, hofs, vofs, line); - else // 16 pal / 16 col - gfxDrawTextScreen(control, hofs, vofs, line); -} -#else -inline void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs, - u32 *line) -{ - u16 *palette = (u16 *)graphics.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 + io_registers[REG_VCOUNT]) & maskY; - int mosaicX = (MOSAIC & 0x000F)+1; - int mosaicY = ((MOSAIC & 0x00F0)>>4)+1; - - if(mosaicOn) { - if((io_registers[REG_VCOUNT] % mosaicY) != 0) { - mosaicY = io_registers[REG_VCOUNT] - (io_registers[REG_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++; - } - } - } - } -} -#endif - -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 *)graphics.paletteRAM; - u8 *charBase = &vram[((control >> 2) & 0x03) << 14]; - u8 *screenBase = (u8 *)&vram[((control >> 8) & 0x1f) << 11]; - int prio = ((control & 3) << 25) + 0x1000000; - - u32 map_size = (control >> 14) & 3; - u32 sizeX = map_sizes_rot[map_size]; - u32 sizeY = map_sizes_rot[map_size]; - - int maskX = sizeX-1; - int maskY = sizeY-1; - - int yshift = ((control >> 14) & 3)+4; - -#ifdef BRANCHLESS_GBA_GFX - int dx = pa & 0x7FFF; - int dmx = pb & 0x7FFF; - int dy = pc & 0x7FFF; - int dmy = pd & 0x7FFF; - - dx |= isel(-(pa & 0x8000), 0, 0xFFFF8000); - - dmx |= isel(-(pb & 0x8000), 0, 0xFFFF8000); - - dy |= isel(-(pc & 0x8000), 0, 0xFFFF8000); - - dmy |= isel(-(pd & 0x8000), 0, 0xFFFF8000); -#else - 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; -#endif - - if(io_registers[REG_VCOUNT] == 0) - changed = 3; - - currentX += dmx; - currentY += dmy; - - if(changed & 1) - { - currentX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - currentX |= 0xF8000000; - } - - if(changed & 2) - { - currentY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - currentY |= 0xF8000000; - } - - int realX = currentX; - int realY = currentY; - - if(control & 0x40) - { - int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; - int y = (io_registers[REG_VCOUNT] % mosaicY); - realX -= y*dmx; - realY -= y*dmy; - } - - memset(line, -1, 240 * sizeof(u32)); - if(control & 0x2000) - { - for(u32 x = 0; x < 240u; ++x) - { - int xxx = (realX >> 8) & maskX; - int yyy = (realY >> 8) & maskY; - - int tile = screenBase[(xxx>>3) + ((yyy>>3)<> 8); - unsigned yyy = (realY >> 8); - - if(xxx < sizeX && yyy < sizeY) - { - int tile = screenBase[(xxx>>3) + ((yyy>>3)< 1) - { - int m = 1; - for(u32 i = 0; i < 239u; ++i) - { - line[i+1] = line[i]; - if(++m == mosaicX) - { - m = 1; - ++i; - } - } - } - } -} - -INLINE void gfxDrawRotScreen16Bit( int& currentX, int& currentY, int changed) -{ - u16 *screenBase = (u16 *)&vram[0]; - int prio = ((io_registers[REG_BG2CNT] & 3) << 25) + 0x1000000; - - u32 sizeX = 240; - u32 sizeY = 160; - - int startX = (BG2X_L) | ((BG2X_H & 0x07FF)<<16); - if(BG2X_H & 0x0800) - startX |= 0xF8000000; - int startY = (BG2Y_L) | ((BG2Y_H & 0x07FF)<<16); - if(BG2Y_H & 0x0800) - startY |= 0xF8000000; - -#ifdef BRANCHLESS_GBA_GFX - int dx = io_registers[REG_BG2PA] & 0x7FFF; - dx |= isel(-(io_registers[REG_BG2PA] & 0x8000), 0, 0xFFFF8000); - - int dmx = io_registers[REG_BG2PB] & 0x7FFF; - dmx |= isel(-(io_registers[REG_BG2PB] & 0x8000), 0, 0xFFFF8000); - - int dy = io_registers[REG_BG2PC] & 0x7FFF; - dy |= isel(-(io_registers[REG_BG2PC] & 0x8000), 0, 0xFFFF8000); - - int dmy = io_registers[REG_BG2PD] & 0x7FFF; - dmy |= isel(-(io_registers[REG_BG2PD] & 0x8000), 0, 0xFFFF8000); -#else - int dx = io_registers[REG_BG2PA] & 0x7FFF; - if(io_registers[REG_BG2PA] & 0x8000) - dx |= 0xFFFF8000; - int dmx = io_registers[REG_BG2PB] & 0x7FFF; - if(io_registers[REG_BG2PB] & 0x8000) - dmx |= 0xFFFF8000; - int dy = io_registers[REG_BG2PC] & 0x7FFF; - if(io_registers[REG_BG2PC] & 0x8000) - dy |= 0xFFFF8000; - int dmy = io_registers[REG_BG2PD] & 0x7FFF; - if(io_registers[REG_BG2PD] & 0x8000) - dmy |= 0xFFFF8000; -#endif - - if(io_registers[REG_VCOUNT] == 0) - changed = 3; - - currentX += dmx; - currentY += dmy; - - if(changed & 1) - { - currentX = (BG2X_L) | ((BG2X_H & 0x07FF)<<16); - if(BG2X_H & 0x0800) - currentX |= 0xF8000000; - } - - if(changed & 2) - { - currentY = (BG2Y_L) | ((BG2Y_H & 0x07FF)<<16); - if(BG2Y_H & 0x0800) - currentY |= 0xF8000000; - } - - int realX = currentX; - int realY = currentY; - - if(io_registers[REG_BG2CNT] & 0x40) { - int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; - int y = (io_registers[REG_VCOUNT] % mosaicY); - realX -= y*dmx; - realY -= y*dmy; - } - - unsigned xxx = (realX >> 8); - unsigned yyy = (realY >> 8); - - memset(line[2], -1, 240 * sizeof(u32)); - for(u32 x = 0; x < 240u; ++x) - { - if(xxx < sizeX && yyy < sizeY) - line[2][x] = (READ16LE(&screenBase[yyy * sizeX + xxx]) | prio); - - realX += dx; - realY += dy; - - xxx = (realX >> 8); - yyy = (realY >> 8); - } - - if(io_registers[REG_BG2CNT] & 0x40) { - int mosaicX = (MOSAIC & 0xF) + 1; - if(mosaicX > 1) { - int m = 1; - for(u32 i = 0; i < 239u; ++i) - { - line[2][i+1] = line[2][i]; - if(++m == mosaicX) - { - m = 1; - ++i; - } - } - } - } -} - -INLINE void gfxDrawRotScreen256(int ¤tX, int& currentY, int changed) -{ - u16 *palette = (u16 *)graphics.paletteRAM; - u8 *screenBase = (io_registers[REG_DISPCNT] & 0x0010) ? &vram[0xA000] : &vram[0x0000]; - int prio = ((io_registers[REG_BG2CNT] & 3) << 25) + 0x1000000; - u32 sizeX = 240; - u32 sizeY = 160; - - int startX = (BG2X_L) | ((BG2X_H & 0x07FF)<<16); - if(BG2X_H & 0x0800) - startX |= 0xF8000000; - int startY = (BG2Y_L) | ((BG2Y_H & 0x07FF)<<16); - if(BG2Y_H & 0x0800) - startY |= 0xF8000000; - -#ifdef BRANCHLESS_GBA_GFX - int dx = io_registers[REG_BG2PA] & 0x7FFF; - dx |= isel(-(io_registers[REG_BG2PA] & 0x8000), 0, 0xFFFF8000); - - int dmx = io_registers[REG_BG2PB] & 0x7FFF; - dmx |= isel(-(io_registers[REG_BG2PB] & 0x8000), 0, 0xFFFF8000); - - int dy = io_registers[REG_BG2PC] & 0x7FFF; - dy |= isel(-(io_registers[REG_BG2PC] & 0x8000), 0, 0xFFFF8000); - - int dmy = io_registers[REG_BG2PD] & 0x7FFF; - dmy |= isel(-(io_registers[REG_BG2PD] & 0x8000), 0, 0xFFFF8000); -#else - int dx = io_registers[REG_BG2PA] & 0x7FFF; - if(io_registers[REG_BG2PA] & 0x8000) - dx |= 0xFFFF8000; - int dmx = io_registers[REG_BG2PB] & 0x7FFF; - if(io_registers[REG_BG2PB] & 0x8000) - dmx |= 0xFFFF8000; - int dy = io_registers[REG_BG2PC] & 0x7FFF; - if(io_registers[REG_BG2PC] & 0x8000) - dy |= 0xFFFF8000; - int dmy = io_registers[REG_BG2PD] & 0x7FFF; - if(io_registers[REG_BG2PD] & 0x8000) - dmy |= 0xFFFF8000; -#endif - - if(io_registers[REG_VCOUNT] == 0) - changed = 3; - - currentX += dmx; - currentY += dmy; - - if(changed & 1) - { - currentX = (BG2X_L) | ((BG2X_H & 0x07FF)<<16); - if(BG2X_H & 0x0800) - currentX |= 0xF8000000; - } - - if(changed & 2) - { - currentY = (BG2Y_L) | ((BG2Y_H & 0x07FF)<<16); - if(BG2Y_H & 0x0800) - currentY |= 0xF8000000; - } - - int realX = currentX; - int realY = currentY; - - if(io_registers[REG_BG2CNT] & 0x40) { - int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; - int y = io_registers[REG_VCOUNT] - (io_registers[REG_VCOUNT] % mosaicY); - realX = startX + y*dmx; - realY = startY + y*dmy; - } - - int xxx = (realX >> 8); - int yyy = (realY >> 8); - - memset(line[2], -1, 240 * sizeof(u32)); - for(u32 x = 0; x < 240; ++x) - { - u8 color = screenBase[yyy * 240 + xxx]; - if(unsigned(xxx) < sizeX && unsigned(yyy) < sizeY && color) - line[2][x] = (READ16LE(&palette[color])|prio); - realX += dx; - realY += dy; - - xxx = (realX >> 8); - yyy = (realY >> 8); - } - - if(io_registers[REG_BG2CNT] & 0x40) - { - int mosaicX = (MOSAIC & 0xF) + 1; - if(mosaicX > 1) - { - int m = 1; - for(u32 i = 0; i < 239u; ++i) - { - line[2][i+1] = line[2][i]; - if(++m == mosaicX) - { - m = 1; - ++i; - } - } - } - } -} - -INLINE void gfxDrawRotScreen16Bit160(int& currentX, int& currentY, int changed) -{ - u16 *screenBase = (io_registers[REG_DISPCNT] & 0x0010) ? (u16 *)&vram[0xa000] : - (u16 *)&vram[0]; - int prio = ((io_registers[REG_BG2CNT] & 3) << 25) + 0x1000000; - u32 sizeX = 160; - u32 sizeY = 128; - - int startX = (BG2X_L) | ((BG2X_H & 0x07FF)<<16); - if(BG2X_H & 0x0800) - startX |= 0xF8000000; - int startY = (BG2Y_L) | ((BG2Y_H & 0x07FF)<<16); - if(BG2Y_H & 0x0800) - startY |= 0xF8000000; - -#ifdef BRANCHLESS_GBA_GFX - int dx = io_registers[REG_BG2PA] & 0x7FFF; - dx |= isel(-(io_registers[REG_BG2PA] & 0x8000), 0, 0xFFFF8000); - - int dmx = io_registers[REG_BG2PB] & 0x7FFF; - dmx |= isel(-(io_registers[REG_BG2PB] & 0x8000), 0, 0xFFFF8000); - - int dy = io_registers[REG_BG2PC] & 0x7FFF; - dy |= isel(-(io_registers[REG_BG2PC] & 0x8000), 0, 0xFFFF8000); - - int dmy = io_registers[REG_BG2PD] & 0x7FFF; - dmy |= isel(-(io_registers[REG_BG2PD] & 0x8000), 0, 0xFFFF8000); -#else - int dx = io_registers[REG_BG2PA] & 0x7FFF; - if(io_registers[REG_BG2PA] & 0x8000) - dx |= 0xFFFF8000; - int dmx = io_registers[REG_BG2PB] & 0x7FFF; - if(io_registers[REG_BG2PB] & 0x8000) - dmx |= 0xFFFF8000; - int dy = io_registers[REG_BG2PC] & 0x7FFF; - if(io_registers[REG_BG2PC] & 0x8000) - dy |= 0xFFFF8000; - int dmy = io_registers[REG_BG2PD] & 0x7FFF; - if(io_registers[REG_BG2PD] & 0x8000) - dmy |= 0xFFFF8000; -#endif - - if(io_registers[REG_VCOUNT] == 0) - changed = 3; - - currentX += dmx; - currentY += dmy; - - if(changed & 1) - { - currentX = (BG2X_L) | ((BG2X_H & 0x07FF)<<16); - if(BG2X_H & 0x0800) - currentX |= 0xF8000000; - } - - if(changed & 2) - { - currentY = (BG2Y_L) | ((BG2Y_H & 0x07FF)<<16); - if(BG2Y_H & 0x0800) - currentY |= 0xF8000000; - } - - int realX = currentX; - int realY = currentY; - - if(io_registers[REG_BG2CNT] & 0x40) { - int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; - int y = io_registers[REG_VCOUNT] - (io_registers[REG_VCOUNT] % mosaicY); - realX = startX + y*dmx; - realY = startY + y*dmy; - } - - int xxx = (realX >> 8); - int yyy = (realY >> 8); - - memset(line[2], -1, 240 * sizeof(u32)); - for(u32 x = 0; x < 240u; ++x) - { - if(unsigned(xxx) < sizeX && unsigned(yyy) < sizeY) - line[2][x] = (READ16LE(&screenBase[yyy * sizeX + xxx]) | prio); - - realX += dx; - realY += dy; - - xxx = (realX >> 8); - yyy = (realY >> 8); - } - - - int mosaicX = (MOSAIC & 0xF) + 1; - if(io_registers[REG_BG2CNT] & 0x40 && (mosaicX > 1)) - { - int m = 1; - for(u32 i = 0; i < 239u; ++i) - { - line[2][i+1] = line[2][i]; - if(++m == mosaicX) - { - m = 1; - ++i; - } - } - } -} - -/* 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. */ - -INLINE void gfxDrawSprites (void) -{ - unsigned lineOBJpix, m; - - lineOBJpix = (io_registers[REG_DISPCNT] & 0x20) ? 954 : 1226; - m = 0; - - u16 *sprites = (u16 *)oam; - u16 *spritePalette = &((u16 *)graphics.paletteRAM)[256]; - int mosaicY = ((MOSAIC & 0xF000)>>12) + 1; - int mosaicX = ((MOSAIC & 0xF00)>>8) + 1; - for(u32 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) - return; - - if ((a0 & 0x0c00) == 0x0c00) - a0 &=0xF3FF; - - u16 a0val = a0>>14; - - if (a0val == 3) - { - a0 &= 0x3FFF; - a1 &= 0x3FFF; - } - - u32 sizeX = 8<<(a1>>14); - u32 sizeY = sizeX; - - - if (a0val & 1) - { -#ifdef BRANCHLESS_GBA_GFX - sizeX <<= isel(-(sizeX & (~31u)), 1, 0); - sizeY >>= isel(-(sizeY>8), 0, 1); -#else - if (sizeX<32) - sizeX<<=1; - if (sizeY>8) - sizeY>>=1; -#endif - } - else if (a0val & 2) - { -#ifdef BRANCHLESS_GBA_GFX - sizeX >>= isel(-(sizeX>8), 0, 1); - sizeY <<= isel(-(sizeY & (~31u)), 1, 0); -#else - if (sizeX>8) - sizeX>>=1; - if (sizeY<32) - 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) && (graphics.layerEnable & 0x8000)) - { - if ((a0 & 0x0300) == 0x0300) - { - sizeX<<=1; - sizeY<<=1; - } - -#ifdef BRANCHLESS_GBA_GFX - sy -= isel(256 - sy - sizeY, 0, 256); - sx -= isel(512 - sx - sizeX, 0, 512); -#else - if((sy+sizeY) > 256) - sy -= 256; - if ((sx+sizeX)> 512) - sx -= 512; -#endif - - if (sx < 0) - { - sizeX+=sx; - sx = 0; - } - else if ((sx+sizeX)>240) - sizeX=240-sx; - - if ((io_registers[REG_VCOUNT]>=sy) && (io_registers[REG_VCOUNT] 256) - sy -= 256; - int t = io_registers[REG_VCOUNT] - sy; - if(unsigned(t) < fieldY) - { - u32 startpix = 0; - if ((sx+fieldX)> 512) - startpix=512-sx; - - if (lineOBJpix && ((sx < 240) || startpix)) - { - lineOBJpix-=8; - int rot = (((a1 >> 9) & 0x1F) << 4); - u16 *OAM = (u16 *)oam; - int dx = READ16LE(&OAM[3 + rot]); - if(dx & 0x8000) - dx |= 0xFFFF8000; - int dmx = READ16LE(&OAM[7 + rot]); - if(dmx & 0x8000) - dmx |= 0xFFFF8000; - int dy = READ16LE(&OAM[11 + rot]); - if(dy & 0x8000) - dy |= 0xFFFF8000; - int dmy = READ16LE(&OAM[15 + rot]); - if(dmy & 0x8000) - dmy |= 0xFFFF8000; - - if(a0 & 0x1000) - t -= (t % mosaicY); - - int realX = ((sizeX) << 7) - (fieldX >> 1)*dx + ((t - (fieldY>>1))* dmx); - int realY = ((sizeY) << 7) - (fieldX >> 1)*dy + ((t - (fieldY>>1))* dmy); - - u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - - int c = (a2 & 0x3FF); - if((io_registers[REG_DISPCNT] & 7) > 2 && (c < 512)) - continue; - - if(a0 & 0x2000) - { - int inc = 32; - if(io_registers[REG_DISPCNT] & 0x40) - inc = sizeX >> 2; - else - c &= 0x3FE; - for(u32 x = 0; x < fieldX; x++) - { - if (x >= startpix) - lineOBJpix-=2; - unsigned xxx = realX >> 8; - unsigned yyy = realY >> 8; - if(xxx < sizeX && yyy < sizeY && sx < 240) - { - - u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) - + ((yyy & 7)<<3) + ((xxx >> 3)<<6) + (xxx & 7))&0x7FFF)]; - - if ((color==0) && (((prio >> 25)&3) < ((line[4][sx]>>25)&3))) - { - line[4][sx] = (line[4][sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - line[4][sx]=(line[4][sx-1] & 0xF9FFFFFF) | prio; - } - else if((color) && (prio < (line[4][sx]&0xFF000000))) - { - line[4][sx] = READ16LE(&spritePalette[color]) | prio; - if((a0 & 0x1000) && m) - line[4][sx]=(line[4][sx-1] & 0xF9FFFFFF) | prio; - } - - if ((a0 & 0x1000) && ((m+1) == mosaicX)) - m = 0; - } - sx = (sx+1)&511; - realX += dx; - realY += dy; - } - } - else - { - int inc = 32; - if(io_registers[REG_DISPCNT] & 0x40) - inc = sizeX >> 3; - int palette = (a2 >> 8) & 0xF0; - for(u32 x = 0; x < fieldX; ++x) - { - if (x >= startpix) - lineOBJpix-=2; - unsigned xxx = realX >> 8; - unsigned yyy = realY >> 8; - if(xxx < sizeX && yyy < sizeY && sx < 240) - { - - 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) < - ((line[4][sx]>>25)&3))) - { - line[4][sx] = (line[4][sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - line[4][sx]=(line[4][sx-1] & 0xF9FFFFFF) | prio; - } - else if((color) && (prio < (line[4][sx]&0xFF000000))) - { - line[4][sx] = READ16LE(&spritePalette[palette+color]) | prio; - if((a0 & 0x1000) && m) - line[4][sx]=(line[4][sx-1] & 0xF9FFFFFF) | prio; - } - } - if((a0 & 0x1000) && m) - { - if (++m==mosaicX) - m=0; - } - - sx = (sx+1)&511; - realX += dx; - realY += dy; - - } - } - } - } - } - else - { - if(sy+sizeY > 256) - sy -= 256; - int t = io_registers[REG_VCOUNT] - sy; - if(unsigned(t) < sizeY) - { - u32 startpix = 0; - if ((sx+sizeX)> 512) - startpix=512-sx; - - if((sx < 240) || startpix) - { - lineOBJpix+=2; - - if(a1 & 0x2000) - t = sizeY - t - 1; - - int c = (a2 & 0x3FF); - if((io_registers[REG_DISPCNT] & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - int xxx = 0; - if(a1 & 0x1000) - xxx = sizeX-1; - - if(a0 & 0x1000) - t -= (t % mosaicY); - - if(a0 & 0x2000) - { - if(io_registers[REG_DISPCNT] & 0x40) - inc = sizeX >> 2; - else - c &= 0x3FE; - - 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(u32 xx = 0; xx < sizeX; xx++) - { - if (xx >= startpix) - --lineOBJpix; - if(sx < 240) - { - u8 color = vram[address]; - if ((color==0) && (((prio >> 25)&3) < - ((line[4][sx]>>25)&3))) - { - line[4][sx] = (line[4][sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - line[4][sx]=(line[4][sx-1] & 0xF9FFFFFF) | prio; - } - else if((color) && (prio < (line[4][sx]&0xFF000000))) - { - line[4][sx] = READ16LE(&spritePalette[color]) | prio; - if((a0 & 0x1000) && m) - line[4][sx]=(line[4][sx-1] & 0xF9FFFFFF) | prio; - } - - if ((a0 & 0x1000) && ((m+1) == mosaicX)) - m = 0; - } - - sx = (sx+1) & 511; - if(a1 & 0x1000) - { - --address; - if(--xxx == -1) - { - address -= 56; - xxx = 7; - } - if(address < 0x10000) - address += 0x8000; - } - else - { - ++address; - if(++xxx == 8) - { - address += 56; - xxx = 0; - } - if(address > 0x17fff) - address -= 0x8000; - } - } - } - else - { - if(io_registers[REG_DISPCNT] & 0x40) - inc = sizeX >> 3; - - 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; - int xx = sizeX - 1; - do - { - if (xx >= (int)(startpix)) - --lineOBJpix; - //if (lineOBJpix<0) - // continue; - if(sx < 240) - { - u8 color = vram[address]; - if(xx & 1) - color >>= 4; - else - color &= 0x0F; - - if ((color==0) && (((prio >> 25)&3) < - ((line[4][sx]>>25)&3))) - { - line[4][sx] = (line[4][sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - line[4][sx]=(line[4][sx-1] & 0xF9FFFFFF) | prio; - } - else if((color) && (prio < (line[4][sx]&0xFF000000))) - { - line[4][sx] = READ16LE(&spritePalette[palette + color]) | prio; - if((a0 & 0x1000) && m) - line[4][sx]=(line[4][sx-1] & 0xF9FFFFFF) | prio; - } - } - - if ((a0 & 0x1000) && ((m+1) == mosaicX)) - m=0; - - sx = (sx+1) & 511; - if(!(xx & 1)) - --address; - if(--xxx == -1) - { - xxx = 7; - address -= 28; - } - if(address < 0x10000) - address += 0x8000; - }while(--xx >= 0); - } - else - { - for(u32 xx = 0; xx < sizeX; ++xx) - { - if (xx >= startpix) - --lineOBJpix; - //if (lineOBJpix<0) - // continue; - if(sx < 240) - { - u8 color = vram[address]; - if(xx & 1) - color >>= 4; - else - color &= 0x0F; - - if ((color==0) && (((prio >> 25)&3) < - ((line[4][sx]>>25)&3))) - { - line[4][sx] = (line[4][sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - line[4][sx]=(line[4][sx-1] & 0xF9FFFFFF) | prio; - } - else if((color) && (prio < (line[4][sx]&0xFF000000))) - { - line[4][sx] = READ16LE(&spritePalette[palette + color]) | prio; - if((a0 & 0x1000) && m) - line[4][sx]=(line[4][sx-1] & 0xF9FFFFFF) | prio; - - } - } - if ((a0 & 0x1000) && ((m+1) == mosaicX)) - m=0; - - sx = (sx+1) & 511; - if(xx & 1) - ++address; - if(++xxx == 8) - { - address += 28; - xxx = 0; - } - if(address > 0x17fff) - address -= 0x8000; - } - } - } - } - } - } - } -} - -INLINE void gfxDrawOBJWin (void) -{ - u16 *sprites = (u16 *)oam; - 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) - return; - - // ignores non OBJ-WIN and disabled OBJ-WIN - if(((a0 & 0x0c00) != 0x0800) || ((a0 & 0x0300) == 0x0200)) - continue; - - u16 a0val = a0>>14; - - if ((a0 & 0x0c00) == 0x0c00) - a0 &=0xF3FF; - - if (a0val == 3) - { - a0 &= 0x3FFF; - a1 &= 0x3FFF; - } - - int sizeX = 8<<(a1>>14); - int sizeY = sizeX; - - if (a0val & 1) - { -#ifdef BRANCHLESS_GBA_GFX - sizeX <<= isel(-(sizeX & (~31u)), 1, 0); - sizeY >>= isel(-(sizeY>8), 0, 1); -#else - if (sizeX<32) - sizeX<<=1; - if (sizeY>8) - sizeY>>=1; -#endif - } - else if (a0val & 2) - { -#ifdef BRANCHLESS_GBA_GFX - sizeX >>= isel(-(sizeX>8), 0, 1); - sizeY <<= isel(-(sizeY & (~31u)), 1, 0); -#else - if (sizeX>8) - sizeX>>=1; - if (sizeY<32) - sizeY<<=1; -#endif - - } - - 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 = io_registers[REG_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; - - int c = (a2 & 0x3FF); - if((io_registers[REG_DISPCNT] & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - bool condition1 = a0 & 0x2000; - - if(io_registers[REG_DISPCNT] & 0x40) - inc = sizeX >> 3; - - for(int x = 0; x < fieldX; x++) - { - bool cont = true; - 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) - cont = false; - - if(cont) - { - u32 color; - if(condition1) - color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) - + ((yyy & 7)<<3) + ((xxx >> 3)<<6) + - (xxx & 7))&0x7fff)]; - else - { - 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) - line[5][sx] = 1; - } - sx = (sx+1)&511; - realX += dx; - realY += dy; - } - } - } - } - else - { - if((sy+sizeY) > 256) - sy -= 256; - int t = io_registers[REG_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(a1 & 0x2000) - t = sizeY - t - 1; - int c = (a2 & 0x3FF); - if((io_registers[REG_DISPCNT] & 7) > 2 && (c < 512)) - continue; - if(a0 & 0x2000) - { - - int inc = 32; - if(io_registers[REG_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; - for(int xx = 0; xx < sizeX; xx++) - { - if (xx >= startpix) - lineOBJpix--; - if (lineOBJpix<0) - continue; - if(sx < 240) - { - u8 color = vram[address]; - if(color) - line[5][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 - { - int inc = 32; - if(io_registers[REG_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) - line[5][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) - line[5][sx] = 1; - } - sx = (sx+1) & 511; - xxx++; - if(xx & 1) - address++; - if(xxx == 8) { - address += 28; - xxx = 0; - } - if(address > 0x17fff) - address -= 0x8000; - } - } - } - } - } - } - } -} - -INLINE u32 gfxIncreaseBrightness(u32 color, int coeff) -{ - color = (((color & 0xffff) << 16) | (color & 0xffff)) & 0x3E07C1F; - - color += ((((0x3E07C1F - color) * coeff) >> 4) & 0x3E07C1F); - - return (color >> 16) | color; -} - -INLINE u32 gfxDecreaseBrightness(u32 color, int coeff) -{ - color = (((color & 0xffff) << 16) | (color & 0xffff)) & 0x3E07C1F; - - color -= (((color * coeff) >> 4) & 0x3E07C1F); - - return (color >> 16) | color; -} - -#define GFX_ALPHA_BLEND(color, color2, ca, cb) \ - int r = AlphaClampLUT[(((color & 0x1F) * ca) >> 4) + (((color2 & 0x1F) * cb) >> 4)]; \ - int g = AlphaClampLUT[((((color >> 5) & 0x1F) * ca) >> 4) + ((((color2 >> 5) & 0x1F) * cb) >> 4)]; \ - int b = AlphaClampLUT[((((color >> 10) & 0x1F) * ca) >> 4) + ((((color2 >> 10) & 0x1F) * cb) >> 4)]; \ - color = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; - -/*============================================================ - GBA.CPP -============================================================ */ -static const bool useBios = true; -bool skipBios; -// it's a few bytes in the linkscript to make a multiboot image work in normal boot as well, -// and most of the ones i've seen have done that, so this is not terribly useful -static const bool cpuIsMultiBoot = false; -int cpuSaveType; // used only in init() to set up function pointers and for save file determination -bool mirroringEnable; - -int cpuDmaCount; - -uint8_t bios[0x4000]; -uint8_t rom[0x2000000]; -uint8_t internalRAM[0x8000]; -uint8_t workRAM[0x40000]; -uint8_t vram[0x20000]; -u16 pix[2 * PIX_BUFFER_SCREEN_WIDTH * 160]; -uint8_t oam[0x400]; -uint8_t ioMem[0x400]; - -bool cpuEEPROMEnabled; // true to process writes to EEPROM at 0dxxxxxx -bool cpuEEPROMSensorEnabled; // eeprom motion sensor? code is mostly disabled - -#ifndef LSB_FIRST -bool cpuBiosSwapped = false; -#endif - -INLINE int CPUUpdateTicks (void) -{ - int cpuLoopTicks = graphics.lcdTicks; - - if(timer0On && (timer0Ticks < cpuLoopTicks)) - cpuLoopTicks = timer0Ticks; - - if(timer1On && !(io_registers[REG_TM1CNT] & 4) && (timer1Ticks < cpuLoopTicks)) - cpuLoopTicks = timer1Ticks; - - if(timer2On && !(io_registers[REG_TM2CNT] & 4) && (timer2Ticks < cpuLoopTicks)) - cpuLoopTicks = timer2Ticks; - - if(timer3On && !(io_registers[REG_TM3CNT] & 4) && (timer3Ticks < cpuLoopTicks)) - cpuLoopTicks = timer3Ticks; - - if (IRQTicks) - { - if (IRQTicks < cpuLoopTicks) - cpuLoopTicks = IRQTicks; - } - - return cpuLoopTicks; -} - -#define CPUUpdateWindow0() \ -{ \ - int x00_window0 = io_registers[REG_WIN0H] >>8; \ - int x01_window0 = io_registers[REG_WIN0H] & 255; \ - int x00_lte_x01 = x00_window0 <= x01_window0; \ - for(int i = 0; i < 240; i++) \ - gfxInWin[0][i] = ((i >= x00_window0 && i < x01_window0) & x00_lte_x01) | ((i >= x00_window0 || i < x01_window0) & ~x00_lte_x01); \ -} - -#define CPUUpdateWindow1() \ -{ \ - int x00_window1 = io_registers[REG_WIN1H]>>8; \ - int x01_window1 = io_registers[REG_WIN1H] & 255; \ - int x00_lte_x01 = x00_window1 <= x01_window1; \ - for(int i = 0; i < 240; i++) \ - gfxInWin[1][i] = ((i >= x00_window1 && i < x01_window1) & x00_lte_x01) | ((i >= x00_window1 || i < x01_window1) & ~x00_lte_x01); \ -} - -#define CPUCompareVCOUNT() \ - if(io_registers[REG_VCOUNT] == (io_registers[REG_DISPSTAT] >> 8)) \ - { \ - io_registers[REG_DISPSTAT] |= 4; \ - UPDATE_REG(0x04, io_registers[REG_DISPSTAT]); \ - if(io_registers[REG_DISPSTAT] & 0x20) \ - { \ - io_registers[REG_IF] |= 4; \ - UPDATE_REG(0x202, io_registers[REG_IF]); \ - } \ - } \ - else \ - { \ - io_registers[REG_DISPSTAT] &= 0xFFFB; \ - UPDATE_REG(0x4, io_registers[REG_DISPSTAT]); \ - } \ - if (graphics.layerEnableDelay > 0) \ - { \ - graphics.layerEnableDelay--; \ - if (graphics.layerEnableDelay == 1) \ - graphics.layerEnable = io_registers[REG_DISPCNT]; \ - } - -int CPULoadRom(const u8 *romfile, const u32 romfilelen) -{ - if (cpuIsMultiBoot) - { - if (romfilelen > 0x40000) - return 0; - } - else - { - if (romfilelen > 0x2000000) - return 0; - } - - uint8_t *whereToLoad = cpuIsMultiBoot ? workRAM : rom; - - memcpy(whereToLoad, romfile, romfilelen); - romSize = romfilelen; - - uint16_t *temp = (uint16_t *)(rom+((romSize+1)&~1)); - int i; - for(i = (romSize+1)&~1; i < 0x2000000; i+=2) { - WRITE16LE(temp, (i >> 1) & 0xFFFF); - temp++; - } - - - flashInit(); - eepromInit(); - - memset(line[0], -1, 240 * sizeof(u32)); - memset(line[1], -1, 240 * sizeof(u32)); - memset(line[2], -1, 240 * sizeof(u32)); - memset(line[3], -1, 240 * sizeof(u32)); - - return romSize; -} - -void doMirroring (bool b) -{ - uint32_t mirroredRomSize = (((romSize)>>20) & 0x3F)<<20; - uint32_t mirroredRomAddress = romSize; - if ((mirroredRomSize <=0x800000) && (b)) - { - mirroredRomAddress = mirroredRomSize; - if (mirroredRomSize==0) - mirroredRomSize=0x100000; - while (mirroredRomAddress<0x01000000) - { - memcpy((uint16_t *)(rom+mirroredRomAddress), (uint16_t *)(rom), mirroredRomSize); - mirroredRomAddress+=mirroredRomSize; - } - } -} - -#define brightness_switch() \ - switch((BLDMOD >> 6) & 3) \ - { \ - case 2: \ - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); \ - break; \ - case 3: \ - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); \ - break; \ - } - -#define alpha_blend_brightness_switch() \ - if(top2 & (BLDMOD>>8)) \ - if(color < 0x80000000) \ - { \ - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); \ - } \ - else if(BLDMOD & top) \ - { \ - brightness_switch(); \ - } - -/* we only use 16bit color depth */ -#define INIT_COLOR_DEPTH_LINE_MIX() uint16_t * lineMix = (pix + PIX_BUFFER_SCREEN_WIDTH * io_registers[REG_VCOUNT]) - -void mode0RenderLine (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 0: Render Line\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - if(graphics.layerEnable & 0x0100) { - gfxDrawTextScreen(io_registers[REG_BG0CNT], io_registers[REG_BG0HOFS], io_registers[REG_BG0VOFS], line[0]); - } - - if(graphics.layerEnable & 0x0200) { - gfxDrawTextScreen(io_registers[REG_BG1CNT], io_registers[REG_BG1HOFS], io_registers[REG_BG1VOFS], line[1]); - } - - if(graphics.layerEnable & 0x0400) { - gfxDrawTextScreen(io_registers[REG_BG2CNT], io_registers[REG_BG2HOFS], io_registers[REG_BG2VOFS], line[2]); - } - - if(graphics.layerEnable & 0x0800) { - gfxDrawTextScreen(io_registers[REG_BG3CNT], io_registers[REG_BG3HOFS], io_registers[REG_BG3VOFS], line[3]); - } - - - uint32_t backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - uint32_t color = backdrop; - uint8_t top = 0x20; - - if(line[0][x] < color) { - color = line[0][x]; - top = 0x01; - } - - if((uint8_t)(line[1][x]>>24) < (uint8_t)(color >> 24)) { - color = line[1][x]; - top = 0x02; - } - - if((uint8_t)(line[2][x]>>24) < (uint8_t)(color >> 24)) { - color = line[2][x]; - top = 0x04; - } - - if((uint8_t)(line[3][x]>>24) < (uint8_t)(color >> 24)) { - color = line[3][x]; - top = 0x08; - } - - if((uint8_t)(line[4][x]>>24) < (uint8_t)(color >> 24)) { - color = line[4][x]; - top = 0x10; - - if(color & 0x00010000) { - // semi-transparent OBJ - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if((uint8_t)(line[0][x]>>24) < (uint8_t)(back >> 24)) { - back = line[0][x]; - top2 = 0x01; - } - - if((uint8_t)(line[1][x]>>24) < (uint8_t)(back >> 24)) { - back = line[1][x]; - top2 = 0x02; - } - - if((uint8_t)(line[2][x]>>24) < (uint8_t)(back >> 24)) { - back = line[2][x]; - top2 = 0x04; - } - - if((uint8_t)(line[3][x]>>24) < (uint8_t)(back >> 24)) { - back = line[3][x]; - top2 = 0x08; - } - - alpha_blend_brightness_switch(); - } - } - - - lineMix[x] = CONVERT_COLOR(color); - } -} - -void mode0RenderLineNoWindow (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 0: Render Line No Window\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - uint32_t backdrop = (READ16LE(&palette[0]) | 0x30000000); - - if(graphics.layerEnable & 0x0100) { - gfxDrawTextScreen(io_registers[REG_BG0CNT], io_registers[REG_BG0HOFS], io_registers[REG_BG0VOFS], line[0]); - } - - if(graphics.layerEnable & 0x0200) { - gfxDrawTextScreen(io_registers[REG_BG1CNT], io_registers[REG_BG1HOFS], io_registers[REG_BG1VOFS], line[1]); - } - - if(graphics.layerEnable & 0x0400) { - gfxDrawTextScreen(io_registers[REG_BG2CNT], io_registers[REG_BG2HOFS], io_registers[REG_BG2VOFS], line[2]); - } - - if(graphics.layerEnable & 0x0800) { - gfxDrawTextScreen(io_registers[REG_BG3CNT], io_registers[REG_BG3HOFS], io_registers[REG_BG3VOFS], line[3]); - } - - int effect = (BLDMOD >> 6) & 3; - - for(int x = 0; x < 240; x++) { - uint32_t color = backdrop; - uint8_t top = 0x20; - - if(line[0][x] < color) { - color = line[0][x]; - top = 0x01; - } - - if(line[1][x] < (color & 0xFF000000)) { - color = line[1][x]; - top = 0x02; - } - - if(line[2][x] < (color & 0xFF000000)) { - color = line[2][x]; - top = 0x04; - } - - if(line[3][x] < (color & 0xFF000000)) { - color = line[3][x]; - top = 0x08; - } - - if(line[4][x] < (color & 0xFF000000)) { - color = line[4][x]; - top = 0x10; - } - - if(!(color & 0x00010000)) { - switch(effect) { - case 0: - break; - case 1: - if(top & BLDMOD) - { - uint32_t back = backdrop; - uint8_t top2 = 0x20; - if((line[0][x] < back) && (top != 0x01)) - { - back = line[0][x]; - top2 = 0x01; - } - - if((line[1][x] < (back & 0xFF000000)) && (top != 0x02)) - { - back = line[1][x]; - top2 = 0x02; - } - - if((line[2][x] < (back & 0xFF000000)) && (top != 0x04)) - { - back = line[2][x]; - top2 = 0x04; - } - - if((line[3][x] < (back & 0xFF000000)) && (top != 0x08)) - { - back = line[3][x]; - top2 = 0x08; - } - - if((line[4][x] < (back & 0xFF000000)) && (top != 0x10)) - { - back = line[4][x]; - top2 = 0x10; - } - - if(top2 & (BLDMOD>>8) && color < 0x80000000) - { - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); - } - - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } else { - // semi-transparent OBJ - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if(line[0][x] < back) { - back = line[0][x]; - top2 = 0x01; - } - - if(line[1][x] < (back & 0xFF000000)) { - back = line[1][x]; - top2 = 0x02; - } - - if(line[2][x] < (back & 0xFF000000)) { - back = line[2][x]; - top2 = 0x04; - } - - if(line[3][x] < (back & 0xFF000000)) { - back = line[3][x]; - top2 = 0x08; - } - - alpha_blend_brightness_switch(); - } - - lineMix[x] = CONVERT_COLOR(color); - } -} - -void mode0RenderLineAll (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 0: Render Line All\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - bool inWindow0 = false; - bool inWindow1 = false; - - if(graphics.layerEnable & 0x2000) { - uint8_t v0 = io_registers[REG_WIN0V] >> 8; - uint8_t v1 = io_registers[REG_WIN0V] & 255; - inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow0 |= (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1); - else - inWindow0 |= (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1); - } - if(graphics.layerEnable & 0x4000) { - uint8_t v0 = io_registers[REG_WIN1V] >> 8; - uint8_t v1 = io_registers[REG_WIN1V] & 255; - inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow1 |= (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1); - else - inWindow1 |= (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1); - } - - if((graphics.layerEnable & 0x0100)) { - gfxDrawTextScreen(io_registers[REG_BG0CNT], io_registers[REG_BG0HOFS], io_registers[REG_BG0VOFS], line[0]); - } - - if((graphics.layerEnable & 0x0200)) { - gfxDrawTextScreen(io_registers[REG_BG1CNT], io_registers[REG_BG1HOFS], io_registers[REG_BG1VOFS], line[1]); - } - - if((graphics.layerEnable & 0x0400)) { - gfxDrawTextScreen(io_registers[REG_BG2CNT], io_registers[REG_BG2HOFS], io_registers[REG_BG2VOFS], line[2]); - } - - if((graphics.layerEnable & 0x0800)) { - gfxDrawTextScreen(io_registers[REG_BG3CNT], io_registers[REG_BG3HOFS], io_registers[REG_BG3VOFS], line[3]); - } - - uint32_t backdrop = (READ16LE(&palette[0]) | 0x30000000); - - uint8_t inWin0Mask = io_registers[REG_WININ] & 0xFF; - uint8_t inWin1Mask = io_registers[REG_WININ] >> 8; - uint8_t outMask = io_registers[REG_WINOUT] & 0xFF; - - for(int x = 0; x < 240; x++) { - uint32_t color = backdrop; - uint8_t top = 0x20; - uint8_t mask = outMask; - - if(!(line[5][x] & 0x80000000)) { - mask = io_registers[REG_WINOUT] >> 8; - } - - int32_t window1_mask = ((inWindow1 & gfxInWin[1][x]) | -(inWindow1 & gfxInWin[1][x])) >> 31; - int32_t window0_mask = ((inWindow0 & gfxInWin[0][x]) | -(inWindow0 & gfxInWin[0][x])) >> 31; - mask = (inWin1Mask & window1_mask) | (mask & ~window1_mask); - mask = (inWin0Mask & window0_mask) | (mask & ~window0_mask); - - if((mask & 1) && (line[0][x] < color)) { - color = line[0][x]; - top = 0x01; - } - - if((mask & 2) && ((uint8_t)(line[1][x]>>24) < (uint8_t)(color >> 24))) { - color = line[1][x]; - top = 0x02; - } - - if((mask & 4) && ((uint8_t)(line[2][x]>>24) < (uint8_t)(color >> 24))) { - color = line[2][x]; - top = 0x04; - } - - if((mask & 8) && ((uint8_t)(line[3][x]>>24) < (uint8_t)(color >> 24))) { - color = line[3][x]; - top = 0x08; - } - - if((mask & 16) && ((uint8_t)(line[4][x]>>24) < (uint8_t)(color >> 24))) { - color = line[4][x]; - top = 0x10; - } - - if(color & 0x00010000) - { - // semi-transparent OBJ - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if((mask & 1) && ((uint8_t)(line[0][x]>>24) < (uint8_t)(back >> 24))) { - back = line[0][x]; - top2 = 0x01; - } - - if((mask & 2) && ((uint8_t)(line[1][x]>>24) < (uint8_t)(back >> 24))) { - back = line[1][x]; - top2 = 0x02; - } - - if((mask & 4) && ((uint8_t)(line[2][x]>>24) < (uint8_t)(back >> 24))) { - back = line[2][x]; - top2 = 0x04; - } - - if((mask & 8) && ((uint8_t)(line[3][x]>>24) < (uint8_t)(back >> 24))) { - back = line[3][x]; - top2 = 0x08; - } - - alpha_blend_brightness_switch(); - } - else if((mask & 32) && (top & BLDMOD)) - { - // special FX on in the window - switch((BLDMOD >> 6) & 3) - { - case 0: - break; - case 1: - { - uint32_t back = backdrop; - uint8_t top2 = 0x20; - if(((mask & 1) && (uint8_t)(line[0][x]>>24) < (uint8_t)(back >> 24)) && top != 0x01) - { - back = line[0][x]; - top2 = 0x01; - } - - if(((mask & 2) && (uint8_t)(line[1][x]>>24) < (uint8_t)(back >> 24)) && top != 0x02) - { - back = line[1][x]; - top2 = 0x02; - } - - if(((mask & 4) && (uint8_t)(line[2][x]>>24) < (uint8_t)(back >> 24)) && top != 0x04) - { - back = line[2][x]; - top2 = 0x04; - } - - if(((mask & 8) && (uint8_t)(line[3][x]>>24) < (uint8_t)(back >> 24)) && top != 0x08) - { - back = line[3][x]; - top2 = 0x08; - } - - if(((mask & 16) && (uint8_t)(line[4][x]>>24) < (uint8_t)(back >> 24)) && top != 0x10) { - back = line[4][x]; - top2 = 0x10; - } - - if(top2 & (BLDMOD>>8) && color < 0x80000000) - { - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - - lineMix[x] = CONVERT_COLOR(color); - } -} - -/* -Mode 1 is a tiled graphics mode, but with background layer 2 supporting scaling and rotation. -There is no layer 3 in this mode. -Layers 0 and 1 can be either 16 colours (with 16 different palettes) or 256 colours. -There are 1024 tiles available. -Layer 2 is 256 colours and allows only 256 tiles. - -These routines only render a single line at a time, because of the way the GBA does events. -*/ - -void mode1RenderLine (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 1: Render Line\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - if(graphics.layerEnable & 0x0100) { - gfxDrawTextScreen(io_registers[REG_BG0CNT], io_registers[REG_BG0HOFS], io_registers[REG_BG0VOFS], line[0]); - } - - if(graphics.layerEnable & 0x0200) { - gfxDrawTextScreen(io_registers[REG_BG1CNT], io_registers[REG_BG1HOFS], io_registers[REG_BG1VOFS], line[1]); - } - - if(graphics.layerEnable & 0x0400) { - int changed = gfxBG2Changed; -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - gfxDrawRotScreen(io_registers[REG_BG2CNT], BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - io_registers[REG_BG2PA], io_registers[REG_BG2PB], io_registers[REG_BG2PC], io_registers[REG_BG2PD], - gfxBG2X, gfxBG2Y, changed, line[2]); - } - - uint32_t backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(uint32_t x = 0; x < 240u; ++x) { - uint32_t color = backdrop; - uint8_t top = 0x20; - - uint8_t li1 = (uint8_t)(line[1][x]>>24); - uint8_t li2 = (uint8_t)(line[2][x]>>24); - uint8_t li4 = (uint8_t)(line[4][x]>>24); - - uint8_t r = (li2 < li1) ? (li2) : (li1); - - if(li4 < r){ - r = (li4); - } - - if(line[0][x] < backdrop) { - color = line[0][x]; - top = 0x01; - } - - if(r < (uint8_t)(color >> 24)) { - if(r == li1){ - color = line[1][x]; - top = 0x02; - }else if(r == li2){ - color = line[2][x]; - top = 0x04; - }else if(r == li4){ - color = line[4][x]; - top = 0x10; - if((color & 0x00010000)) - { - // semi-transparent OBJ - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - uint8_t li0 = (uint8_t)(line[0][x]>>24); - uint8_t li1 = (uint8_t)(line[1][x]>>24); - uint8_t li2 = (uint8_t)(line[2][x]>>24); - uint8_t r = (li1 < li0) ? (li1) : (li0); - - if(li2 < r) { - r = (li2); - } - - if(r < (uint8_t)(back >> 24)) { - if(r == li0){ - back = line[0][x]; - top2 = 0x01; - }else if(r == li1){ - back = line[1][x]; - top2 = 0x02; - }else if(r == li2){ - back = line[2][x]; - top2 = 0x04; - } - } - - alpha_blend_brightness_switch(); - } - } - } - - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -void mode1RenderLineNoWindow (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 1: Render Line No Window\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - if(graphics.layerEnable & 0x0100) { - gfxDrawTextScreen(io_registers[REG_BG0CNT], io_registers[REG_BG0HOFS], io_registers[REG_BG0VOFS], line[0]); - } - - - if(graphics.layerEnable & 0x0200) { - gfxDrawTextScreen(io_registers[REG_BG1CNT], io_registers[REG_BG1HOFS], io_registers[REG_BG1VOFS], line[1]); - } - - if(graphics.layerEnable & 0x0400) { - int changed = gfxBG2Changed; -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - gfxDrawRotScreen(io_registers[REG_BG2CNT], BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - io_registers[REG_BG2PA], io_registers[REG_BG2PB], io_registers[REG_BG2PC], io_registers[REG_BG2PD], - gfxBG2X, gfxBG2Y, changed, line[2]); - } - - uint32_t backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; ++x) { - uint32_t color = backdrop; - uint8_t top = 0x20; - - uint8_t li1 = (uint8_t)(line[1][x]>>24); - uint8_t li2 = (uint8_t)(line[2][x]>>24); - uint8_t li4 = (uint8_t)(line[4][x]>>24); - - uint8_t r = (li2 < li1) ? (li2) : (li1); - - if(li4 < r){ - r = (li4); - } - - if(line[0][x] < backdrop) { - color = line[0][x]; - top = 0x01; - } - - if(r < (uint8_t)(color >> 24)) { - if(r == li1){ - color = line[1][x]; - top = 0x02; - }else if(r == li2){ - color = line[2][x]; - top = 0x04; - }else if(r == li4){ - color = line[4][x]; - top = 0x10; - } - } - - if(!(color & 0x00010000)) { - switch((BLDMOD >> 6) & 3) { - case 0: - break; - case 1: - if(top & BLDMOD) - { - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if((top != 0x01) && (uint8_t)(line[0][x]>>24) < (uint8_t)(back >> 24)) { - back = line[0][x]; - top2 = 0x01; - } - - if((top != 0x02) && (uint8_t)(line[1][x]>>24) < (uint8_t)(back >> 24)) { - back = line[1][x]; - top2 = 0x02; - } - - if((top != 0x04) && (uint8_t)(line[2][x]>>24) < (uint8_t)(back >> 24)) { - back = line[2][x]; - top2 = 0x04; - } - - if((top != 0x10) && (uint8_t)(line[4][x]>>24) < (uint8_t)(back >> 24)) { - back = line[4][x]; - top2 = 0x10; - } - - if(top2 & (BLDMOD>>8) && color < 0x80000000) - { - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } else { - // semi-transparent OBJ - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - uint8_t li0 = (uint8_t)(line[0][x]>>24); - uint8_t li1 = (uint8_t)(line[1][x]>>24); - uint8_t li2 = (uint8_t)(line[2][x]>>24); - - uint8_t r = (li1 < li0) ? (li1) : (li0); - - if(li2 < r) { - r = (li2); - } - - if(r < (uint8_t)(back >> 24)) - { - if(r == li0) - { - back = line[0][x]; - top2 = 0x01; - } - else if(r == li1) - { - back = line[1][x]; - top2 = 0x02; - } - else if(r == li2) - { - back = line[2][x]; - top2 = 0x04; - } - } - - alpha_blend_brightness_switch(); - } - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -void mode1RenderLineAll (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 1: Render Line All\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - bool inWindow0 = false; - bool inWindow1 = false; - - if(graphics.layerEnable & 0x2000) - { - uint8_t v0 = io_registers[REG_WIN0V] >> 8; - uint8_t v1 = io_registers[REG_WIN0V] & 255; - inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); -#ifndef ORIGINAL_BRANCHES - uint32_t condition = v1 >= v0; - int32_t condition_mask = ((condition) | -(condition)) >> 31; - inWindow0 = (((inWindow0 | (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1)) & condition_mask) | (((inWindow0 | (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1)) & ~(condition_mask)))); -#else - if(v1 >= v0) - inWindow0 |= (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1); - else - inWindow0 |= (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1); -#endif - } - if(graphics.layerEnable & 0x4000) - { - uint8_t v0 = io_registers[REG_WIN1V] >> 8; - uint8_t v1 = io_registers[REG_WIN1V] & 255; - inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); -#ifndef ORIGINAL_BRANCHES - uint32_t condition = v1 >= v0; - int32_t condition_mask = ((condition) | -(condition)) >> 31; - inWindow1 = (((inWindow1 | (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1)) & condition_mask) | (((inWindow1 | (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1)) & ~(condition_mask)))); -#else - if(v1 >= v0) - inWindow1 |= (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1); - else - inWindow1 |= (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1); -#endif - } - - if(graphics.layerEnable & 0x0100) { - gfxDrawTextScreen(io_registers[REG_BG0CNT], io_registers[REG_BG0HOFS], io_registers[REG_BG0VOFS], line[0]); - } - - if(graphics.layerEnable & 0x0200) { - gfxDrawTextScreen(io_registers[REG_BG1CNT], io_registers[REG_BG1HOFS], io_registers[REG_BG1VOFS], line[1]); - } - - if(graphics.layerEnable & 0x0400) { - int changed = gfxBG2Changed; -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - gfxDrawRotScreen(io_registers[REG_BG2CNT], BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - io_registers[REG_BG2PA], io_registers[REG_BG2PB], io_registers[REG_BG2PC], io_registers[REG_BG2PD], - gfxBG2X, gfxBG2Y, changed, line[2]); - } - - uint32_t backdrop = (READ16LE(&palette[0]) | 0x30000000); - - uint8_t inWin0Mask = io_registers[REG_WININ] & 0xFF; - uint8_t inWin1Mask = io_registers[REG_WININ] >> 8; - uint8_t outMask = io_registers[REG_WINOUT] & 0xFF; - - for(int x = 0; x < 240; ++x) { - uint32_t color = backdrop; - uint8_t top = 0x20; - uint8_t mask = outMask; - - if(!(line[5][x] & 0x80000000)) { - mask = io_registers[REG_WINOUT] >> 8; - } - - int32_t window1_mask = ((inWindow1 & gfxInWin[1][x]) | -(inWindow1 & gfxInWin[1][x])) >> 31; - int32_t window0_mask = ((inWindow0 & gfxInWin[0][x]) | -(inWindow0 & gfxInWin[0][x])) >> 31; - mask = (inWin1Mask & window1_mask) | (mask & ~window1_mask); - mask = (inWin0Mask & window0_mask) | (mask & ~window0_mask); - - // At the very least, move the inexpensive 'mask' operation up front - if((mask & 1) && line[0][x] < backdrop) { - color = line[0][x]; - top = 0x01; - } - - if((mask & 2) && (uint8_t)(line[1][x]>>24) < (uint8_t)(color >> 24)) { - color = line[1][x]; - top = 0x02; - } - - if((mask & 4) && (uint8_t)(line[2][x]>>24) < (uint8_t)(color >> 24)) { - color = line[2][x]; - top = 0x04; - } - - if((mask & 16) && (uint8_t)(line[4][x]>>24) < (uint8_t)(color >> 24)) { - color = line[4][x]; - top = 0x10; - } - - if(color & 0x00010000) { - // semi-transparent OBJ - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if((mask & 1) && (uint8_t)(line[0][x]>>24) < (uint8_t)(backdrop >> 24)) { - back = line[0][x]; - top2 = 0x01; - } - - if((mask & 2) && (uint8_t)(line[1][x]>>24) < (uint8_t)(back >> 24)) { - back = line[1][x]; - top2 = 0x02; - } - - if((mask & 4) && (uint8_t)(line[2][x]>>24) < (uint8_t)(back >> 24)) { - back = line[2][x]; - top2 = 0x04; - } - - alpha_blend_brightness_switch(); - } else if(mask & 32) { - // special FX on the window - switch((BLDMOD >> 6) & 3) { - case 0: - break; - case 1: - if(top & BLDMOD) - { - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if((mask & 1) && (top != 0x01) && (uint8_t)(line[0][x]>>24) < (uint8_t)(backdrop >> 24)) { - back = line[0][x]; - top2 = 0x01; - } - - if((mask & 2) && (top != 0x02) && (uint8_t)(line[1][x]>>24) < (uint8_t)(back >> 24)) { - back = line[1][x]; - top2 = 0x02; - } - - if((mask & 4) && (top != 0x04) && (uint8_t)(line[2][x]>>24) < (uint8_t)(back >> 24)) { - back = line[2][x]; - top2 = 0x04; - } - - if((mask & 16) && (top != 0x10) && (uint8_t)(line[4][x]>>24) < (uint8_t)(back >> 24)) { - back = line[4][x]; - top2 = 0x10; - } - - if(top2 & (BLDMOD>>8) && color < 0x80000000) - { - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -/* -Mode 2 is a 256 colour tiled graphics mode which supports scaling and rotation. -There is no background layer 0 or 1 in this mode. Only background layers 2 and 3. -There are 256 tiles available. -It does not support flipping. - -These routines only render a single line at a time, because of the way the GBA does events. -*/ - -void mode2RenderLine (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 2: Render Line\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - if(graphics.layerEnable & 0x0400) { - int changed = gfxBG2Changed; -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen(io_registers[REG_BG2CNT], BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - io_registers[REG_BG2PA], io_registers[REG_BG2PB], io_registers[REG_BG2PC], io_registers[REG_BG2PD], gfxBG2X, gfxBG2Y, - changed, line[2]); - } - - if(graphics.layerEnable & 0x0800) { - int changed = gfxBG3Changed; -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen(io_registers[REG_BG3CNT], BG3X_L, BG3X_H, BG3Y_L, BG3Y_H, - io_registers[REG_BG3PA], io_registers[REG_BG3PB], io_registers[REG_BG3PC], io_registers[REG_BG3PD], gfxBG3X, gfxBG3Y, - changed, line[3]); - } - - uint32_t backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; ++x) { - uint32_t color = backdrop; - uint8_t top = 0x20; - - uint8_t li2 = (uint8_t)(line[2][x]>>24); - uint8_t li3 = (uint8_t)(line[3][x]>>24); - uint8_t li4 = (uint8_t)(line[4][x]>>24); - - uint8_t r = (li3 < li2) ? (li3) : (li2); - - if(li4 < r){ - r = (li4); - } - - if(r < (uint8_t)(color >> 24)) { - if(r == li2){ - color = line[2][x]; - top = 0x04; - }else if(r == li3){ - color = line[3][x]; - top = 0x08; - }else if(r == li4){ - color = line[4][x]; - top = 0x10; - - if(color & 0x00010000) { - // semi-transparent OBJ - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - uint8_t li2 = (uint8_t)(line[2][x]>>24); - uint8_t li3 = (uint8_t)(line[3][x]>>24); - uint8_t r = (li3 < li2) ? (li3) : (li2); - - if(r < (uint8_t)(back >> 24)) { - if(r == li2){ - back = line[2][x]; - top2 = 0x04; - }else if(r == li3){ - back = line[3][x]; - top2 = 0x08; - } - } - - alpha_blend_brightness_switch(); - } - } - } - - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - gfxBG3Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -void mode2RenderLineNoWindow (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 2: Render Line No Window\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - if(graphics.layerEnable & 0x0400) { - int changed = gfxBG2Changed; -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen(io_registers[REG_BG2CNT], BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - io_registers[REG_BG2PA], io_registers[REG_BG2PB], io_registers[REG_BG2PC], io_registers[REG_BG2PD], gfxBG2X, gfxBG2Y, - changed, line[2]); - } - - if(graphics.layerEnable & 0x0800) { - int changed = gfxBG3Changed; -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen(io_registers[REG_BG3CNT], BG3X_L, BG3X_H, BG3Y_L, BG3Y_H, - io_registers[REG_BG3PA], io_registers[REG_BG3PB], io_registers[REG_BG3PC], io_registers[REG_BG3PD], gfxBG3X, gfxBG3Y, - changed, line[3]); - } - - uint32_t backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; ++x) { - uint32_t color = backdrop; - uint8_t top = 0x20; - - uint8_t li2 = (uint8_t)(line[2][x]>>24); - uint8_t li3 = (uint8_t)(line[3][x]>>24); - uint8_t li4 = (uint8_t)(line[4][x]>>24); - - uint8_t r = (li3 < li2) ? (li3) : (li2); - - if(li4 < r){ - r = (li4); - } - - if(r < (uint8_t)(color >> 24)) { - if(r == li2){ - color = line[2][x]; - top = 0x04; - }else if(r == li3){ - color = line[3][x]; - top = 0x08; - }else if(r == li4){ - color = line[4][x]; - top = 0x10; - } - } - - if(!(color & 0x00010000)) { - switch((BLDMOD >> 6) & 3) { - case 0: - break; - case 1: - if(top & BLDMOD) - { - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if((top != 0x04) && (uint8_t)(line[2][x]>>24) < (uint8_t)(back >> 24)) { - back = line[2][x]; - top2 = 0x04; - } - - if((top != 0x08) && (uint8_t)(line[3][x]>>24) < (uint8_t)(back >> 24)) { - back = line[3][x]; - top2 = 0x08; - } - - if((top != 0x10) && (uint8_t)(line[4][x]>>24) < (uint8_t)(back >> 24)) { - back = line[4][x]; - top2 = 0x10; - } - - if(top2 & (BLDMOD>>8) && color < 0x80000000) - { - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } else { - // semi-transparent OBJ - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - uint8_t li2 = (uint8_t)(line[2][x]>>24); - uint8_t li3 = (uint8_t)(line[3][x]>>24); - uint8_t r = (li3 < li2) ? (li3) : (li2); - - if(r < (uint8_t)(back >> 24)) { - if(r == li2){ - back = line[2][x]; - top2 = 0x04; - }else if(r == li3){ - back = line[3][x]; - top2 = 0x08; - } - } - - alpha_blend_brightness_switch(); - } - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - gfxBG3Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -void mode2RenderLineAll (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 2: Render Line All\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - bool inWindow0 = false; - bool inWindow1 = false; - - if(graphics.layerEnable & 0x2000) - { - uint8_t v0 = io_registers[REG_WIN0V] >> 8; - uint8_t v1 = io_registers[REG_WIN0V] & 255; - inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); -#ifndef ORIGINAL_BRANCHES - uint32_t condition = v1 >= v0; - int32_t condition_mask = ((condition) | -(condition)) >> 31; - inWindow0 = (((inWindow0 | (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1)) & condition_mask) | (((inWindow0 | (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1)) & ~(condition_mask)))); -#else - if(v1 >= v0) - inWindow0 |= (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1); - else - inWindow0 |= (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1); -#endif - } - if(graphics.layerEnable & 0x4000) - { - uint8_t v0 = io_registers[REG_WIN1V] >> 8; - uint8_t v1 = io_registers[REG_WIN1V] & 255; - inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); -#ifndef ORIGINAL_BRANCHES - uint32_t condition = v1 >= v0; - int32_t condition_mask = ((condition) | -(condition)) >> 31; - inWindow1 = (((inWindow1 | (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1)) & condition_mask) | (((inWindow1 | (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1)) & ~(condition_mask)))); -#else - if(v1 >= v0) - inWindow1 |= (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1); - else - inWindow1 |= (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1); -#endif - } - - if(graphics.layerEnable & 0x0400) { - int changed = gfxBG2Changed; -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen(io_registers[REG_BG2CNT], BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - io_registers[REG_BG2PA], io_registers[REG_BG2PB], io_registers[REG_BG2PC], io_registers[REG_BG2PD], gfxBG2X, gfxBG2Y, - changed, line[2]); - } - - if(graphics.layerEnable & 0x0800) { - int changed = gfxBG3Changed; -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen(io_registers[REG_BG3CNT], BG3X_L, BG3X_H, BG3Y_L, BG3Y_H, - io_registers[REG_BG3PA], io_registers[REG_BG3PB], io_registers[REG_BG3PC], io_registers[REG_BG3PD], gfxBG3X, gfxBG3Y, - changed, line[3]); - } - - uint32_t backdrop = (READ16LE(&palette[0]) | 0x30000000); - - uint8_t inWin0Mask = io_registers[REG_WININ] & 0xFF; - uint8_t inWin1Mask = io_registers[REG_WININ] >> 8; - uint8_t outMask = io_registers[REG_WINOUT] & 0xFF; - - for(int x = 0; x < 240; x++) { - uint32_t color = backdrop; - uint8_t top = 0x20; - uint8_t mask = outMask; - - if(!(line[5][x] & 0x80000000)) { - mask = io_registers[REG_WINOUT] >> 8; - } - - int32_t window1_mask = ((inWindow1 & gfxInWin[1][x]) | -(inWindow1 & gfxInWin[1][x])) >> 31; - int32_t window0_mask = ((inWindow0 & gfxInWin[0][x]) | -(inWindow0 & gfxInWin[0][x])) >> 31; - mask = (inWin1Mask & window1_mask) | (mask & ~window1_mask); - mask = (inWin0Mask & window0_mask) | (mask & ~window0_mask); - - if((mask & 4) && line[2][x] < color) { - color = line[2][x]; - top = 0x04; - } - - if((mask & 8) && (uint8_t)(line[3][x]>>24) < (uint8_t)(color >> 24)) { - color = line[3][x]; - top = 0x08; - } - - if((mask & 16) && (uint8_t)(line[4][x]>>24) < (uint8_t)(color >> 24)) { - color = line[4][x]; - top = 0x10; - } - - if(color & 0x00010000) { - // semi-transparent OBJ - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if((mask & 4) && line[2][x] < back) { - back = line[2][x]; - top2 = 0x04; - } - - if((mask & 8) && (uint8_t)(line[3][x]>>24) < (uint8_t)(back >> 24)) { - back = line[3][x]; - top2 = 0x08; - } - - alpha_blend_brightness_switch(); - } else if(mask & 32) { - // special FX on the window - switch((BLDMOD >> 6) & 3) { - case 0: - break; - case 1: - if(top & BLDMOD) - { - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if((mask & 4) && (top != 0x04) && line[2][x] < back) { - back = line[2][x]; - top2 = 0x04; - } - - if((mask & 8) && (top != 0x08) && (uint8_t)(line[3][x]>>24) < (uint8_t)(back >> 24)) { - back = line[3][x]; - top2 = 0x08; - } - - if((mask & 16) && (top != 0x10) && (uint8_t)(line[4][x]>>24) < (uint8_t)(back >> 24)) { - back = line[4][x]; - top2 = 0x10; - } - - if(top2 & (BLDMOD>>8) && color < 0x80000000) - { - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - gfxBG3Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -/* -Mode 3 is a 15-bit (32768) colour bitmap graphics mode. -It has a single layer, background layer 2, the same size as the screen. -It doesn't support paging, scrolling, flipping, rotation or tiles. - -These routines only render a single line at a time, because of the way the GBA does events. -*/ - -void mode3RenderLine (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 3: Render Line\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - if(graphics.layerEnable & 0x0400) { - int changed = gfxBG2Changed; - -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen16Bit(gfxBG2X, gfxBG2Y, changed); - } - - uint32_t background = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; ++x) { - uint32_t color = background; - uint8_t top = 0x20; - - if(line[2][x] < color) { - color = line[2][x]; - top = 0x04; - } - - if((uint8_t)(line[4][x]>>24) < (uint8_t)(color >>24)) { - color = line[4][x]; - top = 0x10; - - if(color & 0x00010000) { - // semi-transparent OBJ - uint32_t back = background; - uint8_t top2 = 0x20; - - if(line[2][x] < background) { - back = line[2][x]; - top2 = 0x04; - } - - alpha_blend_brightness_switch(); - } - } - - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -void mode3RenderLineNoWindow (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 3: Render Line No Window\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - if(graphics.layerEnable & 0x0400) { - int changed = gfxBG2Changed; - -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen16Bit(gfxBG2X, gfxBG2Y, changed); - } - - uint32_t background = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; ++x) { - uint32_t color = background; - uint8_t top = 0x20; - - if(line[2][x] < background) { - color = line[2][x]; - top = 0x04; - } - - if((uint8_t)(line[4][x]>>24) < (uint8_t)(color >>24)) { - color = line[4][x]; - top = 0x10; - } - - if(!(color & 0x00010000)) { - switch((BLDMOD >> 6) & 3) { - case 0: - break; - case 1: - if(top & BLDMOD) - { - uint32_t back = background; - uint8_t top2 = 0x20; - - if(top != 0x04 && (line[2][x] < background) ) { - back = line[2][x]; - top2 = 0x04; - } - - if(top != 0x10 && ((uint8_t)(line[4][x]>>24) < (uint8_t)(back >> 24))) { - back = line[4][x]; - top2 = 0x10; - } - - if(top2 & (BLDMOD>>8) && color < 0x80000000) - { - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); - } - - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } else { - // semi-transparent OBJ - uint32_t back = background; - uint8_t top2 = 0x20; - - if(line[2][x] < background) { - back = line[2][x]; - top2 = 0x04; - } - - alpha_blend_brightness_switch(); - } - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -void mode3RenderLineAll (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 3: Render Line All\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - bool inWindow0 = false; - bool inWindow1 = false; - - if(graphics.layerEnable & 0x2000) - { - uint8_t v0 = io_registers[REG_WIN0V] >> 8; - uint8_t v1 = io_registers[REG_WIN0V] & 255; - inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); -#ifndef ORIGINAL_BRANCHES - uint32_t condition = v1 >= v0; - int32_t condition_mask = ((condition) | -(condition)) >> 31; - inWindow0 = (((inWindow0 | (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1)) & condition_mask) | (((inWindow0 | (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1)) & ~(condition_mask)))); -#else - if(v1 >= v0) - inWindow0 |= (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1); - else - inWindow0 |= (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1); -#endif - } - - if(graphics.layerEnable & 0x4000) - { - uint8_t v0 = io_registers[REG_WIN1V] >> 8; - uint8_t v1 = io_registers[REG_WIN1V] & 255; - inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); -#ifndef ORIGINAL_BRANCHES - uint32_t condition = v1 >= v0; - int32_t condition_mask = ((condition) | -(condition)) >> 31; - inWindow1 = (((inWindow1 | (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1)) & condition_mask) | (((inWindow1 | (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1)) & ~(condition_mask)))); -#else - if(v1 >= v0) - inWindow1 |= (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1); - else - inWindow1 |= (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1); -#endif - } - - if(graphics.layerEnable & 0x0400) { - int changed = gfxBG2Changed; - -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen16Bit(gfxBG2X, gfxBG2Y, changed); - } - - uint8_t inWin0Mask = io_registers[REG_WININ] & 0xFF; - uint8_t inWin1Mask = io_registers[REG_WININ] >> 8; - uint8_t outMask = io_registers[REG_WINOUT] & 0xFF; - - uint32_t background = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; ++x) { - uint32_t color = background; - uint8_t top = 0x20; - uint8_t mask = outMask; - - if(!(line[5][x] & 0x80000000)) { - mask = io_registers[REG_WINOUT] >> 8; - } - - int32_t window1_mask = ((inWindow1 & gfxInWin[1][x]) | -(inWindow1 & gfxInWin[1][x])) >> 31; - int32_t window0_mask = ((inWindow0 & gfxInWin[0][x]) | -(inWindow0 & gfxInWin[0][x])) >> 31; - mask = (inWin1Mask & window1_mask) | (mask & ~window1_mask); - mask = (inWin0Mask & window0_mask) | (mask & ~window0_mask); - - if((mask & 4) && line[2][x] < background) { - color = line[2][x]; - top = 0x04; - } - - if((mask & 16) && ((uint8_t)(line[4][x]>>24) < (uint8_t)(color >>24))) { - color = line[4][x]; - top = 0x10; - } - - if(color & 0x00010000) { - // semi-transparent OBJ - uint32_t back = background; - uint8_t top2 = 0x20; - - if((mask & 4) && line[2][x] < background) { - back = line[2][x]; - top2 = 0x04; - } - - alpha_blend_brightness_switch(); - } else if(mask & 32) { - switch((BLDMOD >> 6) & 3) { - case 0: - break; - case 1: - if(top & BLDMOD) - { - uint32_t back = background; - uint8_t top2 = 0x20; - - if((mask & 4) && (top != 0x04) && line[2][x] < back) { - back = line[2][x]; - top2 = 0x04; - } - - if((mask & 16) && (top != 0x10) && (uint8_t)(line[4][x]>>24) < (uint8_t)(back >> 24)) { - back = line[4][x]; - top2 = 0x10; - } - - if(top2 & (BLDMOD>>8) && color < 0x80000000) - { - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -/* -Mode 4 is a 256 colour bitmap graphics mode with 2 swappable pages. -It has a single layer, background layer 2, the same size as the screen. -It doesn't support scrolling, flipping, rotation or tiles. - -These routines only render a single line at a time, because of the way the GBA does events. -*/ - -void mode4RenderLine (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 4: Render Line\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - if(graphics.layerEnable & 0x400) - { - int changed = gfxBG2Changed; - -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen256(gfxBG2X, gfxBG2Y, changed); - } - - uint32_t backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; ++x) - { - uint32_t color = backdrop; - uint8_t top = 0x20; - - if(line[2][x] < backdrop) { - color = line[2][x]; - top = 0x04; - } - - if((uint8_t)(line[4][x]>>24) < (uint8_t)(color >> 24)) { - color = line[4][x]; - top = 0x10; - - if(color & 0x00010000) { - // semi-transparent OBJ - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if(line[2][x] < backdrop) { - back = line[2][x]; - top2 = 0x04; - } - - alpha_blend_brightness_switch(); - } - } - - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -void mode4RenderLineNoWindow (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 4: Render Line No Window\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - if(graphics.layerEnable & 0x400) - { - int changed = gfxBG2Changed; - -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen256(gfxBG2X, gfxBG2Y, changed); - } - - uint32_t backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; ++x) - { - uint32_t color = backdrop; - uint8_t top = 0x20; - - if(line[2][x] < backdrop) { - color = line[2][x]; - top = 0x04; - } - - if((uint8_t)(line[4][x]>>24) < (uint8_t)(color >> 24)) { - color = line[4][x]; - top = 0x10; - } - - if(!(color & 0x00010000)) { - switch((BLDMOD >> 6) & 3) { - case 0: - break; - case 1: - if(top & BLDMOD) - { - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if((top != 0x04) && line[2][x] < backdrop) { - back = line[2][x]; - top2 = 0x04; - } - - if((top != 0x10) && (uint8_t)(line[4][x]>>24) < (uint8_t)(back >> 24)) { - back = line[4][x]; - top2 = 0x10; - } - - if(top2 & (BLDMOD>>8) && color < 0x80000000) - { - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } else { - // semi-transparent OBJ - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if(line[2][x] < back) { - back = line[2][x]; - top2 = 0x04; - } - - alpha_blend_brightness_switch(); - } - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -void mode4RenderLineAll (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 4: Render Line All\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - bool inWindow0 = false; - bool inWindow1 = false; - - if(graphics.layerEnable & 0x2000) - { - uint8_t v0 = io_registers[REG_WIN0V] >> 8; - uint8_t v1 = io_registers[REG_WIN0V] & 255; - inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); -#ifndef ORIGINAL_BRANCHES - uint32_t condition = v1 >= v0; - int32_t condition_mask = ((condition) | -(condition)) >> 31; - inWindow0 = (((inWindow0 | (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1)) & condition_mask) | (((inWindow0 | (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1)) & ~(condition_mask)))); -#else - if(v1 >= v0) - inWindow0 |= (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1); - else - inWindow0 |= (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1); -#endif - } - - if(graphics.layerEnable & 0x4000) - { - uint8_t v0 = io_registers[REG_WIN1V] >> 8; - uint8_t v1 = io_registers[REG_WIN1V] & 255; - inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); -#ifndef ORIGINAL_BRANCHES - uint32_t condition = v1 >= v0; - int32_t condition_mask = ((condition) | -(condition)) >> 31; - inWindow1 = (((inWindow1 | (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1)) & condition_mask) | (((inWindow1 | (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1)) & ~(condition_mask)))); -#else - if(v1 >= v0) - inWindow1 |= (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1); - else - inWindow1 |= (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1); -#endif - } - - if(graphics.layerEnable & 0x400) - { - int changed = gfxBG2Changed; - -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen256(gfxBG2X, gfxBG2Y, changed); - } - - uint32_t backdrop = (READ16LE(&palette[0]) | 0x30000000); - - uint8_t inWin0Mask = io_registers[REG_WININ] & 0xFF; - uint8_t inWin1Mask = io_registers[REG_WININ] >> 8; - uint8_t outMask = io_registers[REG_WINOUT] & 0xFF; - - for(int x = 0; x < 240; ++x) { - uint32_t color = backdrop; - uint8_t top = 0x20; - uint8_t mask = outMask; - - if(!(line[5][x] & 0x80000000)) - mask = io_registers[REG_WINOUT] >> 8; - - int32_t window1_mask = ((inWindow1 & gfxInWin[1][x]) | -(inWindow1 & gfxInWin[1][x])) >> 31; - int32_t window0_mask = ((inWindow0 & gfxInWin[0][x]) | -(inWindow0 & gfxInWin[0][x])) >> 31; - mask = (inWin1Mask & window1_mask) | (mask & ~window1_mask); - mask = (inWin0Mask & window0_mask) | (mask & ~window0_mask); - - if((mask & 4) && (line[2][x] < backdrop)) - { - color = line[2][x]; - top = 0x04; - } - - if((mask & 16) && ((uint8_t)(line[4][x]>>24) < (uint8_t)(color >>24))) - { - color = line[4][x]; - top = 0x10; - } - - if(color & 0x00010000) { - // semi-transparent OBJ - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if((mask & 4) && line[2][x] < back) { - back = line[2][x]; - top2 = 0x04; - } - - alpha_blend_brightness_switch(); - } else if(mask & 32) { - switch((BLDMOD >> 6) & 3) { - case 0: - break; - case 1: - if(top & BLDMOD) - { - uint32_t back = backdrop; - uint8_t top2 = 0x20; - - if((mask & 4) && (top != 0x04) && (line[2][x] < backdrop)) { - back = line[2][x]; - top2 = 0x04; - } - - if((mask & 16) && (top != 0x10) && (uint8_t)(line[4][x]>>24) < (uint8_t)(back >> 24)) { - back = line[4][x]; - top2 = 0x10; - } - - if(top2 & (BLDMOD>>8) && color < 0x80000000) - { - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -/* -Mode 5 is a low resolution (160x128) 15-bit colour bitmap graphics mode -with 2 swappable pages! -It has a single layer, background layer 2, lower resolution than the screen. -It doesn't support scrolling, flipping, rotation or tiles. - -These routines only render a single line at a time, because of the way the GBA does events. -*/ - -void mode5RenderLine (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 5: Render Line\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - if(graphics.layerEnable & 0x0400) { - int changed = gfxBG2Changed; - -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen16Bit160(gfxBG2X, gfxBG2Y, changed); - } - - uint32_t background; - background = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; ++x) { - uint32_t color = background; - uint8_t top = 0x20; - - if(line[2][x] < background) { - color = line[2][x]; - top = 0x04; - } - - if((uint8_t)(line[4][x]>>24) < (uint8_t)(color >>24)) { - color = line[4][x]; - top = 0x10; - - if(color & 0x00010000) { - // semi-transparent OBJ - uint32_t back = background; - uint8_t top2 = 0x20; - - if(line[2][x] < back) { - back = line[2][x]; - top2 = 0x04; - } - - alpha_blend_brightness_switch(); - } - } - - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -void mode5RenderLineNoWindow (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 5: Render Line No Window\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - if(graphics.layerEnable & 0x0400) { - int changed = gfxBG2Changed; - -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen16Bit160(gfxBG2X, gfxBG2Y, changed); - } - - uint32_t background; - background = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; ++x) { - uint32_t color = background; - uint8_t top = 0x20; - - if(line[2][x] < background) { - color = line[2][x]; - top = 0x04; - } - - if((uint8_t)(line[4][x]>>24) < (uint8_t)(color >>24)) { - color = line[4][x]; - top = 0x10; - } - - if(!(color & 0x00010000)) { - switch((BLDMOD >> 6) & 3) { - case 0: - break; - case 1: - if(top & BLDMOD) - { - uint32_t back = background; - uint8_t top2 = 0x20; - - if((top != 0x04) && line[2][x] < background) { - back = line[2][x]; - top2 = 0x04; - } - - if((top != 0x10) && (uint8_t)(line[4][x]>>24) < (uint8_t)(back >> 24)) { - back = line[4][x]; - top2 = 0x10; - } - - if(top2 & (BLDMOD>>8) && color < 0x80000000) - { - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); - } - - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } else { - // semi-transparent OBJ - uint32_t back = background; - uint8_t top2 = 0x20; - - if(line[2][x] < back) { - back = line[2][x]; - top2 = 0x04; - } - - alpha_blend_brightness_switch(); - } - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -void mode5RenderLineAll (void) -{ -#ifdef REPORT_VIDEO_MODES - fprintf(stderr, "MODE 5: Render Line All\n"); -#endif - INIT_COLOR_DEPTH_LINE_MIX(); - - uint16_t *palette = (uint16_t *)graphics.paletteRAM; - - if(graphics.layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - -#if 0 - if(gfxLastVCOUNT > io_registers[REG_VCOUNT]) - changed = 3; -#endif - - gfxDrawRotScreen16Bit160(gfxBG2X, gfxBG2Y, changed); - } - - - - bool inWindow0 = false; - bool inWindow1 = false; - - if(graphics.layerEnable & 0x2000) - { - uint8_t v0 = io_registers[REG_WIN0V] >> 8; - uint8_t v1 = io_registers[REG_WIN0V] & 255; - inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); -#ifndef ORIGINAL_BRANCHES - uint32_t condition = v1 >= v0; - int32_t condition_mask = ((condition) | -(condition)) >> 31; - inWindow0 = (((inWindow0 | (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1)) & condition_mask) | (((inWindow0 | (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1)) & ~(condition_mask)))); -#else - if(v1 >= v0) - inWindow0 |= (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1); - else - inWindow0 |= (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1); -#endif - } - - if(graphics.layerEnable & 0x4000) - { - uint8_t v0 = io_registers[REG_WIN1V] >> 8; - uint8_t v1 = io_registers[REG_WIN1V] & 255; - inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); -#ifndef ORIGINAL_BRANCHES - uint32_t condition = v1 >= v0; - int32_t condition_mask = ((condition) | -(condition)) >> 31; - inWindow1 = (((inWindow1 | (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1)) & condition_mask) | (((inWindow1 | (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1)) & ~(condition_mask)))); -#else - if(v1 >= v0) - inWindow1 |= (io_registers[REG_VCOUNT] >= v0 && io_registers[REG_VCOUNT] < v1); - else - inWindow1 |= (io_registers[REG_VCOUNT] >= v0 || io_registers[REG_VCOUNT] < v1); -#endif - } - - uint8_t inWin0Mask = io_registers[REG_WININ] & 0xFF; - uint8_t inWin1Mask = io_registers[REG_WININ] >> 8; - uint8_t outMask = io_registers[REG_WINOUT] & 0xFF; - - uint32_t background; - background = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; ++x) { - uint32_t color = background; - uint8_t top = 0x20; - uint8_t mask = outMask; - - if(!(line[5][x] & 0x80000000)) { - mask = io_registers[REG_WINOUT] >> 8; - } - - int32_t window1_mask = ((inWindow1 & gfxInWin[1][x]) | -(inWindow1 & gfxInWin[1][x])) >> 31; - int32_t window0_mask = ((inWindow0 & gfxInWin[0][x]) | -(inWindow0 & gfxInWin[0][x])) >> 31; - mask = (inWin1Mask & window1_mask) | (mask & ~window1_mask); - mask = (inWin0Mask & window0_mask) | (mask & ~window0_mask); - - if((mask & 4) && (line[2][x] < background)) { - color = line[2][x]; - top = 0x04; - } - - if((mask & 16) && ((uint8_t)(line[4][x]>>24) < (uint8_t)(color >>24))) { - color = line[4][x]; - top = 0x10; - } - - if(color & 0x00010000) { - // semi-transparent OBJ - uint32_t back = background; - uint8_t top2 = 0x20; - - if((mask & 4) && line[2][x] < back) { - back = line[2][x]; - top2 = 0x04; - } - - alpha_blend_brightness_switch(); - } else if(mask & 32) { - switch((BLDMOD >> 6) & 3) { - case 0: - break; - case 1: - if(top & BLDMOD) - { - uint32_t back = background; - uint8_t top2 = 0x20; - - if((mask & 4) && (top != 0x04) && (line[2][x] < background)) { - back = line[2][x]; - top2 = 0x04; - } - - if((mask & 16) && (top != 0x10) && (uint8_t)(line[4][x]>>24) < (uint8_t)(back >> 24)) { - back = line[4][x]; - top2 = 0x10; - } - - if(top2 & (BLDMOD>>8) && color < 0x80000000) - { - GFX_ALPHA_BLEND(color, back, coeff[COLEV & 0x1F], coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - - lineMix[x] = CONVERT_COLOR(color); - } - gfxBG2Changed = 0; - //gfxLastVCOUNT = io_registers[REG_VCOUNT]; -} - -void (Gigazoid::*renderLine)(void); -bool render_line_all_enabled; - -#define CPUUpdateRender() \ - render_line_all_enabled = false; \ - switch(io_registers[REG_DISPCNT] & 7) { \ - case 0: \ - if((!fxOn && !windowOn && !(graphics.layerEnable & 0x8000))) \ - renderLine = &Gigazoid::mode0RenderLine; \ - else if(fxOn && !windowOn && !(graphics.layerEnable & 0x8000)) \ - renderLine = &Gigazoid::mode0RenderLineNoWindow; \ - else { \ - renderLine = &Gigazoid::mode0RenderLineAll; \ - render_line_all_enabled = true; \ - } \ - break; \ - case 1: \ - if((!fxOn && !windowOn && !(graphics.layerEnable & 0x8000))) \ - renderLine = &Gigazoid::mode1RenderLine; \ - else if(fxOn && !windowOn && !(graphics.layerEnable & 0x8000)) \ - renderLine = &Gigazoid::mode1RenderLineNoWindow; \ - else { \ - renderLine = &Gigazoid::mode1RenderLineAll; \ - render_line_all_enabled = true; \ - } \ - break; \ - case 2: \ - if((!fxOn && !windowOn && !(graphics.layerEnable & 0x8000))) \ - renderLine = &Gigazoid::mode2RenderLine; \ - else if(fxOn && !windowOn && !(graphics.layerEnable & 0x8000)) \ - renderLine = &Gigazoid::mode2RenderLineNoWindow; \ - else { \ - renderLine = &Gigazoid::mode2RenderLineAll; \ - render_line_all_enabled = true; \ - } \ - break; \ - case 3: \ - if((!fxOn && !windowOn && !(graphics.layerEnable & 0x8000))) \ - renderLine = &Gigazoid::mode3RenderLine; \ - else if(fxOn && !windowOn && !(graphics.layerEnable & 0x8000)) \ - renderLine = &Gigazoid::mode3RenderLineNoWindow; \ - else { \ - renderLine = &Gigazoid::mode3RenderLineAll; \ - render_line_all_enabled = true; \ - } \ - break; \ - case 4: \ - if((!fxOn && !windowOn && !(graphics.layerEnable & 0x8000))) \ - renderLine = &Gigazoid::mode4RenderLine; \ - else if(fxOn && !windowOn && !(graphics.layerEnable & 0x8000)) \ - renderLine = &Gigazoid::mode4RenderLineNoWindow; \ - else { \ - renderLine = &Gigazoid::mode4RenderLineAll; \ - render_line_all_enabled = true; \ - } \ - break; \ - case 5: \ - if((!fxOn && !windowOn && !(graphics.layerEnable & 0x8000))) \ - renderLine = &Gigazoid::mode5RenderLine; \ - else if(fxOn && !windowOn && !(graphics.layerEnable & 0x8000)) \ - renderLine = &Gigazoid::mode5RenderLineNoWindow; \ - else { \ - renderLine = &Gigazoid::mode5RenderLineAll; \ - render_line_all_enabled = true; \ - } \ - } - -#define CPUSwap(a, b) \ -a ^= b; \ -b ^= a; \ -a ^= b; - -void CPUSwitchMode(int mode, bool saveState, bool breakLoop) -{ - CPU_UPDATE_CPSR(); - - switch(armMode) { - case 0x10: - case 0x1F: - bus.reg[R13_USR].I = bus.reg[13].I; - bus.reg[R14_USR].I = bus.reg[14].I; - bus.reg[17].I = bus.reg[16].I; - break; - case 0x11: - CPUSwap(bus.reg[R8_FIQ].I, bus.reg[8].I); - CPUSwap(bus.reg[R9_FIQ].I, bus.reg[9].I); - CPUSwap(bus.reg[R10_FIQ].I, bus.reg[10].I); - CPUSwap(bus.reg[R11_FIQ].I, bus.reg[11].I); - CPUSwap(bus.reg[R12_FIQ].I, bus.reg[12].I); - bus.reg[R13_FIQ].I = bus.reg[13].I; - bus.reg[R14_FIQ].I = bus.reg[14].I; - bus.reg[SPSR_FIQ].I = bus.reg[17].I; - break; - case 0x12: - bus.reg[R13_IRQ].I = bus.reg[13].I; - bus.reg[R14_IRQ].I = bus.reg[14].I; - bus.reg[SPSR_IRQ].I = bus.reg[17].I; - break; - case 0x13: - bus.reg[R13_SVC].I = bus.reg[13].I; - bus.reg[R14_SVC].I = bus.reg[14].I; - bus.reg[SPSR_SVC].I = bus.reg[17].I; - break; - case 0x17: - bus.reg[R13_ABT].I = bus.reg[13].I; - bus.reg[R14_ABT].I = bus.reg[14].I; - bus.reg[SPSR_ABT].I = bus.reg[17].I; - break; - case 0x1b: - bus.reg[R13_UND].I = bus.reg[13].I; - bus.reg[R14_UND].I = bus.reg[14].I; - bus.reg[SPSR_UND].I = bus.reg[17].I; - break; - } - - uint32_t CPSR = bus.reg[16].I; - uint32_t SPSR = bus.reg[17].I; - - switch(mode) { - case 0x10: - case 0x1F: - bus.reg[13].I = bus.reg[R13_USR].I; - bus.reg[14].I = bus.reg[R14_USR].I; - bus.reg[16].I = SPSR; - break; - case 0x11: - CPUSwap(bus.reg[8].I, bus.reg[R8_FIQ].I); - CPUSwap(bus.reg[9].I, bus.reg[R9_FIQ].I); - CPUSwap(bus.reg[10].I, bus.reg[R10_FIQ].I); - CPUSwap(bus.reg[11].I, bus.reg[R11_FIQ].I); - CPUSwap(bus.reg[12].I, bus.reg[R12_FIQ].I); - bus.reg[13].I = bus.reg[R13_FIQ].I; - bus.reg[14].I = bus.reg[R14_FIQ].I; - if(saveState) - bus.reg[17].I = CPSR; else - bus.reg[17].I = bus.reg[SPSR_FIQ].I; - break; - case 0x12: - bus.reg[13].I = bus.reg[R13_IRQ].I; - bus.reg[14].I = bus.reg[R14_IRQ].I; - bus.reg[16].I = SPSR; - if(saveState) - bus.reg[17].I = CPSR; - else - bus.reg[17].I = bus.reg[SPSR_IRQ].I; - break; - case 0x13: - bus.reg[13].I = bus.reg[R13_SVC].I; - bus.reg[14].I = bus.reg[R14_SVC].I; - bus.reg[16].I = SPSR; - if(saveState) - bus.reg[17].I = CPSR; - else - bus.reg[17].I = bus.reg[SPSR_SVC].I; - break; - case 0x17: - bus.reg[13].I = bus.reg[R13_ABT].I; - bus.reg[14].I = bus.reg[R14_ABT].I; - bus.reg[16].I = SPSR; - if(saveState) - bus.reg[17].I = CPSR; - else - bus.reg[17].I = bus.reg[SPSR_ABT].I; - break; - case 0x1b: - bus.reg[13].I = bus.reg[R13_UND].I; - bus.reg[14].I = bus.reg[R14_UND].I; - bus.reg[16].I = SPSR; - if(saveState) - bus.reg[17].I = CPSR; - else - bus.reg[17].I = bus.reg[SPSR_UND].I; - break; - default: - break; - } - armMode = mode; - CPUUpdateFlags(breakLoop); - CPU_UPDATE_CPSR(); -} - - - -void doDMA(uint32_t &s, uint32_t &d, uint32_t si, uint32_t di, uint32_t 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. - int32_t sm_gt_15_mask = ((sm>15) | -(sm>15)) >> 31; - int32_t dm_gt_15_mask = ((dm>15) | -(dm>15)) >> 31; - sm = ((((15) & sm_gt_15_mask) | ((((sm) & ~(sm_gt_15_mask)))))); - dm = ((((15) & dm_gt_15_mask) | ((((dm) & ~(dm_gt_15_mask)))))); - - //if ((sm>=0x05) && (sm<=0x07) || (dm>=0x05) && (dm <=0x07)) - // blank = (((io_registers[REG_DISPSTAT] | ((io_registers[REG_DISPSTAT] >> 1)&1))==1) ? true : false); - - if(transfer32) - { - s &= 0xFFFFFFFC; - if(s < 0x02000000 && (bus.reg[15].I >> 24)) - { - do - { - CPUWriteMemory(d, 0); - d += di; - c--; - }while(c != 0); - } - else - { - do { - CPUWriteMemory(d, CPUReadMemory(s)); - d += di; - s += si; - c--; - }while(c != 0); - } - } - else - { - s &= 0xFFFFFFFE; - si = (int)si >> 1; - di = (int)di >> 1; - if(s < 0x02000000 && (bus.reg[15].I >> 24)) - { - do { - CPUWriteHalfWord(d, 0); - d += di; - c--; - }while(c != 0); - } - else - { - do{ - CPUWriteHalfWord(d, CPUReadHalfWord(s)); - d += di; - s += si; - c--; - }while(c != 0); - } - } - - cpuDmaCount = 0; - - if(transfer32) - { - sw = 1+memoryWaitSeq32[sm & 15]; - dw = 1+memoryWaitSeq32[dm & 15]; - cpuDmaTicksToUpdate += (sw+dw)*(sc-1) + 6 + memoryWait32[sm & 15] + memoryWaitSeq32[dm & 15]; - } - else - { - sw = 1+memoryWaitSeq[sm & 15]; - dw = 1+memoryWaitSeq[dm & 15]; - cpuDmaTicksToUpdate += (sw+dw)*(sc-1) + 6 + memoryWait[sm & 15] + memoryWaitSeq[dm & 15]; - } -} - - -void CPUCheckDMA(int reason, int dmamask) -{ - uint32_t arrayval[] = {4, (uint32_t)-4, 0, 4}; - // DMA 0 - if((DM0CNT_H & 0x8000) && (dmamask & 1)) - { - if(((DM0CNT_H >> 12) & 3) == reason) - { - uint32_t sourceIncrement, destIncrement; - uint32_t condition1 = ((DM0CNT_H >> 7) & 3); - uint32_t condition2 = ((DM0CNT_H >> 5) & 3); - sourceIncrement = arrayval[condition1]; - destIncrement = arrayval[condition2]; - doDMA(dma0Source, dma0Dest, sourceIncrement, destIncrement, - DM0CNT_L ? DM0CNT_L : 0x4000, - DM0CNT_H & 0x0400); - - if(DM0CNT_H & 0x4000) - { - io_registers[REG_IF] |= 0x0100; - UPDATE_REG(0x202, io_registers[REG_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) { - uint32_t sourceIncrement, destIncrement; - uint32_t condition1 = ((DM1CNT_H >> 7) & 3); - uint32_t condition2 = ((DM1CNT_H >> 5) & 3); - sourceIncrement = arrayval[condition1]; - destIncrement = arrayval[condition2]; - uint32_t di_value, c_value, transfer_value; - if(reason == 3) - { - di_value = 0; - c_value = 4; - transfer_value = 0x0400; - } - else - { - di_value = destIncrement; - c_value = DM1CNT_L ? DM1CNT_L : 0x4000; - transfer_value = DM1CNT_H & 0x0400; - } - doDMA(dma1Source, dma1Dest, sourceIncrement, di_value, c_value, transfer_value); - - if(DM1CNT_H & 0x4000) { - io_registers[REG_IF] |= 0x0200; - UPDATE_REG(0x202, io_registers[REG_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) { - uint32_t sourceIncrement, destIncrement; - uint32_t condition1 = ((DM2CNT_H >> 7) & 3); - uint32_t condition2 = ((DM2CNT_H >> 5) & 3); - sourceIncrement = arrayval[condition1]; - destIncrement = arrayval[condition2]; - uint32_t di_value, c_value, transfer_value; - if(reason == 3) - { - di_value = 0; - c_value = 4; - transfer_value = 0x0400; - } - else - { - di_value = destIncrement; - c_value = DM2CNT_L ? DM2CNT_L : 0x4000; - transfer_value = DM2CNT_H & 0x0400; - } - doDMA(dma2Source, dma2Dest, sourceIncrement, di_value, c_value, transfer_value); - - if(DM2CNT_H & 0x4000) { - io_registers[REG_IF] |= 0x0400; - UPDATE_REG(0x202, io_registers[REG_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) - { - uint32_t sourceIncrement, destIncrement; - uint32_t condition1 = ((DM3CNT_H >> 7) & 3); - uint32_t condition2 = ((DM3CNT_H >> 5) & 3); - sourceIncrement = arrayval[condition1]; - destIncrement = arrayval[condition2]; - doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement, - DM3CNT_L ? DM3CNT_L : 0x10000, - DM3CNT_H & 0x0400); - if(DM3CNT_H & 0x4000) { - io_registers[REG_IF] |= 0x0800; - UPDATE_REG(0x202, io_registers[REG_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); - } - } - } -} - -uint16_t *address_lut[0x300]; - -void CPUUpdateRegister(uint32_t address, uint16_t value) -{ - switch(address) - { - case 0x00: - { - if((value & 7) > 5) // display modes above 0-5 are prohibited - io_registers[REG_DISPCNT] = (value & 7); - - bool change = (0 != ((io_registers[REG_DISPCNT] ^ value) & 0x80)); - bool changeBG = (0 != ((io_registers[REG_DISPCNT] ^ value) & 0x0F00)); - uint16_t changeBGon = ((~io_registers[REG_DISPCNT]) & value) & 0x0F00; // these layers are being activated - - io_registers[REG_DISPCNT] = (value & 0xFFF7); // bit 3 can only be accessed by the BIOS to enable GBC mode - UPDATE_REG(0x00, io_registers[REG_DISPCNT]); - - graphics.layerEnable = value; - - if(changeBGon) - { - graphics.layerEnableDelay = 4; - graphics.layerEnable &= ~changeBGon; - } - - windowOn = (graphics.layerEnable & 0x6000) ? true : false; - if(change && !((value & 0x80))) - { - if(!(io_registers[REG_DISPSTAT] & 1)) - { - graphics.lcdTicks = 1008; - io_registers[REG_DISPSTAT] &= 0xFFFC; - UPDATE_REG(0x04, io_registers[REG_DISPSTAT]); - CPUCompareVCOUNT(); - } - } - CPUUpdateRender(); - // we only care about changes in BG0-BG3 - if(changeBG) - { - if(!(graphics.layerEnable & 0x0100)) - memset(line[0], -1, 240 * sizeof(u32)); - if(!(graphics.layerEnable & 0x0200)) - memset(line[1], -1, 240 * sizeof(u32)); - if(!(graphics.layerEnable & 0x0400)) - memset(line[2], -1, 240 * sizeof(u32)); - if(!(graphics.layerEnable & 0x0800)) - memset(line[3], -1, 240 * sizeof(u32)); - } - break; - } - case 0x04: - io_registers[REG_DISPSTAT] = (value & 0xFF38) | (io_registers[REG_DISPSTAT] & 7); - UPDATE_REG(0x04, io_registers[REG_DISPSTAT]); - break; - case 0x06: - // not writable - break; - case 0x08: /* BG0CNT */ - case 0x0A: /* BG1CNT */ - *address_lut[address] = (value & 0xDFCF); - UPDATE_REG(address, *address_lut[address]); - break; - case 0x0C: /* BG2CNT */ - case 0x0E: /* BG3CNT */ - *address_lut[address] = (value & 0xFFCF); - UPDATE_REG(address, *address_lut[address]); - break; - case 0x10: /* BG0HOFS */ - case 0x12: /* BG0VOFS */ - case 0x14: /* BG1HOFS */ - case 0x16: /* BG1VOFS */ - case 0x18: /* BG2HOFS */ - case 0x1A: /* BG2VOFS */ - case 0x1C: /* BG3HOFS */ - case 0x1E: /* BG3VOFS */ - *address_lut[address] = value & 511; - UPDATE_REG(address, *address_lut[address]); - break; - case 0x20: /* BG2PA */ - case 0x22: /* BG2PB */ - case 0x24: /* BG2PC */ - case 0x26: /* BG2PD */ - *address_lut[address] = value; - UPDATE_REG(address, *address_lut[address]); - 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 */ - case 0x32: /* BG3PB */ - case 0x34: /* BG3PC */ - case 0x36: /* BG3PD */ - *address_lut[address] = value; - UPDATE_REG(address, *address_lut[address]); - 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: - io_registers[REG_WIN0H] = value; - UPDATE_REG(0x40, io_registers[REG_WIN0H]); - CPUUpdateWindow0(); - break; - case 0x42: - io_registers[REG_WIN1H] = value; - UPDATE_REG(0x42, io_registers[REG_WIN1H]); - CPUUpdateWindow1(); - break; - case 0x44: - case 0x46: - *address_lut[address] = value; - UPDATE_REG(address, *address_lut[address]); - break; - case 0x48: /* WININ */ - case 0x4A: /* WINOUT */ - *address_lut[address] = value & 0x3F3F; - UPDATE_REG(address, *address_lut[address]); - 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: - { - int gb_addr[2] = {address & 0xFF, (address & 0xFF) + 1}; - uint32_t address_array[2] = {address & 0xFF, (address&0xFF)+1}; - uint8_t data_array[2] = {(uint8_t)(value & 0xFF), (uint8_t)(value>>8)}; - gb_addr[0] = table[gb_addr[0] - 0x60]; - gb_addr[1] = table[gb_addr[1] - 0x60]; - soundEvent_u8_parallel(gb_addr, address_array, data_array); - 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_u16(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; - break; - case 0x102: - timer0Value = value; - timerOnOffDelay|=1; - cpuNextEvent = cpuTotalTicks; - break; - case 0x104: - timer1Reload = value; - 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 0x130: - io_registers[REG_P1] |= (value & 0x3FF); - UPDATE_REG(0x130, io_registers[REG_P1]); - break; - case 0x132: - UPDATE_REG(0x132, value & 0xC3FF); - break; - - - case 0x200: - io_registers[REG_IE] = value & 0x3FFF; - UPDATE_REG(0x200, io_registers[REG_IE]); - if ((io_registers[REG_IME] & 1) && (io_registers[REG_IF] & io_registers[REG_IE]) && armIrqEnable) - cpuNextEvent = cpuTotalTicks; - break; - case 0x202: - io_registers[REG_IF] ^= (value & io_registers[REG_IF]); - UPDATE_REG(0x202, io_registers[REG_IF]); - break; - case 0x204: - { - memoryWait[0x0e] = memoryWaitSeq[0x0e] = gamepakRamWaitState[value & 3]; - - 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; - - memoryWait32[8] = memoryWait[8] + memoryWaitSeq[8] + 1; - memoryWaitSeq32[8] = memoryWaitSeq[8]*2 + 1; - - memoryWait32[9] = memoryWait[9] + memoryWaitSeq[9] + 1; - memoryWaitSeq32[9] = memoryWaitSeq[9]*2 + 1; - - memoryWait32[10] = memoryWait[10] + memoryWaitSeq[10] + 1; - memoryWaitSeq32[10] = memoryWaitSeq[10]*2 + 1; - - memoryWait32[11] = memoryWait[11] + memoryWaitSeq[11] + 1; - memoryWaitSeq32[11] = memoryWaitSeq[11]*2 + 1; - - memoryWait32[12] = memoryWait[12] + memoryWaitSeq[12] + 1; - memoryWaitSeq32[12] = memoryWaitSeq[12]*2 + 1; - - memoryWait32[13] = memoryWait[13] + memoryWaitSeq[13] + 1; - memoryWaitSeq32[13] = memoryWaitSeq[13]*2 + 1; - - memoryWait32[14] = memoryWait[14] + memoryWaitSeq[14] + 1; - memoryWaitSeq32[14] = memoryWaitSeq[14]*2 + 1; - - if((value & 0x4000) == 0x4000) - bus.busPrefetchEnable = true; - else - bus.busPrefetchEnable = false; - - bus.busPrefetch = false; - bus.busPrefetchCount = 0; - - UPDATE_REG(0x204, value & 0x7FFF); - - } - break; - case 0x208: - io_registers[REG_IME] = value & 1; - UPDATE_REG(0x208, io_registers[REG_IME]); - if ((io_registers[REG_IME] & 1) && (io_registers[REG_IF] & io_registers[REG_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 CPUInit(const u8 *biosfile, const u32 biosfilelen) -{ - eepromInUse = false; - switch(cpuSaveType) - { - case 0: // automatic - default: - cpuEEPROMEnabled = true; - cpuEEPROMSensorEnabled = false; - cpuSaveGameFunc = &Gigazoid::flashSaveDecide; // EEPROM usage is automatically detected - break; - case 1: // EEPROM - cpuEEPROMEnabled = true; - cpuEEPROMSensorEnabled = false; - cpuSaveGameFunc = &Gigazoid::dummyWrite; // EEPROM usage is automatically detected - break; - case 2: // SRAM - cpuEEPROMEnabled = false; - cpuEEPROMSensorEnabled = false; - cpuSaveGameFunc = &Gigazoid::sramWrite; - break; - case 3: // FLASH - cpuEEPROMEnabled = false; - cpuEEPROMSensorEnabled = false; - cpuSaveGameFunc = &Gigazoid::flashWrite; - break; - case 4: // EEPROM+Sensor - cpuEEPROMEnabled = true; - cpuEEPROMSensorEnabled = true; - cpuSaveGameFunc = &Gigazoid::dummyWrite; // EEPROM usage is automatically detected - break; - case 5: // NONE - cpuEEPROMEnabled = false; - cpuEEPROMSensorEnabled = false; - cpuSaveGameFunc = &Gigazoid::dummyWrite; - break; - } - - memcpy(bios, biosfile, 16384); - - 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; - } - - 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; - - // what is this? - if(romSize < 0x1fe2000) { - *((uint16_t *)&rom[0x1fe209c]) = 0xdffa; // SWI 0xFA - *((uint16_t *)&rom[0x1fe209e]) = 0x4770; // BX LR - } - - graphics.layerEnable = 0xff00; - graphics.layerEnableDelay = 1; - io_registers[REG_DISPCNT] = 0x0080; - io_registers[REG_DISPSTAT] = 0; - graphics.lcdTicks = (useBios && !skipBios) ? 1008 : 208; - - /* address lut for use in CPUUpdateRegister */ - address_lut[0x08] = &io_registers[REG_BG0CNT]; - address_lut[0x0A] = &io_registers[REG_BG1CNT]; - address_lut[0x0C] = &io_registers[REG_BG2CNT]; - address_lut[0x0E] = &io_registers[REG_BG3CNT]; - address_lut[0x10] = &io_registers[REG_BG0HOFS]; - address_lut[0x12] = &io_registers[REG_BG0VOFS]; - address_lut[0x14] = &io_registers[REG_BG1HOFS]; - address_lut[0x16] = &io_registers[REG_BG1VOFS]; - address_lut[0x18] = &io_registers[REG_BG2HOFS]; - address_lut[0x1A] = &io_registers[REG_BG2VOFS]; - address_lut[0x1C] = &io_registers[REG_BG3HOFS]; - address_lut[0x1E] = &io_registers[REG_BG3VOFS]; - address_lut[0x20] = &io_registers[REG_BG2PA]; - address_lut[0x22] = &io_registers[REG_BG2PB]; - address_lut[0x24] = &io_registers[REG_BG2PC]; - address_lut[0x26] = &io_registers[REG_BG2PD]; - address_lut[0x48] = &io_registers[REG_WININ]; - address_lut[0x4A] = &io_registers[REG_WINOUT]; - address_lut[0x30] = &io_registers[REG_BG3PA]; - address_lut[0x32] = &io_registers[REG_BG3PB]; - address_lut[0x34] = &io_registers[REG_BG3PC]; - address_lut[0x36] = &io_registers[REG_BG3PD]; - address_lut[0x40] = &io_registers[REG_WIN0H]; - address_lut[0x42] = &io_registers[REG_WIN1H]; - address_lut[0x44] = &io_registers[REG_WIN0V]; - address_lut[0x46] = &io_registers[REG_WIN1V]; -} - -void CPUReset (void) -{ - rtcReset(); - memset(&bus.reg[0], 0, sizeof(bus.reg)); // clean registers - memset(oam, 0, 0x400); // clean OAM - memset(graphics.paletteRAM, 0, 0x400); // clean palette - memset(pix, 0, 4 * 160 * 240); // clean picture - memset(vram, 0, 0x20000); // clean vram - memset(ioMem, 0, 0x400); // clean io memory - - io_registers[REG_DISPCNT] = 0x0080; - io_registers[REG_DISPSTAT] = 0x0000; - io_registers[REG_VCOUNT] = (useBios && !skipBios) ? 0 :0x007E; - io_registers[REG_BG0CNT] = 0x0000; - io_registers[REG_BG1CNT] = 0x0000; - io_registers[REG_BG2CNT] = 0x0000; - io_registers[REG_BG3CNT] = 0x0000; - io_registers[REG_BG0HOFS] = 0x0000; - io_registers[REG_BG0VOFS] = 0x0000; - io_registers[REG_BG1HOFS] = 0x0000; - io_registers[REG_BG1VOFS] = 0x0000; - io_registers[REG_BG2HOFS] = 0x0000; - io_registers[REG_BG2VOFS] = 0x0000; - io_registers[REG_BG3HOFS] = 0x0000; - io_registers[REG_BG3VOFS] = 0x0000; - io_registers[REG_BG2PA] = 0x0100; - io_registers[REG_BG2PB] = 0x0000; - io_registers[REG_BG2PC] = 0x0000; - io_registers[REG_BG2PD] = 0x0100; - BG2X_L = 0x0000; - BG2X_H = 0x0000; - BG2Y_L = 0x0000; - BG2Y_H = 0x0000; - io_registers[REG_BG3PA] = 0x0100; - io_registers[REG_BG3PB] = 0x0000; - io_registers[REG_BG3PC] = 0x0000; - io_registers[REG_BG3PD] = 0x0100; - BG3X_L = 0x0000; - BG3X_H = 0x0000; - BG3Y_L = 0x0000; - BG3Y_H = 0x0000; - io_registers[REG_WIN0H] = 0x0000; - io_registers[REG_WIN1H] = 0x0000; - io_registers[REG_WIN0V] = 0x0000; - io_registers[REG_WIN1V] = 0x0000; - io_registers[REG_WININ] = 0x0000; - io_registers[REG_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; - io_registers[REG_TM0D] = 0x0000; - io_registers[REG_TM0CNT] = 0x0000; - io_registers[REG_TM1D] = 0x0000; - io_registers[REG_TM1CNT] = 0x0000; - io_registers[REG_TM2D] = 0x0000; - io_registers[REG_TM2CNT] = 0x0000; - io_registers[REG_TM3D] = 0x0000; - io_registers[REG_TM3CNT] = 0x0000; - io_registers[REG_P1] = 0x03FF; - io_registers[REG_IE] = 0x0000; - io_registers[REG_IF] = 0x0000; - io_registers[REG_IME] = 0x0000; - - armMode = 0x1F; - - if(cpuIsMultiBoot) { - bus.reg[13].I = 0x03007F00; - bus.reg[15].I = 0x02000000; - bus.reg[16].I = 0x00000000; - bus.reg[R13_IRQ].I = 0x03007FA0; - bus.reg[R13_SVC].I = 0x03007FE0; - armIrqEnable = true; - } else { -#ifdef HAVE_HLE_BIOS - if(useBios && !skipBios) - { - bus.reg[15].I = 0x00000000; - armMode = 0x13; - armIrqEnable = false; - } - else - { -#endif - bus.reg[13].I = 0x03007F00; - bus.reg[15].I = 0x08000000; - bus.reg[16].I = 0x00000000; - bus.reg[R13_IRQ].I = 0x03007FA0; - bus.reg[R13_SVC].I = 0x03007FE0; - armIrqEnable = true; -#ifdef HAVE_HLE_BIOS - } -#endif - } - armState = true; - C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false; - UPDATE_REG(0x00, io_registers[REG_DISPCNT]); - UPDATE_REG(0x06, io_registers[REG_VCOUNT]); - UPDATE_REG(0x20, io_registers[REG_BG2PA]); - UPDATE_REG(0x26, io_registers[REG_BG2PD]); - UPDATE_REG(0x30, io_registers[REG_BG3PA]); - UPDATE_REG(0x36, io_registers[REG_BG3PD]); - UPDATE_REG(0x130, io_registers[REG_P1]); - UPDATE_REG(0x88, 0x200); - - // disable FIQ - bus.reg[16].I |= 0x40; - - CPU_UPDATE_CPSR(); - - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 4; - - // reset internal state - holdState = false; - - biosProtected[0] = 0x00; - biosProtected[1] = 0xf0; - biosProtected[2] = 0x29; - biosProtected[3] = 0xe1; - - graphics.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; - renderLine = &Gigazoid::mode0RenderLine; - fxOn = false; - windowOn = false; - graphics.layerEnable = io_registers[REG_DISPCNT]; - - memset(line[0], -1, 240 * sizeof(u32)); - memset(line[1], -1, 240 * sizeof(u32)); - memset(line[2], -1, 240 * sizeof(u32)); - memset(line[3], -1, 240 * sizeof(u32)); - - for(int i = 0; i < 256; i++) { - map[i].address = 0; - 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 = graphics.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(cpuIsMultiBoot) - BIOS_RegisterRamReset(0xfe); - else if(!useBios && !cpuIsMultiBoot) - BIOS_RegisterRamReset(0xff); - else if (skipBios) - BIOS_RegisterRamReset(0xff); // ?? - - ARM_PREFETCH; -} - -void CPUInterrupt(void) -{ - uint32_t PC = bus.reg[15].I; - bool savedState = armState; - - if(armMode != 0x12 ) - CPUSwitchMode(0x12, true, false); - - bus.reg[14].I = PC; - if(!savedState) - bus.reg[14].I += 2; - bus.reg[15].I = 0x18; - armState = true; - armIrqEnable = false; - - bus.armNextPC = bus.reg[15].I; - bus.reg[15].I += 4; - ARM_PREFETCH; - - // if(!holdState) - biosProtected[0] = 0x02; - biosProtected[1] = 0xc0; - biosProtected[2] = 0x5e; - biosProtected[3] = 0xe5; -} - -void CPULoop (void) -{ - bus.busPrefetchCount = 0; - int ticks = 300000; - int timerOverflow = 0; - // variable used by the CPU core - cpuTotalTicks = 0; - - cpuNextEvent = CPUUpdateTicks(); - if(cpuNextEvent > ticks) - cpuNextEvent = ticks; - - bool framedone = false; - - do - { - if(!holdState) - { - if(armState) - { - if (!armExecute()) - return; - } - else - { - if (!thumbExecute()) - return; - } - clockTicks = 0; - } - else - clockTicks = CPUUpdateTicks(); - - cpuTotalTicks += clockTicks; - - - if(cpuTotalTicks >= cpuNextEvent) { - int remainingTicks = cpuTotalTicks - cpuNextEvent; - - clockTicks = cpuNextEvent; - cpuTotalTicks = 0; - -updateLoop: - - if (IRQTicks) - { - IRQTicks -= clockTicks; - if (IRQTicks<0) - IRQTicks = 0; - } - - graphics.lcdTicks -= clockTicks; - - soundTicksUp += clockTicks; - - AdvanceRTC(clockTicks); - - if(graphics.lcdTicks <= 0) - { - if(io_registers[REG_DISPSTAT] & 1) - { // V-BLANK - // if in V-Blank mode, keep computing... - if(io_registers[REG_DISPSTAT] & 2) - { - graphics.lcdTicks += 1008; - io_registers[REG_VCOUNT] += 1; - UPDATE_REG(0x06, io_registers[REG_VCOUNT]); - io_registers[REG_DISPSTAT] &= 0xFFFD; - UPDATE_REG(0x04, io_registers[REG_DISPSTAT]); - CPUCompareVCOUNT(); - } - else - { - graphics.lcdTicks += 224; - io_registers[REG_DISPSTAT] |= 2; - UPDATE_REG(0x04, io_registers[REG_DISPSTAT]); - if(io_registers[REG_DISPSTAT] & 16) - { - io_registers[REG_IF] |= 2; - UPDATE_REG(0x202, io_registers[REG_IF]); - } - if (scanlineCallback && scanlineCallbackLine == io_registers[REG_VCOUNT]) - scanlineCallback(); - } - - if(io_registers[REG_VCOUNT] >= 228) - { - //Reaching last line - io_registers[REG_DISPSTAT] &= 0xFFFC; - UPDATE_REG(0x04, io_registers[REG_DISPSTAT]); - io_registers[REG_VCOUNT] = 0; - UPDATE_REG(0x06, io_registers[REG_VCOUNT]); - CPUCompareVCOUNT(); - } - } - else if(io_registers[REG_DISPSTAT] & 2) - { - // if in H-Blank, leave it and move to drawing mode - io_registers[REG_VCOUNT] += 1; - UPDATE_REG(0x06, io_registers[REG_VCOUNT]); - graphics.lcdTicks += 1008; - io_registers[REG_DISPSTAT] &= 0xFFFD; - if(io_registers[REG_VCOUNT] == 160) - { - // moved to start of emulated frame - //UpdateJoypad(); - - io_registers[REG_DISPSTAT] |= 1; - io_registers[REG_DISPSTAT] &= 0xFFFD; - UPDATE_REG(0x04, io_registers[REG_DISPSTAT]); - if(io_registers[REG_DISPSTAT] & 0x0008) - { - io_registers[REG_IF] |= 1; - UPDATE_REG(0x202, io_registers[REG_IF]); - } - CPUCheckDMA(1, 0x0f); - systemDrawScreen(); - - process_sound_tick_fn(); - framedone = true; - } - - UPDATE_REG(0x04, io_registers[REG_DISPSTAT]); - CPUCompareVCOUNT(); - } - else - { - bool draw_objwin = (graphics.layerEnable & 0x9000) == 0x9000; - bool draw_sprites = graphics.layerEnable & 0x1000; - memset(line[4], -1, 240 * sizeof(u32)); // erase all sprites - - if(draw_sprites) - gfxDrawSprites(); - - if(render_line_all_enabled) - { - memset(line[5], -1, 240 * sizeof(u32)); // erase all OBJ Win - if(draw_objwin) - gfxDrawOBJWin(); - } - - (this->*renderLine)(); - - // entering H-Blank - io_registers[REG_DISPSTAT] |= 2; - UPDATE_REG(0x04, io_registers[REG_DISPSTAT]); - graphics.lcdTicks += 224; - CPUCheckDMA(2, 0x0f); - if(io_registers[REG_DISPSTAT] & 16) - { - io_registers[REG_IF] |= 2; - UPDATE_REG(0x202, io_registers[REG_IF]); - } - if (scanlineCallback && scanlineCallbackLine == io_registers[REG_VCOUNT]) - scanlineCallback(); - } - } - - // we shouldn't be doing sound in stop state, but we lose synchronization - // if sound is disabled, so in stop state, soundTick will just produce - // mute sound - - // moving this may have consequences; we'll see - //soundTicksUp += clockTicks; - - if(!stopState) { - if(timer0On) { - timer0Ticks -= clockTicks; - if(timer0Ticks <= 0) { - timer0Ticks += (0x10000 - timer0Reload) << timer0ClockReload; - timerOverflow |= 1; - soundTimerOverflow(0); - if(io_registers[REG_TM0CNT] & 0x40) { - io_registers[REG_IF] |= 0x08; - UPDATE_REG(0x202, io_registers[REG_IF]); - } - } - io_registers[REG_TM0D] = 0xFFFF - (timer0Ticks >> timer0ClockReload); - UPDATE_REG(0x100, io_registers[REG_TM0D]); - } - - if(timer1On) { - if(io_registers[REG_TM1CNT] & 4) { - if(timerOverflow & 1) { - io_registers[REG_TM1D]++; - if(io_registers[REG_TM1D] == 0) { - io_registers[REG_TM1D] += timer1Reload; - timerOverflow |= 2; - soundTimerOverflow(1); - if(io_registers[REG_TM1CNT] & 0x40) { - io_registers[REG_IF] |= 0x10; - UPDATE_REG(0x202, io_registers[REG_IF]); - } - } - UPDATE_REG(0x104, io_registers[REG_TM1D]); - } - } else { - timer1Ticks -= clockTicks; - if(timer1Ticks <= 0) { - timer1Ticks += (0x10000 - timer1Reload) << timer1ClockReload; - timerOverflow |= 2; - soundTimerOverflow(1); - if(io_registers[REG_TM1CNT] & 0x40) { - io_registers[REG_IF] |= 0x10; - UPDATE_REG(0x202, io_registers[REG_IF]); - } - } - io_registers[REG_TM1D] = 0xFFFF - (timer1Ticks >> timer1ClockReload); - UPDATE_REG(0x104, io_registers[REG_TM1D]); - } - } - - if(timer2On) { - if(io_registers[REG_TM2CNT] & 4) { - if(timerOverflow & 2) { - io_registers[REG_TM2D]++; - if(io_registers[REG_TM2D] == 0) { - io_registers[REG_TM2D] += timer2Reload; - timerOverflow |= 4; - if(io_registers[REG_TM2CNT] & 0x40) { - io_registers[REG_IF] |= 0x20; - UPDATE_REG(0x202, io_registers[REG_IF]); - } - } - UPDATE_REG(0x108, io_registers[REG_TM2D]); - } - } else { - timer2Ticks -= clockTicks; - if(timer2Ticks <= 0) { - timer2Ticks += (0x10000 - timer2Reload) << timer2ClockReload; - timerOverflow |= 4; - if(io_registers[REG_TM2CNT] & 0x40) { - io_registers[REG_IF] |= 0x20; - UPDATE_REG(0x202, io_registers[REG_IF]); - } - } - io_registers[REG_TM2D] = 0xFFFF - (timer2Ticks >> timer2ClockReload); - UPDATE_REG(0x108, io_registers[REG_TM2D]); - } - } - - if(timer3On) { - if(io_registers[REG_TM3CNT] & 4) { - if(timerOverflow & 4) { - io_registers[REG_TM3D]++; - if(io_registers[REG_TM3D] == 0) { - io_registers[REG_TM3D] += timer3Reload; - if(io_registers[REG_TM3CNT] & 0x40) { - io_registers[REG_IF] |= 0x40; - UPDATE_REG(0x202, io_registers[REG_IF]); - } - } - UPDATE_REG(0x10C, io_registers[REG_TM3D]); - } - } else { - timer3Ticks -= clockTicks; - if(timer3Ticks <= 0) { - timer3Ticks += (0x10000 - timer3Reload) << timer3ClockReload; - if(io_registers[REG_TM3CNT] & 0x40) { - io_registers[REG_IF] |= 0x40; - UPDATE_REG(0x202, io_registers[REG_IF]); - } - } - io_registers[REG_TM3D] = 0xFFFF - (timer3Ticks >> timer3ClockReload); - UPDATE_REG(0x10C, io_registers[REG_TM3D]); - } - } - } - - timerOverflow = 0; - ticks -= clockTicks; - cpuNextEvent = CPUUpdateTicks(); - - if(cpuDmaTicksToUpdate > 0) - { - if(cpuDmaTicksToUpdate > cpuNextEvent) - clockTicks = cpuNextEvent; - else - clockTicks = cpuDmaTicksToUpdate; - cpuDmaTicksToUpdate -= clockTicks; - if(cpuDmaTicksToUpdate < 0) - cpuDmaTicksToUpdate = 0; - goto skipIRQ; - } - - if(io_registers[REG_IF] && (io_registers[REG_IME] & 1) && armIrqEnable) - { - int res = io_registers[REG_IF] & io_registers[REG_IE]; - if(stopState) - res &= 0x3080; - if(res) - { - if (intState) - { - if (!IRQTicks) - { - CPUInterrupt(); - intState = false; - holdState = false; - stopState = false; - } - } - else - { - if (!holdState) - { - intState = true; - IRQTicks=7; - if (cpuNextEvent> IRQTicks) - cpuNextEvent = IRQTicks; - } - else - { - CPUInterrupt(); - holdState = false; - stopState = false; - } - } - } - } - - skipIRQ: - - if(remainingTicks > 0) { - if(remainingTicks > cpuNextEvent) - clockTicks = cpuNextEvent; - else - clockTicks = remainingTicks; - remainingTicks -= clockTicks; - if(remainingTicks < 0) - remainingTicks = 0; - goto updateLoop; - } - - if (timerOnOffDelay) - { - // Apply Timer - if (timerOnOffDelay & 1) - { - timer0ClockReload = TIMER_TICKS[timer0Value & 3]; - if(!timer0On && (timer0Value & 0x80)) { - // reload the counter - io_registers[REG_TM0D] = timer0Reload; - timer0Ticks = (0x10000 - io_registers[REG_TM0D]) << timer0ClockReload; - UPDATE_REG(0x100, io_registers[REG_TM0D]); - } - timer0On = timer0Value & 0x80 ? true : false; - io_registers[REG_TM0CNT] = timer0Value & 0xC7; - UPDATE_REG(0x102, io_registers[REG_TM0CNT]); - } - if (timerOnOffDelay & 2) - { - timer1ClockReload = TIMER_TICKS[timer1Value & 3]; - if(!timer1On && (timer1Value & 0x80)) { - // reload the counter - io_registers[REG_TM1D] = timer1Reload; - timer1Ticks = (0x10000 - io_registers[REG_TM1D]) << timer1ClockReload; - UPDATE_REG(0x104, io_registers[REG_TM1D]); - } - timer1On = timer1Value & 0x80 ? true : false; - io_registers[REG_TM1CNT] = timer1Value & 0xC7; - UPDATE_REG(0x106, io_registers[REG_TM1CNT]); - } - if (timerOnOffDelay & 4) - { - timer2ClockReload = TIMER_TICKS[timer2Value & 3]; - if(!timer2On && (timer2Value & 0x80)) { - // reload the counter - io_registers[REG_TM2D] = timer2Reload; - timer2Ticks = (0x10000 - io_registers[REG_TM2D]) << timer2ClockReload; - UPDATE_REG(0x108, io_registers[REG_TM2D]); - } - timer2On = timer2Value & 0x80 ? true : false; - io_registers[REG_TM2CNT] = timer2Value & 0xC7; - UPDATE_REG(0x10A, io_registers[REG_TM2CNT]); - } - if (timerOnOffDelay & 8) - { - timer3ClockReload = TIMER_TICKS[timer3Value & 3]; - if(!timer3On && (timer3Value & 0x80)) { - // reload the counter - io_registers[REG_TM3D] = timer3Reload; - timer3Ticks = (0x10000 - io_registers[REG_TM3D]) << timer3ClockReload; - UPDATE_REG(0x10C, io_registers[REG_TM3D]); - } - timer3On = timer3Value & 0x80 ? true : false; - io_registers[REG_TM3CNT] = timer3Value & 0xC7; - UPDATE_REG(0x10E, io_registers[REG_TM3CNT]); - } - cpuNextEvent = CPUUpdateTicks(); - timerOnOffDelay = 0; - // End of Apply Timer - } - - if(cpuNextEvent > ticks) - cpuNextEvent = ticks; - - if(ticks <= 0 || framedone) - break; - - } - }while(1); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// END GBA.CPP -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void Gigazoid_Init() -{ - // one time constructor stuff - - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - flashSize = 0x10000; - flashDeviceID = 0x1b; - flashManufacturerID = 0x32; - flashBank = 0; - - eepromMode = EEPROM_IDLE; - - eepromInUse = false; - eepromSize = 512; - - // this is constant now - // soundSampleRate = 22050; - - soundEnableFlag = 0x3ff; /* emulator channels enabled*/ - - armState = true; - armIrqEnable = true; - armMode = 0x1f; - - renderLine = &Gigazoid::mode0RenderLine; - - #define ARRAYINIT(n) memcpy((n), (n##_init), sizeof(n)) - ARRAYINIT(memoryWait); - ARRAYINIT(memoryWaitSeq); - ARRAYINIT(memoryWait32); - ARRAYINIT(memoryWaitSeq32); - #undef ARRAYINIT -} - -u32 *systemVideoFrameDest; -u32 *systemVideoFramePalette; -s16 *systemAudioFrameDest; -int *systemAudioFrameSamp; -bool lagged; - -void (*scanlineCallback)(); -int scanlineCallbackLine; - -void (*fetchCallback)(u32 addr); -void (*writeCallback)(u32 addr); -void (*readCallback)(u32 addr); -void (*traceCallback)(u32 addr, u32 opcode); - -void (*padCallback)(); - -void systemDrawScreen (void) -{ - // upconvert 555->888 (TODO: BETTER) - for (int i = 0; i < 240 * 160; i++) - { - u32 input = pix[i]; - /* - u32 output = 0xff000000 | - input << 9 & 0xf80000 | - input << 6 & 0xf800 | - input << 3 & 0xf8; - */ - u32 output = systemVideoFramePalette[input]; - systemVideoFrameDest[i] = output; - } - systemVideoFrameDest = nullptr; - systemVideoFramePalette = nullptr; -} - -// called at regular intervals on sound clock -void systemOnWriteDataToSoundBuffer(int16_t * finalWave, int length) -{ - memcpy(systemAudioFrameDest, finalWave, length * 2); - systemAudioFrameDest = nullptr; - *systemAudioFrameSamp = length / 2; - systemAudioFrameSamp = nullptr; -} - -void UpdateJoypad() -{ - /* update joystick information */ - io_registers[REG_P1] = 0x03FF ^ (joy & 0x3FF); -#if 0 - if(cpuEEPROMSensorEnabled) - systemUpdateMotionSensor(); -#endif - UPDATE_REG(0x130, io_registers[REG_P1]); - io_registers[REG_P1CNT] = READ16LE(((uint16_t *)&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((io_registers[REG_P1CNT] & 0x4000) || stopState) { - uint16_t p1 = (0x3FF ^ io_registers[REG_P1CNT]) & 0x3FF; - if(io_registers[REG_P1CNT] & 0x8000) { - if(p1 == (io_registers[REG_P1CNT] & 0x3FF)) { - io_registers[REG_IF] |= 0x1000; - UPDATE_REG(0x202, io_registers[REG_IF]); - } - } else { - if(p1 & io_registers[REG_P1CNT]) { - io_registers[REG_IF] |= 0x1000; - UPDATE_REG(0x202, io_registers[REG_IF]); - } - } - } -} - -public: - -templatevoid SyncState(NewState *ns) -{ - NSS(flashSaveMemory); - NSS(flashState); - NSS(flashReadState); - NSS(flashSize); - NSS(flashDeviceID); - NSS(flashManufacturerID); - NSS(flashBank); - - NSS(eepromMode); - NSS(eepromByte); - NSS(eepromBits); - NSS(eepromAddress); - NSS(eepromData); - NSS(eepromBuffer); - NSS(eepromInUse); - NSS(eepromSize); - - NSS(rtcClockData); - NSS(rtcEnabled); - SSS(rtcInternalTime); - NSS(RTCTicks); - NSS(RTCUseRealTime); - - NSS(soundTicksUp); - NSS(soundEnableFlag); - SSS_HACKY(pcm[0], this); - SSS_HACKY(pcm[1], this); - SSS(pcm_synth); - - SSS(bufs_buffer[0]); - SSS(bufs_buffer[1]); - SSS(bufs_buffer[2]); - NSS(mixer_samples_read); - - SSS(gb_apu); - - NSS(cpuNextEvent); - NSS(holdState); - NSS(cpuPrefetch); - NSS(cpuTotalTicks); - NSS(memoryWait); - NSS(memoryWaitSeq); - NSS(memoryWait32); - NSS(memoryWaitSeq32); - NSS(biosProtected); - NSS(cpuBitsSet); - - NSS(N_FLAG); - NSS(C_FLAG); - NSS(Z_FLAG); - NSS(V_FLAG); - NSS(armState); - NSS(armIrqEnable); - NSS(armMode); - - NSS(io_registers); - - NSS(MOSAIC); - - NSS(BG2X_L); - NSS(BG2X_H); - NSS(BG2Y_L); - NSS(BG2Y_H); - NSS(BG3X_L); - NSS(BG3X_H); - NSS(BG3Y_L); - NSS(BG3Y_H); - NSS(BLDMOD); - NSS(COLEV); - NSS(COLY); - NSS(DM0SAD_L); - NSS(DM0SAD_H); - NSS(DM0DAD_L); - NSS(DM0DAD_H); - NSS(DM0CNT_L); - NSS(DM0CNT_H); - NSS(DM1SAD_L); - NSS(DM1SAD_H); - NSS(DM1DAD_L); - NSS(DM1DAD_H); - NSS(DM1CNT_L); - NSS(DM1CNT_H); - NSS(DM2SAD_L); - NSS(DM2SAD_H); - NSS(DM2DAD_L); - NSS(DM2DAD_H); - NSS(DM2CNT_L); - NSS(DM2CNT_H); - NSS(DM3SAD_L); - NSS(DM3SAD_H); - NSS(DM3DAD_L); - NSS(DM3DAD_H); - NSS(DM3CNT_L); - NSS(DM3CNT_H); - - NSS(timerOnOffDelay); - NSS(timer0Value); - NSS(dma0Source); - NSS(dma0Dest); - NSS(dma1Source); - NSS(dma1Dest); - NSS(dma2Source); - NSS(dma2Dest); - NSS(dma3Source); - NSS(dma3Dest); - - EBS(cpuSaveGameFunc, 0); - EVS(cpuSaveGameFunc, &Gigazoid::flashWrite, 1); - EVS(cpuSaveGameFunc, &Gigazoid::sramWrite, 2); - EVS(cpuSaveGameFunc, &Gigazoid::flashSaveDecide, 3); - EVS(cpuSaveGameFunc, &Gigazoid::dummyWrite, 4); - EES(cpuSaveGameFunc, nullptr); - - NSS(fxOn); - NSS(windowOn); - NSS(cpuDmaTicksToUpdate); - NSS(IRQTicks); - NSS(intState); - - NSS(bus); - NSS(graphics); - - // map; // values never change - - NSS(clockTicks); - - NSS(romSize); - NSS(line); - NSS(gfxInWin); - NSS(lineOBJpixleft); - NSS(joy); - - NSS(gfxBG2Changed); - NSS(gfxBG3Changed); - - NSS(gfxBG2X); - NSS(gfxBG2Y); - NSS(gfxBG3X); - NSS(gfxBG3Y); - - NSS(ioReadable); - - NSS(stopState); - - NSS(timer0On); - NSS(timer0Ticks); - NSS(timer0Reload); - NSS(timer0ClockReload); - NSS(timer1Value); - NSS(timer1On); - NSS(timer1Ticks); - NSS(timer1Reload); - NSS(timer1ClockReload); - NSS(timer2Value); - NSS(timer2On); - NSS(timer2Ticks); - NSS(timer2Reload); - NSS(timer2ClockReload); - NSS(timer3Value); - NSS(timer3On); - NSS(timer3Ticks); - NSS(timer3Reload); - NSS(timer3ClockReload); - - NSS(skipBios); - NSS(cpuSaveType); - NSS(mirroringEnable); - - NSS(cpuDmaCount); - - NSS(internalRAM); - NSS(workRAM); - NSS(vram); - NSS(pix); - NSS(oam); - NSS(ioMem); - - NSS(cpuEEPROMEnabled); - NSS(cpuEEPROMSensorEnabled); - - EBS(renderLine, 0); - EVS(renderLine, &Gigazoid::mode0RenderLine, 0x01); - EVS(renderLine, &Gigazoid::mode0RenderLineNoWindow, 0x02); - EVS(renderLine, &Gigazoid::mode0RenderLineAll, 0x03); - EVS(renderLine, &Gigazoid::mode1RenderLine, 0x11); - EVS(renderLine, &Gigazoid::mode1RenderLineNoWindow, 0x12); - EVS(renderLine, &Gigazoid::mode1RenderLineAll, 0x13); - EVS(renderLine, &Gigazoid::mode2RenderLine, 0x21); - EVS(renderLine, &Gigazoid::mode2RenderLineNoWindow, 0x22); - EVS(renderLine, &Gigazoid::mode2RenderLineAll, 0x23); - EVS(renderLine, &Gigazoid::mode3RenderLine, 0x31); - EVS(renderLine, &Gigazoid::mode3RenderLineNoWindow, 0x32); - EVS(renderLine, &Gigazoid::mode3RenderLineAll, 0x33); - EVS(renderLine, &Gigazoid::mode4RenderLine, 0x41); - EVS(renderLine, &Gigazoid::mode4RenderLineNoWindow, 0x42); - EVS(renderLine, &Gigazoid::mode4RenderLineAll, 0x43); - EVS(renderLine, &Gigazoid::mode5RenderLine, 0x51); - EVS(renderLine, &Gigazoid::mode5RenderLineNoWindow, 0x52); - EVS(renderLine, &Gigazoid::mode5RenderLineAll, 0x53); - EES(renderLine, nullptr); - - NSS(render_line_all_enabled); - - // address_lut; // values never change - - NSS(lagged); -} - -// load a legacy battery ram file to a place where it might work, who knows -void LoadLegacyBatteryRam(const char *data, int len) -{ - std::memcpy(eepromData, data, std::min(len, sizeof(eepromData))); - std::memcpy(flashSaveMemory, data, std::min(len, sizeof(flashSaveMemory))); - if (len <= 0x10000) - { - // can salvage broken pokeymans saves in some cases - std::memcpy(flashSaveMemory + 0x10000, data, std::min(len, 0x10000)); - } -} - -bool HasBatteryRam() -{ - return cpuSaveType != 5; -} - -int BatteryRamSize() -{ - switch (cpuSaveType) - { - default: - case 0: // auto - return 0x10000; - case 1: - case 4: // eeprom - return eepromSize; - case 2: // sram - // should only be 32K, but vba uses 64K as a stand-in for both SRAM (guess no game ever checks mirroring?), - // and for 64K flash where the program never issues any flash commands - return 0x10000; - case 3: // flash - return flashSize; - case 5: // none - return 0; - } -} - -void SaveLegacyBatteryRam(char *dest) -{ - switch (cpuSaveType) - { - default: - case 0: // auto - std::memcpy(dest, flashSaveMemory, 0x10000); - return; - case 1: - case 4: // eeprom - std::memcpy(dest, eepromData, eepromSize); - return; - case 2: // sram - // should only be 32K, but vba uses 64K as a stand-in for both SRAM (guess no game ever checks mirroring?), - // and for 64K flash where the program never issues any flash commands - std::memcpy(dest, flashSaveMemory, 0x10000); - return; - case 3: // flash - std::memcpy(dest, flashSaveMemory, flashSize); - return; - case 5: // none - return; - } -} - -templatebool SyncBatteryRam(NewState *ns) -{ - // if we were given a positive ID from the gamedb, we can choose to save/load only that type - // else, we save\load everything -- even if we used our knowledge of the current state to - // save only what was needed, we'd have to save that metadata as well for load - - // file id detection - char batteryramid[8]; - std::memcpy(batteryramid, "GBABATT\0", 8); - NSS(batteryramid); - if (std::memcmp(batteryramid, "GBABATT\0", 8) != 0) - return false; - - int flashFileSize; - int eepromFileSize; - - // when writing, try to figure out the sizes as smartly as we can - switch (cpuSaveType) - { - default: - case 0: // auto - flashFileSize = 0x20000; - eepromFileSize = 0x2000; - break; - case 1: - case 4: // eeprom - flashFileSize = 0; - eepromFileSize = eepromSize; - break; - case 2: // sram - // should only be 32K, but vba uses 64K as a stand-in for both SRAM (guess no game ever checks mirroring?), - // and for 64K flash where the program never issues any flash commands - flashFileSize = 0x10000; - eepromFileSize = 0; - break; - case 3: // flash - flashFileSize = flashSize; - eepromFileSize = 0; - break; - case 5: // none - flashFileSize = 0; - eepromFileSize = 0; - break; - } - NSS(flashFileSize); - NSS(eepromFileSize); - // when reading, cap to allowable limits. any save file with numbers larger than this is not legal. - flashFileSize = std::min(flashFileSize, sizeof(flashSaveMemory)); - eepromFileSize = std::min(eepromFileSize, sizeof(eepromData)); - - PSS(flashSaveMemory, flashFileSize); - PSS(eepromData, eepromFileSize); - - return true; -} - - Gigazoid() - { - Gigazoid_Init(); - } - - ~Gigazoid() - { - } - - bool LoadRom(const u8 *romfile, const u32 romfilelen, const u8 *biosfile, const u32 biosfilelen, const FrontEndSettings &settings) - { - if (biosfilelen != 16384) - return false; - - if (!CPULoadRom(romfile, romfilelen)) - return false; - - cpuSaveType = settings.cpuSaveType; - flashSize = settings.flashSize; - rtcEnabled = settings.enableRtc; - mirroringEnable = settings.mirroringEnable; - skipBios = settings.skipBios; - - RTCUseRealTime = settings.RTCuseRealTime; - rtcInternalTime.hour = settings.RTChour; - rtcInternalTime.mday = settings.RTCmday; - rtcInternalTime.min = settings.RTCmin; - rtcInternalTime.month = settings.RTCmonth; - rtcInternalTime.sec = settings.RTCsec; - rtcInternalTime.wday = settings.RTCwday; - rtcInternalTime.year = settings.RTCyear; - - if(flashSize == 0x10000) - { - flashDeviceID = 0x1b; - flashManufacturerID = 0x32; - } - else - { - flashDeviceID = 0x13; //0x09; - flashManufacturerID = 0x62; //0xc2; - } - - doMirroring(mirroringEnable); - - CPUInit(biosfile, biosfilelen); - CPUReset(); - - // CPUReset already calls this, but if that were to change - // soundReset(); - - return true; - } - - void Reset() - { - CPUReset(); - } - - bool FrameAdvance(int input, u32 *videobuffer, s16 *audiobuffer, int *numsamp, u32 *videopalette) - { - joy = input; - systemVideoFrameDest = videobuffer; - systemVideoFramePalette = videopalette; - systemAudioFrameDest = audiobuffer; - systemAudioFrameSamp = numsamp; - lagged = true; - UpdateJoypad(); - do - { - CPULoop(); - } while (systemVideoFrameDest); - return lagged; - } - - void FillMemoryAreas(MemoryAreas &mem) - { - mem.bios = bios; - mem.iwram = internalRAM; - mem.ewram = workRAM; - mem.palram = graphics.paletteRAM; - mem.mmio = ioMem; - mem.rom = rom; - mem.vram = vram; - mem.oam = oam; - switch (cpuSaveType) - { - default: - case 0: // auto - mem.sram = flashSaveMemory; - mem.sram_size = 0x10000;; - return; - case 1: - case 4: // eeprom - mem.sram = eepromData; - mem.sram_size = eepromSize; - return; - case 2: // sram - mem.sram = flashSaveMemory; - mem.sram_size = 0x10000; - return; - case 3: // flash - mem.sram = flashSaveMemory; - mem.sram_size = flashSize; - return; - case 5: // none - return; - } - } - - void BusWrite(u32 addr, u8 val) - { - CPUWriteByte(addr, val); - } - u8 BusRead(u32 addr) - { - return CPUReadByte(addr); - } - - void SetScanlineCallback(void (*cb)(), int scanline) - { - // the sequence of calls in a frame will be: - // 160,161,...,227,0,1,...,160 - // calls coincide with entering hblank, or something like that - if (scanline < 0 || scanline > 227) - cb = nullptr; - scanlineCallback = cb; - scanlineCallbackLine = scanline; - } - - uint32_t *GetRegisters() - { - return &bus.reg[0].I; - } - - void SetPadCallback(void (*cb)()) - { - // before each read of the pad regs - padCallback = cb; - } - - void SetFetchCallback(void (*cb)(u32 addr)) - { - // before each opcode fetch - fetchCallback = cb; - } - - void SetReadCallback(void (*cb)(u32 addr)) - { - // before each read, not including opcodes, including pad regs - readCallback = cb; - } - - void SetWriteCallback(void (*cb)(u32 addr)) - { - // before each write - writeCallback = cb; - } - - void SetTraceCallback(void (*cb)(u32 addr, u32 opcode)) - { - // before each opcode fetch - traceCallback = cb; - } - -}; // class Gigazoid - -// zeroing mem operators: these are very important -void *operator new(std::size_t n) -{ - void *p = std::malloc(n); - std::memset(p, 0, n); - return p; -} -void operator delete(void *p) -{ - std::free(p); -} - -#ifdef _WIN32 -#define EXPORT extern "C" __declspec(dllexport) -#elif __linux__ -#define EXPORT extern "C" -#endif - -// public interface follows -EXPORT Gigazoid *Create() -{ - return new Gigazoid(); -} - -EXPORT void Destroy(Gigazoid *g) -{ - delete g; -} - -EXPORT int LoadRom(Gigazoid *g, const u8 *romfile, const u32 romfilelen, const u8 *biosfile, const u32 biosfilelen, const FrontEndSettings *settings) -{ - return g->LoadRom(romfile, romfilelen, biosfile, biosfilelen, *settings); -} - -EXPORT void Reset(Gigazoid *g) -{ - // TODO: this calls a soundreset that seems to remake some buffers. that seems like it should be fixed? - g->Reset(); -} - -EXPORT int FrameAdvance(Gigazoid *g, int input, u32 *videobuffer, s16 *audiobuffer, int *numsamp, u32 *videopalette) -{ - return g->FrameAdvance(input, videobuffer, audiobuffer, numsamp, videopalette); -} - -EXPORT int SaveRamSize(Gigazoid *g) -{ - /* - if (g->HasBatteryRam()) - { - NewStateDummy dummy; - g->SyncBatteryRam(&dummy); - return dummy.GetLength(); - } - else - { - return 0; - }*/ - return g->BatteryRamSize(); -} - -EXPORT int SaveRamSave(Gigazoid *g, char *data, int length) -{ - /* - if (g->HasBatteryRam()) - { - NewStateExternalBuffer saver(data, length); - g->SyncBatteryRam(&saver); - return !saver.Overflow() && saver.GetLength() == length; - } - else - { - return false; - }*/ - if (!g->HasBatteryRam() || length != g->BatteryRamSize()) - return false; - g->SaveLegacyBatteryRam(data); - return true; -} - -EXPORT int SaveRamLoad(Gigazoid *g, const char *data, int length) -{ - if (g->HasBatteryRam()) - { - NewStateExternalBuffer loader(const_cast(data), length); - if (g->SyncBatteryRam(&loader)) - { - return !loader.Overflow() && loader.GetLength() == length; - } - else - { - // couldn't find the magic signature at the top, so try a salvage load - g->LoadLegacyBatteryRam(data, length); - return true; - } - } - else - { - return false; - } -} - -EXPORT int BinStateSize(Gigazoid *g) -{ - NewStateDummy dummy; - g->SyncState(&dummy); - return dummy.GetLength(); -} - -EXPORT int BinStateSave(Gigazoid *g, char *data, int length) -{ - NewStateExternalBuffer saver(data, length); - g->SyncState(&saver); - return !saver.Overflow() && saver.GetLength() == length; -} - -EXPORT int BinStateLoad(Gigazoid *g, const char *data, int length) -{ - NewStateExternalBuffer loader(const_cast(data), length); - g->SyncState(&loader); - return !loader.Overflow() && loader.GetLength() == length; -} - -EXPORT void TxtStateSave(Gigazoid *g, FPtrs *ff) -{ - NewStateExternalFunctions saver(ff); - g->SyncState(&saver); -} - -EXPORT void TxtStateLoad(Gigazoid *g, FPtrs *ff) -{ - NewStateExternalFunctions loader(ff); - g->SyncState(&loader); -} - -EXPORT void GetMemoryAreas(Gigazoid *g, MemoryAreas *mem) -{ - g->FillMemoryAreas(*mem); -} - -EXPORT void SystemBusWrite(Gigazoid *g, u32 addr, u8 val) -{ - g->BusWrite(addr, val); -} - -EXPORT u8 SystemBusRead(Gigazoid *g, u32 addr) -{ - return g->BusRead(addr); -} - -EXPORT void SetScanlineCallback(Gigazoid *g, void (*cb)(), int scanline) -{ - g->SetScanlineCallback(cb, scanline); -} - -EXPORT void SetTraceCallback(Gigazoid *g, void (*cb)(u32 addr, u32 opcode)) -{ - g->SetTraceCallback(cb); -} - -EXPORT u32 *GetRegisters(Gigazoid *g) -{ - return g->GetRegisters(); -} - -EXPORT void SetPadCallback(Gigazoid *g, void (*cb)()) { g->SetPadCallback(cb); } -EXPORT void SetFetchCallback(Gigazoid *g, void (*cb)(u32 addr)) { g->SetFetchCallback(cb); } -EXPORT void SetReadCallback(Gigazoid *g, void (*cb)(u32 addr)) { g->SetReadCallback(cb); } -EXPORT void SetWriteCallback(Gigazoid *g, void (*cb)(u32 addr)) { g->SetWriteCallback(cb); } - - -#include "optable.inc" diff --git a/vbanext/instance.h b/vbanext/instance.h deleted file mode 100644 index 3139a854ba..0000000000 --- a/vbanext/instance.h +++ /dev/null @@ -1,227 +0,0 @@ -#ifndef INSTANCE_H -#define INSTANCE_H - -struct FrontEndSettings -{ - int cpuSaveType; // [0auto] 1eeprom 2sram 3flash 4eeprom+sensor 5none - int flashSize; // [0x10000] 0x20000 - int enableRtc; // [false] true - int mirroringEnable; // [false] true - int skipBios; // [false] true - - int RTCuseRealTime; - int RTCyear; // 00..99 - int RTCmonth; // 00..11 - int RTCmday; // 01..31 - int RTCwday; // 00..06 - int RTChour; // 00..23 - int RTCmin; // 00..59 - int RTCsec; // 00..59 - -}; - -struct MemoryAreas -{ - void *bios; - void *iwram; - void *ewram; - void *palram; - void *vram; - void *oam; - void *rom; - void *mmio; - void *sram; - uint32_t sram_size; -}; - -#define FLASH_128K_SZ 0x20000 - -#define EEPROM_IDLE 0 -#define EEPROM_READADDRESS 1 -#define EEPROM_READDATA 2 -#define EEPROM_READDATA2 3 -#define EEPROM_WRITEDATA 4 - -enum { - IMAGE_UNKNOWN, - IMAGE_GBA -}; - -#define SGCNT0_H 0x82 -#define FIFOA_L 0xa0 -#define FIFOA_H 0xa2 -#define FIFOB_L 0xa4 -#define FIFOB_H 0xa6 - -#define BLIP_BUFFER_ACCURACY 16 -#define BLIP_PHASE_BITS 8 -#define BLIP_WIDEST_IMPULSE_ 16 -#define BLIP_BUFFER_EXTRA_ 18 -#define BLIP_RES 256 -#define BLIP_RES_MIN_ONE 255 -#define BLIP_SAMPLE_BITS 30 -#define BLIP_READER_DEFAULT_BASS 9 -#define BLIP_DEFAULT_LENGTH 250 /* 1/4th of a second */ - -#define BUFS_SIZE 3 -#define STEREO 2 - -#define CLK_MUL GB_APU_OVERCLOCK -#define CLK_MUL_MUL_2 8 -#define CLK_MUL_MUL_4 16 -#define CLK_MUL_MUL_6 24 -#define CLK_MUL_MUL_8 32 -#define CLK_MUL_MUL_15 60 -#define CLK_MUL_MUL_32 128 -#define DAC_BIAS 7 - -#define PERIOD_MASK 0x70 -#define SHIFT_MASK 0x07 - -#define PERIOD2_MASK 0x1FFFF - -#define BANK40_MASK 0x40 -#define BANK_SIZE 32 -#define BANK_SIZE_MIN_ONE 31 -#define BANK_SIZE_DIV_TWO 16 - -/* 11-bit frequency in NRx3 and NRx4*/ -#define GB_OSC_FREQUENCY() (((regs[4] & 7) << 8) + regs[3]) - -#define WAVE_TYPE 0x100 -#define NOISE_TYPE 0x200 -#define MIXED_TYPE WAVE_TYPE | NOISE_TYPE -#define TYPE_INDEX_MASK 0xFF - -#define BITS_16 0 -#define BITS_32 1 - -#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 - -typedef struct { - uint8_t *address; - uint32_t mask; -} memoryMap; - -typedef union { - struct { -#ifdef LSB_FIRST - uint8_t B0; - uint8_t B1; - uint8_t B2; - uint8_t B3; -#else - uint8_t B3; - uint8_t B2; - uint8_t B1; - uint8_t B0; -#endif - } B; - struct { -#ifdef LSB_FIRST - uint16_t W0; - uint16_t W1; -#else - uint16_t W1; - uint16_t W0; -#endif - } W; -#ifdef LSB_FIRST - uint32_t I; -#else - volatile uint32_t I; -#endif -} reg_pair; - -typedef struct -{ - reg_pair reg[45]; - bool busPrefetch; - bool busPrefetchEnable; - uint32_t busPrefetchCount; - uint32_t armNextPC; -} bus_t; - -typedef struct -{ - uint8_t paletteRAM[0x400]; - int layerEnable; - int layerEnableDelay; - int lcdTicks; -} graphics_t; - -/* Begins reading from buffer. Name should be unique to the current block.*/ -#define BLIP_READER_BEGIN( name, blip_buffer ) \ - const int32_t * name##_reader_buf = (blip_buffer).buffer_;\ - int32_t name##_reader_accum = (blip_buffer).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) - -#define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset) - -#define BLIP_READER_NEXT_IDX_( name, idx ) {\ - name##_reader_accum -= name##_reader_accum >> BLIP_READER_DEFAULT_BASS;\ - name##_reader_accum += name##_reader_buf [(idx)];\ -} - -#define BLIP_READER_NEXT_RAW_IDX_( name, idx ) {\ - name##_reader_accum -= name##_reader_accum >> BLIP_READER_DEFAULT_BASS; \ - name##_reader_accum += *(int32_t const*) ((char const*) name##_reader_buf + (idx)); \ -} - -#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 ) (int16_t) in != in -#endif - -/* Clamp sample to int16_t range */ -#define BLIP_CLAMP( sample, out ) { if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 24) ^ 0x7FFF; } -#define GB_ENV_DAC_ENABLED() (regs[2] & 0xF8) /* Non-zero if DAC is enabled*/ -#define GB_NOISE_PERIOD2_INDEX() (regs[3] >> 4) -#define GB_NOISE_PERIOD2(base) (base << GB_NOISE_PERIOD2_INDEX()) -#define GB_NOISE_LFSR_MASK() ((regs[3] & 0x08) ? ~0x4040 : ~0x4000) -#define GB_WAVE_DAC_ENABLED() (regs[0] & 0x80) /* Non-zero if DAC is enabled*/ - -#define reload_sweep_timer() \ - sweep_delay = (regs [0] & PERIOD_MASK) >> 4; \ - if ( !sweep_delay ) \ - sweep_delay = 8; - - -#ifdef __LIBRETRO__ -#define PIX_BUFFER_SCREEN_WIDTH 256 -#else -#define PIX_BUFFER_SCREEN_WIDTH 240 -#endif - -#endif diff --git a/vbanext/mingw/Makefile b/vbanext/mingw/Makefile deleted file mode 100644 index 05f14773d1..0000000000 --- a/vbanext/mingw/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -CXX = g++ -CXXFLAGS = -Wall -O3 -fpermissive -Wno-unused-but-set-variable \ - -Wno-strict-aliasing -Wzero-as-null-pointer-constant -Wno-unused-variable \ - -Wno-parentheses -Wno-sign-compare -std=gnu++11 -fomit-frame-pointer -fno-exceptions -fPIC - -MACHINE = $(shell $(CXX) -dumpmachine) -ifneq (,$(findstring i686,$(MACHINE))) - $(error 32 bit build no longer supported) -else ifneq (,$(findstring x86_64,$(MACHINE))) - ARCH = 64 -else - $(error Unknown arch) -endif - -LDFLAGS_32 = -static-libgcc -static-libstdc++ -LDFLAGS_64 = -LDFLAGS = -shared $(LDFLAGS_$(ARCH)) $(CXXFLAGS) - -TARGET = libvbanext.dll -RM = rm -CP = cp - -SRCS = \ - ../instance.cpp \ - ../newstate.cpp - -OBJS = $(SRCS:.cpp=.o) -DEST_32 = ../../output/dll -DEST_64 = ../../output/dll - -all: $(TARGET) - -%.o: %.cpp - $(CXX) -c -o $@ $< $(CXXFLAGS) - -$(TARGET) : $(OBJS) - $(CXX) -o $@ $(LDFLAGS) $(OBJS) - -clean: - $(RM) $(OBJS) - $(RM) $(TARGET) - -install: - $(CP) $(TARGET) $(DEST_$(ARCH)) diff --git a/vbanext/msvs/libvbanext/libvbanext.sln b/vbanext/msvs/libvbanext/libvbanext.sln deleted file mode 100644 index 3b47db7b92..0000000000 --- a/vbanext/msvs/libvbanext/libvbanext.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libvbanext", "libvbanext.vcxproj", "{DE666222-17A4-4B1E-8A5A-0A69838AE23F}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DE666222-17A4-4B1E-8A5A-0A69838AE23F}.Debug|Win32.ActiveCfg = Debug|Win32 - {DE666222-17A4-4B1E-8A5A-0A69838AE23F}.Debug|Win32.Build.0 = Debug|Win32 - {DE666222-17A4-4B1E-8A5A-0A69838AE23F}.Release|Win32.ActiveCfg = Release|Win32 - {DE666222-17A4-4B1E-8A5A-0A69838AE23F}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/vbanext/msvs/libvbanext/libvbanext.vcxproj b/vbanext/msvs/libvbanext/libvbanext.vcxproj deleted file mode 100644 index c2e55b1d9c..0000000000 --- a/vbanext/msvs/libvbanext/libvbanext.vcxproj +++ /dev/null @@ -1,90 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {DE666222-17A4-4B1E-8A5A-0A69838AE23F} - libvbanext - - - - DynamicLibrary - true - MultiByte - - - DynamicLibrary - false - true - MultiByte - - - - - - - - - - - - - - - Level3 - Disabled - 4146;4800 - - - true - - - copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\..\..\output\dll\$(TargetFileName) - - - - - Level3 - Full - true - true - 4146;4800 - AnySuitable - true - - - true - true - true - - - copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\..\..\output\dll\$(TargetFileName) - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vbanext/msvs/libvbanext/libvbanext.vcxproj.filters b/vbanext/msvs/libvbanext/libvbanext.vcxproj.filters deleted file mode 100644 index 17408fd5f3..0000000000 --- a/vbanext/msvs/libvbanext/libvbanext.vcxproj.filters +++ /dev/null @@ -1,53 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {25bb448a-4359-4425-bc82-a36c2dcddcb8} - - - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Header Files - - - \ No newline at end of file diff --git a/vbanext/newstate.cpp b/vbanext/newstate.cpp deleted file mode 100644 index 1b356e3a86..0000000000 --- a/vbanext/newstate.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "newstate.h" -#include - -NewStateDummy::NewStateDummy() - :length(0) -{ -} -void NewStateDummy::Save(const void *ptr, size_t size, const char *name) -{ - length += size; -} -void NewStateDummy::Load(void *ptr, size_t size, const char *name) -{ -} - -NewStateExternalBuffer::NewStateExternalBuffer(char *buffer, long maxlength) - :buffer(buffer), length(0), maxlength(maxlength) -{ -} - -void NewStateExternalBuffer::Save(const void *ptr, size_t size, const char *name) -{ - if (maxlength - length >= (long)size) - { - std::memcpy(buffer + length, ptr, size); - } - length += size; -} - -void NewStateExternalBuffer::Load(void *ptr, size_t size, const char *name) -{ - char *dst = static_cast(ptr); - if (maxlength - length >= (long)size) - { - std::memcpy(dst, buffer + length, size); - } - length += size; -} - -NewStateExternalFunctions::NewStateExternalFunctions(const FPtrs *ff) - :Save_(ff->Save_), - Load_(ff->Load_), - EnterSection_(ff->EnterSection_), - ExitSection_(ff->ExitSection_) -{ -} - -void NewStateExternalFunctions::Save(const void *ptr, size_t size, const char *name) -{ - Save_(ptr, size, name); -} -void NewStateExternalFunctions::Load(void *ptr, size_t size, const char *name) -{ - Load_(ptr, size, name); -} -void NewStateExternalFunctions::EnterSection(const char *name) -{ - EnterSection_(name); -} -void NewStateExternalFunctions::ExitSection(const char *name) -{ - ExitSection_(name); -} - diff --git a/vbanext/newstate.h b/vbanext/newstate.h deleted file mode 100644 index 2f0f75f8ef..0000000000 --- a/vbanext/newstate.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef NEWSTATE_H -#define NEWSTATE_H - -#include -#include - -class NewState -{ -public: - virtual void Save(const void *ptr, size_t size, const char *name) = 0; - virtual void Load(void *ptr, size_t size, const char *name) = 0; - virtual void EnterSection(const char *name) { } - virtual void ExitSection(const char *name) { } -}; - -class NewStateDummy : public NewState -{ -private: - long length; -public: - NewStateDummy(); - long GetLength() { return length; } - void Rewind() { length = 0; } - virtual void Save(const void *ptr, size_t size, const char *name); - virtual void Load(void *ptr, size_t size, const char *name); -}; - -class NewStateExternalBuffer : public NewState -{ -private: - char *const buffer; - long length; - const long maxlength; -public: - NewStateExternalBuffer(char *buffer, long maxlength); - long GetLength() { return length; } - void Rewind() { length = 0; } - bool Overflow() { return length > maxlength; } - virtual void Save(const void *ptr, size_t size, const char *name); - virtual void Load(void *ptr, size_t size, const char *name); -}; - -struct FPtrs -{ - void (*Save_)(const void *ptr, size_t size, const char *name); - void (*Load_)(void *ptr, size_t size, const char *name); - void (*EnterSection_)(const char *name); - void (*ExitSection_)(const char *name); -}; - -class NewStateExternalFunctions : public NewState -{ -private: - void (*Save_)(const void *ptr, size_t size, const char *name); - void (*Load_)(void *ptr, size_t size, const char *name); - void (*EnterSection_)(const char *name); - void (*ExitSection_)(const char *name); -public: - NewStateExternalFunctions(const FPtrs *ff); - virtual void Save(const void *ptr, size_t size, const char *name); - virtual void Load(void *ptr, size_t size, const char *name); - virtual void EnterSection(const char *name); - virtual void ExitSection(const char *name); -}; - -// defines and explicitly instantiates -#define SYNCFUNC(x)\ - template void x::SyncState(NewState *ns);\ - template void x::SyncState(NewState *ns);\ - templatevoid x::SyncState(NewState *ns) - -// N = normal variable -// P = pointer to fixed size data -// S = "sub object" -// T = "ptr to sub object" -// R = pointer, store its offset from some other pointer -// E = general purpose cased value "enum" - - -// first line is default value in converted enum; last line is default value in argument x -#define EBS(x,d) do { int _ttmp = (d); if (isReader) ns->Load(&_ttmp, sizeof(_ttmp), #x); if (0) -#define EVS(x,v,n) else if (!isReader && (x) == (v)) _ttmp = (n); else if (isReader && _ttmp == (n)) (x) = (v) -#define EES(x,d) else if (isReader) (x) = (d); if (!isReader) ns->Save(&_ttmp, sizeof(_ttmp), #x); } while (0) - -#define RSS(x,b) do { if (isReader)\ -{ ptrdiff_t _ttmp; ns->Load(&_ttmp, sizeof(_ttmp), #x); (x) = (_ttmp == (ptrdiff_t)0xdeadbeef ? 0 : (b) + _ttmp); }\ - else\ -{ ptrdiff_t _ttmp = (x) == 0 ? 0xdeadbeef : (x) - (b); ns->Save(&_ttmp, sizeof(_ttmp), #x); } } while (0) - -#define PSS(x,s) do { if (isReader) ns->Load((x), (s), #x); else ns->Save((x), (s), #x); } while (0) - -#define NSS(x) do { if (isReader) ns->Load(&(x), sizeof(x), #x); else ns->Save(&(x), sizeof(x), #x); } while (0) - -#define SSS(x) do { ns->EnterSection(#x); (x).SyncState(ns); ns->ExitSection(#x); } while (0) -#define SSS_HACKY(x,extra) do { ns->EnterSection(#x); (x).SyncState(ns, extra); ns->ExitSection(#x); } while (0) - -#define TSS(x) do { ns->EnterSection(#x); (x)->SyncState(ns); ns->ExitSection(#x); } while (0) - -#endif diff --git a/vbanext/optable.inc b/vbanext/optable.inc deleted file mode 100644 index d0cbc9eb00..0000000000 --- a/vbanext/optable.inc +++ /dev/null @@ -1,327 +0,0 @@ -#define F(fcn) &Gigazoid::fcn - -#define REP16(insn) \ - F(insn),F(insn),F(insn),F(insn),F(insn),F(insn),F(insn),F(insn),\ - F(insn),F(insn),F(insn),F(insn),F(insn),F(insn),F(insn),F(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 -#define arm_BP armUnknownInsn - -#define thumbUI thumbUnknownInsn -#define thumbBP thumbUnknownInsn - -void (Gigazoid::*const Gigazoid::armInsnTable[4096])(u32 opcode) = { - F(arm000),F(arm001),F(arm002),F(arm003),F(arm004),F(arm005),F(arm006),F(arm007), // F(000) - F(arm000),F(arm009),F(arm002),F(arm00B),F(arm004),F(arm_UI),F(arm006),F(arm_UI), // F(008) - F(arm010),F(arm011),F(arm012),F(arm013),F(arm014),F(arm015),F(arm016),F(arm017), // F(010) - F(arm010),F(arm019),F(arm012),F(arm01B),F(arm014),F(arm01D),F(arm016),F(arm01F), // F(018) - F(arm020),F(arm021),F(arm022),F(arm023),F(arm024),F(arm025),F(arm026),F(arm027), // F(020) - F(arm020),F(arm029),F(arm022),F(arm_UI),F(arm024),F(arm_UI),F(arm026),F(arm_UI), // F(028) - F(arm030),F(arm031),F(arm032),F(arm033),F(arm034),F(arm035),F(arm036),F(arm037), // F(030) - F(arm030),F(arm039),F(arm032),F(arm_UI),F(arm034),F(arm01D),F(arm036),F(arm01F), // F(038) - F(arm040),F(arm041),F(arm042),F(arm043),F(arm044),F(arm045),F(arm046),F(arm047), // F(040) - F(arm040),F(arm_UI),F(arm042),F(arm04B),F(arm044),F(arm_UI),F(arm046),F(arm_UI), // F(048) - F(arm050),F(arm051),F(arm052),F(arm053),F(arm054),F(arm055),F(arm056),F(arm057), // F(050) - F(arm050),F(arm_UI),F(arm052),F(arm05B),F(arm054),F(arm05D),F(arm056),F(arm05F), // F(058) - F(arm060),F(arm061),F(arm062),F(arm063),F(arm064),F(arm065),F(arm066),F(arm067), // F(060) - F(arm060),F(arm_UI),F(arm062),F(arm_UI),F(arm064),F(arm_UI),F(arm066),F(arm_UI), // F(068) - F(arm070),F(arm071),F(arm072),F(arm073),F(arm074),F(arm075),F(arm076),F(arm077), // F(070) - F(arm070),F(arm_UI),F(arm072),F(arm_UI),F(arm074),F(arm05D),F(arm076),F(arm05F), // F(078) - F(arm080),F(arm081),F(arm082),F(arm083),F(arm084),F(arm085),F(arm086),F(arm087), // F(080) - F(arm080),F(arm089),F(arm082),F(arm08B),F(arm084),F(arm_UI),F(arm086),F(arm_UI), // F(088) - F(arm090),F(arm091),F(arm092),F(arm093),F(arm094),F(arm095),F(arm096),F(arm097), // F(090) - F(arm090),F(arm099),F(arm092),F(arm09B),F(arm094),F(arm09D),F(arm096),F(arm09F), // F(098) - F(arm0A0),F(arm0A1),F(arm0A2),F(arm0A3),F(arm0A4),F(arm0A5),F(arm0A6),F(arm0A7), // F(0A0) - F(arm0A0),F(arm0A9),F(arm0A2),F(arm_UI),F(arm0A4),F(arm_UI),F(arm0A6),F(arm_UI), // F(0A8) - F(arm0B0),F(arm0B1),F(arm0B2),F(arm0B3),F(arm0B4),F(arm0B5),F(arm0B6),F(arm0B7), // F(0B0) - F(arm0B0),F(arm0B9),F(arm0B2),F(arm_UI),F(arm0B4),F(arm09D),F(arm0B6),F(arm09F), // F(0B8) - F(arm0C0),F(arm0C1),F(arm0C2),F(arm0C3),F(arm0C4),F(arm0C5),F(arm0C6),F(arm0C7), // F(0C0) - F(arm0C0),F(arm0C9),F(arm0C2),F(arm0CB),F(arm0C4),F(arm_UI),F(arm0C6),F(arm_UI), // F(0C8) - F(arm0D0),F(arm0D1),F(arm0D2),F(arm0D3),F(arm0D4),F(arm0D5),F(arm0D6),F(arm0D7), // F(0D0) - F(arm0D0),F(arm0D9),F(arm0D2),F(arm0DB),F(arm0D4),F(arm0DD),F(arm0D6),F(arm0DF), // F(0D8) - F(arm0E0),F(arm0E1),F(arm0E2),F(arm0E3),F(arm0E4),F(arm0E5),F(arm0E6),F(arm0E7), // F(0E0) - F(arm0E0),F(arm0E9),F(arm0E2),F(arm_UI),F(arm0E4),F(arm_UI),F(arm0E6),F(arm_UI), // F(0E8) - F(arm0F0),F(arm0F1),F(arm0F2),F(arm0F3),F(arm0F4),F(arm0F5),F(arm0F6),F(arm0F7), // F(0F0) - F(arm0F0),F(arm0F9),F(arm0F2),F(arm_UI),F(arm0F4),F(arm0DD),F(arm0F6),F(arm0DF), // F(0F8) - - F(arm100),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI), // F(100) - F(arm_UI),F(arm109),F(arm_UI),F(arm10B),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI), // F(108) - F(arm110),F(arm111),F(arm112),F(arm113),F(arm114),F(arm115),F(arm116),F(arm117), // F(110) - F(arm110),F(arm_UI),F(arm112),F(arm11B),F(arm114),F(arm11D),F(arm116),F(arm11F), // F(118) - F(arm120),F(arm121),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_BP), // F(120) - F(arm_UI),F(arm_UI),F(arm_UI),F(arm12B),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI), // F(128) - F(arm130),F(arm131),F(arm132),F(arm133),F(arm134),F(arm135),F(arm136),F(arm137), // F(130) - F(arm130),F(arm_UI),F(arm132),F(arm13B),F(arm134),F(arm13D),F(arm136),F(arm13F), // F(138) - F(arm140),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI), // F(140) - F(arm_UI),F(arm149),F(arm_UI),F(arm14B),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI), // F(148) - F(arm150),F(arm151),F(arm152),F(arm153),F(arm154),F(arm155),F(arm156),F(arm157), // F(150) - F(arm150),F(arm_UI),F(arm152),F(arm15B),F(arm154),F(arm15D),F(arm156),F(arm15F), // F(158) - F(arm160),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI), // F(160) - F(arm_UI),F(arm_UI),F(arm_UI),F(arm16B),F(arm_UI),F(arm_UI),F(arm_UI),F(arm_UI), // F(168) - F(arm170),F(arm171),F(arm172),F(arm173),F(arm174),F(arm175),F(arm176),F(arm177), // F(170) - F(arm170),F(arm_UI),F(arm172),F(arm17B),F(arm174),F(arm17D),F(arm176),F(arm17F), // F(178) - F(arm180),F(arm181),F(arm182),F(arm183),F(arm184),F(arm185),F(arm186),F(arm187), // F(180) - F(arm180),F(arm_UI),F(arm182),F(arm18B),F(arm184),F(arm_UI),F(arm186),F(arm_UI), // F(188) - F(arm190),F(arm191),F(arm192),F(arm193),F(arm194),F(arm195),F(arm196),F(arm197), // F(190) - F(arm190),F(arm_UI),F(arm192),F(arm19B),F(arm194),F(arm19D),F(arm196),F(arm19F), // F(198) - F(arm1A0),F(arm1A1),F(arm1A2),F(arm1A3),F(arm1A4),F(arm1A5),F(arm1A6),F(arm1A7), // F(1A0) - F(arm1A0),F(arm_UI),F(arm1A2),F(arm1AB),F(arm1A4),F(arm_UI),F(arm1A6),F(arm_UI), // F(1A8) - F(arm1B0),F(arm1B1),F(arm1B2),F(arm1B3),F(arm1B4),F(arm1B5),F(arm1B6),F(arm1B7), // F(1B0) - F(arm1B0),F(arm_UI),F(arm1B2),F(arm1BB),F(arm1B4),F(arm1BD),F(arm1B6),F(arm1BF), // F(1B8) - F(arm1C0),F(arm1C1),F(arm1C2),F(arm1C3),F(arm1C4),F(arm1C5),F(arm1C6),F(arm1C7), // F(1C0) - F(arm1C0),F(arm_UI),F(arm1C2),F(arm1CB),F(arm1C4),F(arm_UI),F(arm1C6),F(arm_UI), // F(1C8) - F(arm1D0),F(arm1D1),F(arm1D2),F(arm1D3),F(arm1D4),F(arm1D5),F(arm1D6),F(arm1D7), // F(1D0) - F(arm1D0),F(arm_UI),F(arm1D2),F(arm1DB),F(arm1D4),F(arm1DD),F(arm1D6),F(arm1DF), // F(1D8) - F(arm1E0),F(arm1E1),F(arm1E2),F(arm1E3),F(arm1E4),F(arm1E5),F(arm1E6),F(arm1E7), // F(1E0) - F(arm1E0),F(arm_UI),F(arm1E2),F(arm1EB),F(arm1E4),F(arm_UI),F(arm1E6),F(arm_UI), // F(1E8) - F(arm1F0),F(arm1F1),F(arm1F2),F(arm1F3),F(arm1F4),F(arm1F5),F(arm1F6),F(arm1F7), // F(1F0) - F(arm1F0),F(arm_UI),F(arm1F2),F(arm1FB),F(arm1F4),F(arm1FD),F(arm1F6),F(arm1FF), // F(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 - - F(arm600),F(arm_UI),F(arm602),F(arm_UI),F(arm604),F(arm_UI),F(arm606),F(arm_UI), // F(600) - F(arm600),F(arm_UI),F(arm602),F(arm_UI),F(arm604),F(arm_UI),F(arm606),F(arm_UI), // F(608) - F(arm610),F(arm_UI),F(arm612),F(arm_UI),F(arm614),F(arm_UI),F(arm616),F(arm_UI), // F(610) - F(arm610),F(arm_UI),F(arm612),F(arm_UI),F(arm614),F(arm_UI),F(arm616),F(arm_UI), // F(618) - F(arm600),F(arm_UI),F(arm602),F(arm_UI),F(arm604),F(arm_UI),F(arm606),F(arm_UI), // F(620) - F(arm600),F(arm_UI),F(arm602),F(arm_UI),F(arm604),F(arm_UI),F(arm606),F(arm_UI), // F(628) - F(arm610),F(arm_UI),F(arm612),F(arm_UI),F(arm614),F(arm_UI),F(arm616),F(arm_UI), // F(630) - F(arm610),F(arm_UI),F(arm612),F(arm_UI),F(arm614),F(arm_UI),F(arm616),F(arm_UI), // F(638) - F(arm640),F(arm_UI),F(arm642),F(arm_UI),F(arm644),F(arm_UI),F(arm646),F(arm_UI), // F(640) - F(arm640),F(arm_UI),F(arm642),F(arm_UI),F(arm644),F(arm_UI),F(arm646),F(arm_UI), // F(648) - F(arm650),F(arm_UI),F(arm652),F(arm_UI),F(arm654),F(arm_UI),F(arm656),F(arm_UI), // F(650) - F(arm650),F(arm_UI),F(arm652),F(arm_UI),F(arm654),F(arm_UI),F(arm656),F(arm_UI), // F(658) - F(arm640),F(arm_UI),F(arm642),F(arm_UI),F(arm644),F(arm_UI),F(arm646),F(arm_UI), // F(660) - F(arm640),F(arm_UI),F(arm642),F(arm_UI),F(arm644),F(arm_UI),F(arm646),F(arm_UI), // F(668) - F(arm650),F(arm_UI),F(arm652),F(arm_UI),F(arm654),F(arm_UI),F(arm656),F(arm_UI), // F(670) - F(arm650),F(arm_UI),F(arm652),F(arm_UI),F(arm654),F(arm_UI),F(arm656),F(arm_UI), // F(678) - F(arm680),F(arm_UI),F(arm682),F(arm_UI),F(arm684),F(arm_UI),F(arm686),F(arm_UI), // F(680) - F(arm680),F(arm_UI),F(arm682),F(arm_UI),F(arm684),F(arm_UI),F(arm686),F(arm_UI), // F(688) - F(arm690),F(arm_UI),F(arm692),F(arm_UI),F(arm694),F(arm_UI),F(arm696),F(arm_UI), // F(690) - F(arm690),F(arm_UI),F(arm692),F(arm_UI),F(arm694),F(arm_UI),F(arm696),F(arm_UI), // F(698) - F(arm680),F(arm_UI),F(arm682),F(arm_UI),F(arm684),F(arm_UI),F(arm686),F(arm_UI), // F(6A0) - F(arm680),F(arm_UI),F(arm682),F(arm_UI),F(arm684),F(arm_UI),F(arm686),F(arm_UI), // F(6A8) - F(arm690),F(arm_UI),F(arm692),F(arm_UI),F(arm694),F(arm_UI),F(arm696),F(arm_UI), // F(6B0) - F(arm690),F(arm_UI),F(arm692),F(arm_UI),F(arm694),F(arm_UI),F(arm696),F(arm_UI), // F(6B8) - F(arm6C0),F(arm_UI),F(arm6C2),F(arm_UI),F(arm6C4),F(arm_UI),F(arm6C6),F(arm_UI), // F(6C0) - F(arm6C0),F(arm_UI),F(arm6C2),F(arm_UI),F(arm6C4),F(arm_UI),F(arm6C6),F(arm_UI), // F(6C8) - F(arm6D0),F(arm_UI),F(arm6D2),F(arm_UI),F(arm6D4),F(arm_UI),F(arm6D6),F(arm_UI), // F(6D0) - F(arm6D0),F(arm_UI),F(arm6D2),F(arm_UI),F(arm6D4),F(arm_UI),F(arm6D6),F(arm_UI), // F(6D8) - F(arm6C0),F(arm_UI),F(arm6C2),F(arm_UI),F(arm6C4),F(arm_UI),F(arm6C6),F(arm_UI), // F(6E0) - F(arm6C0),F(arm_UI),F(arm6C2),F(arm_UI),F(arm6C4),F(arm_UI),F(arm6C6),F(arm_UI), // F(6E8) - F(arm6D0),F(arm_UI),F(arm6D2),F(arm_UI),F(arm6D4),F(arm_UI),F(arm6D6),F(arm_UI), // F(6F0) - F(arm6D0),F(arm_UI),F(arm6D2),F(arm_UI),F(arm6D4),F(arm_UI),F(arm6D6),F(arm_UI), // F(6F8) - - F(arm700),F(arm_UI),F(arm702),F(arm_UI),F(arm704),F(arm_UI),F(arm706),F(arm_UI), // F(700) - F(arm700),F(arm_UI),F(arm702),F(arm_UI),F(arm704),F(arm_UI),F(arm706),F(arm_UI), // F(708) - F(arm710),F(arm_UI),F(arm712),F(arm_UI),F(arm714),F(arm_UI),F(arm716),F(arm_UI), // F(710) - F(arm710),F(arm_UI),F(arm712),F(arm_UI),F(arm714),F(arm_UI),F(arm716),F(arm_UI), // F(718) - F(arm720),F(arm_UI),F(arm722),F(arm_UI),F(arm724),F(arm_UI),F(arm726),F(arm_UI), // F(720) - F(arm720),F(arm_UI),F(arm722),F(arm_UI),F(arm724),F(arm_UI),F(arm726),F(arm_UI), // F(728) - F(arm730),F(arm_UI),F(arm732),F(arm_UI),F(arm734),F(arm_UI),F(arm736),F(arm_UI), // F(730) - F(arm730),F(arm_UI),F(arm732),F(arm_UI),F(arm734),F(arm_UI),F(arm736),F(arm_UI), // F(738) - F(arm740),F(arm_UI),F(arm742),F(arm_UI),F(arm744),F(arm_UI),F(arm746),F(arm_UI), // F(740) - F(arm740),F(arm_UI),F(arm742),F(arm_UI),F(arm744),F(arm_UI),F(arm746),F(arm_UI), // F(748) - F(arm750),F(arm_UI),F(arm752),F(arm_UI),F(arm754),F(arm_UI),F(arm756),F(arm_UI), // F(750) - F(arm750),F(arm_UI),F(arm752),F(arm_UI),F(arm754),F(arm_UI),F(arm756),F(arm_UI), // F(758) - F(arm760),F(arm_UI),F(arm762),F(arm_UI),F(arm764),F(arm_UI),F(arm766),F(arm_UI), // F(760) - F(arm760),F(arm_UI),F(arm762),F(arm_UI),F(arm764),F(arm_UI),F(arm766),F(arm_UI), // F(768) - F(arm770),F(arm_UI),F(arm772),F(arm_UI),F(arm774),F(arm_UI),F(arm776),F(arm_UI), // F(770) - F(arm770),F(arm_UI),F(arm772),F(arm_UI),F(arm774),F(arm_UI),F(arm776),F(arm_UI), // F(778) - F(arm780),F(arm_UI),F(arm782),F(arm_UI),F(arm784),F(arm_UI),F(arm786),F(arm_UI), // F(780) - F(arm780),F(arm_UI),F(arm782),F(arm_UI),F(arm784),F(arm_UI),F(arm786),F(arm_UI), // F(788) - F(arm790),F(arm_UI),F(arm792),F(arm_UI),F(arm794),F(arm_UI),F(arm796),F(arm_UI), // F(790) - F(arm790),F(arm_UI),F(arm792),F(arm_UI),F(arm794),F(arm_UI),F(arm796),F(arm_UI), // F(798) - F(arm7A0),F(arm_UI),F(arm7A2),F(arm_UI),F(arm7A4),F(arm_UI),F(arm7A6),F(arm_UI), // F(7A0) - F(arm7A0),F(arm_UI),F(arm7A2),F(arm_UI),F(arm7A4),F(arm_UI),F(arm7A6),F(arm_UI), // F(7A8) - F(arm7B0),F(arm_UI),F(arm7B2),F(arm_UI),F(arm7B4),F(arm_UI),F(arm7B6),F(arm_UI), // F(7B0) - F(arm7B0),F(arm_UI),F(arm7B2),F(arm_UI),F(arm7B4),F(arm_UI),F(arm7B6),F(arm_UI), // F(7B8) - F(arm7C0),F(arm_UI),F(arm7C2),F(arm_UI),F(arm7C4),F(arm_UI),F(arm7C6),F(arm_UI), // F(7C0) - F(arm7C0),F(arm_UI),F(arm7C2),F(arm_UI),F(arm7C4),F(arm_UI),F(arm7C6),F(arm_UI), // F(7C8) - F(arm7D0),F(arm_UI),F(arm7D2),F(arm_UI),F(arm7D4),F(arm_UI),F(arm7D6),F(arm_UI), // F(7D0) - F(arm7D0),F(arm_UI),F(arm7D2),F(arm_UI),F(arm7D4),F(arm_UI),F(arm7D6),F(arm_UI), // F(7D8) - F(arm7E0),F(arm_UI),F(arm7E2),F(arm_UI),F(arm7E4),F(arm_UI),F(arm7E6),F(arm_UI), // F(7E0) - F(arm7E0),F(arm_UI),F(arm7E2),F(arm_UI),F(arm7E4),F(arm_UI),F(arm7E6),F(arm_UI), // F(7E8) - F(arm7F0),F(arm_UI),F(arm7F2),F(arm_UI),F(arm7F4),F(arm_UI),F(arm7F6),F(arm_UI), // F(7F0) - F(arm7F0),F(arm_UI),F(arm7F2),F(arm_UI),F(arm7F4),F(arm_UI),F(arm7F6),F(arm_BP), // F(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 - - F(arm_UI),F(armE01),F(arm_UI),F(armE01),F(arm_UI),F(armE01),F(arm_UI),F(armE01), // F(E00) - F(arm_UI),F(armE01),F(arm_UI),F(armE01),F(arm_UI),F(armE01),F(arm_UI),F(armE01), // F(E08) - F(arm_UI),F(armE01),F(arm_UI),F(armE01),F(arm_UI),F(armE01),F(arm_UI),F(armE01), // F(E10) - F(arm_UI),F(armE01),F(arm_UI),F(armE01),F(arm_UI),F(armE01),F(arm_UI),F(armE01), // F(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 -}; - -void (Gigazoid::*const Gigazoid::thumbInsnTable[1024])(u32 opcode) = { - F(thumb00_00),F(thumb00_01),F(thumb00_02),F(thumb00_03),F(thumb00_04),F(thumb00_05),F(thumb00_06),F(thumb00_07), // F(00) - F(thumb00_08),F(thumb00_09),F(thumb00_0A),F(thumb00_0B),F(thumb00_0C),F(thumb00_0D),F(thumb00_0E),F(thumb00_0F), - F(thumb00_10),F(thumb00_11),F(thumb00_12),F(thumb00_13),F(thumb00_14),F(thumb00_15),F(thumb00_16),F(thumb00_17), - F(thumb00_18),F(thumb00_19),F(thumb00_1A),F(thumb00_1B),F(thumb00_1C),F(thumb00_1D),F(thumb00_1E),F(thumb00_1F), - F(thumb08_00),F(thumb08_01),F(thumb08_02),F(thumb08_03),F(thumb08_04),F(thumb08_05),F(thumb08_06),F(thumb08_07), // F(08) - F(thumb08_08),F(thumb08_09),F(thumb08_0A),F(thumb08_0B),F(thumb08_0C),F(thumb08_0D),F(thumb08_0E),F(thumb08_0F), - F(thumb08_10),F(thumb08_11),F(thumb08_12),F(thumb08_13),F(thumb08_14),F(thumb08_15),F(thumb08_16),F(thumb08_17), - F(thumb08_18),F(thumb08_19),F(thumb08_1A),F(thumb08_1B),F(thumb08_1C),F(thumb08_1D),F(thumb08_1E),F(thumb08_1F), - F(thumb10_00),F(thumb10_01),F(thumb10_02),F(thumb10_03),F(thumb10_04),F(thumb10_05),F(thumb10_06),F(thumb10_07), // F(10) - F(thumb10_08),F(thumb10_09),F(thumb10_0A),F(thumb10_0B),F(thumb10_0C),F(thumb10_0D),F(thumb10_0E),F(thumb10_0F), - F(thumb10_10),F(thumb10_11),F(thumb10_12),F(thumb10_13),F(thumb10_14),F(thumb10_15),F(thumb10_16),F(thumb10_17), - F(thumb10_18),F(thumb10_19),F(thumb10_1A),F(thumb10_1B),F(thumb10_1C),F(thumb10_1D),F(thumb10_1E),F(thumb10_1F), - F(thumb18_0),F(thumb18_1),F(thumb18_2),F(thumb18_3),F(thumb18_4),F(thumb18_5),F(thumb18_6),F(thumb18_7), // F(18) - F(thumb1A_0),F(thumb1A_1),F(thumb1A_2),F(thumb1A_3),F(thumb1A_4),F(thumb1A_5),F(thumb1A_6),F(thumb1A_7), - F(thumb1C_0),F(thumb1C_1),F(thumb1C_2),F(thumb1C_3),F(thumb1C_4),F(thumb1C_5),F(thumb1C_6),F(thumb1C_7), - F(thumb1E_0),F(thumb1E_1),F(thumb1E_2),F(thumb1E_3),F(thumb1E_4),F(thumb1E_5),F(thumb1E_6),F(thumb1E_7), - F(thumb20),F(thumb20),F(thumb20),F(thumb20),F(thumb21),F(thumb21),F(thumb21),F(thumb21), // F(20) - F(thumb22),F(thumb22),F(thumb22),F(thumb22),F(thumb23),F(thumb23),F(thumb23),F(thumb23), - F(thumb24),F(thumb24),F(thumb24),F(thumb24),F(thumb25),F(thumb25),F(thumb25),F(thumb25), - F(thumb26),F(thumb26),F(thumb26),F(thumb26),F(thumb27),F(thumb27),F(thumb27),F(thumb27), - F(thumb28),F(thumb28),F(thumb28),F(thumb28),F(thumb29),F(thumb29),F(thumb29),F(thumb29), // F(28) - F(thumb2A),F(thumb2A),F(thumb2A),F(thumb2A),F(thumb2B),F(thumb2B),F(thumb2B),F(thumb2B), - F(thumb2C),F(thumb2C),F(thumb2C),F(thumb2C),F(thumb2D),F(thumb2D),F(thumb2D),F(thumb2D), - F(thumb2E),F(thumb2E),F(thumb2E),F(thumb2E),F(thumb2F),F(thumb2F),F(thumb2F),F(thumb2F), - F(thumb30),F(thumb30),F(thumb30),F(thumb30),F(thumb31),F(thumb31),F(thumb31),F(thumb31), // F(30) - F(thumb32),F(thumb32),F(thumb32),F(thumb32),F(thumb33),F(thumb33),F(thumb33),F(thumb33), - F(thumb34),F(thumb34),F(thumb34),F(thumb34),F(thumb35),F(thumb35),F(thumb35),F(thumb35), - F(thumb36),F(thumb36),F(thumb36),F(thumb36),F(thumb37),F(thumb37),F(thumb37),F(thumb37), - F(thumb38),F(thumb38),F(thumb38),F(thumb38),F(thumb39),F(thumb39),F(thumb39),F(thumb39), // F(38) - F(thumb3A),F(thumb3A),F(thumb3A),F(thumb3A),F(thumb3B),F(thumb3B),F(thumb3B),F(thumb3B), - F(thumb3C),F(thumb3C),F(thumb3C),F(thumb3C),F(thumb3D),F(thumb3D),F(thumb3D),F(thumb3D), - F(thumb3E),F(thumb3E),F(thumb3E),F(thumb3E),F(thumb3F),F(thumb3F),F(thumb3F),F(thumb3F), - F(thumb40_0),F(thumb40_1),F(thumb40_2),F(thumb40_3),F(thumb41_0),F(thumb41_1),F(thumb41_2),F(thumb41_3), // F(40) - F(thumb42_0),F(thumb42_1),F(thumb42_2),F(thumb42_3),F(thumb43_0),F(thumb43_1),F(thumb43_2),F(thumb43_3), - F(thumbUI),F(thumb44_1),F(thumb44_2),F(thumb44_3),F(thumbUI),F(thumb45_1),F(thumb45_2),F(thumb45_3), - F(thumbUI),F(thumb46_1),F(thumb46_2),F(thumb46_3),F(thumb47),F(thumb47),F(thumbUI),F(thumbUI), - F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48), // F(48) - F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48), - F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48), - F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48),F(thumb48), - F(thumb50),F(thumb50),F(thumb50),F(thumb50),F(thumb50),F(thumb50),F(thumb50),F(thumb50), // F(50) - F(thumb52),F(thumb52),F(thumb52),F(thumb52),F(thumb52),F(thumb52),F(thumb52),F(thumb52), - F(thumb54),F(thumb54),F(thumb54),F(thumb54),F(thumb54),F(thumb54),F(thumb54),F(thumb54), - F(thumb56),F(thumb56),F(thumb56),F(thumb56),F(thumb56),F(thumb56),F(thumb56),F(thumb56), - F(thumb58),F(thumb58),F(thumb58),F(thumb58),F(thumb58),F(thumb58),F(thumb58),F(thumb58), // F(58) - F(thumb5A),F(thumb5A),F(thumb5A),F(thumb5A),F(thumb5A),F(thumb5A),F(thumb5A),F(thumb5A), - F(thumb5C),F(thumb5C),F(thumb5C),F(thumb5C),F(thumb5C),F(thumb5C),F(thumb5C),F(thumb5C), - F(thumb5E),F(thumb5E),F(thumb5E),F(thumb5E),F(thumb5E),F(thumb5E),F(thumb5E),F(thumb5E), - F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60), // F(60) - F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60), - F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60), - F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60),F(thumb60), - F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68), // F(68) - F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68), - F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68), - F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68),F(thumb68), - F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70), // F(70) - F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70), - F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70), - F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70),F(thumb70), - F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78), // F(78) - F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78), - F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78), - F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78),F(thumb78), - F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80), // F(80) - F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80), - F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80), - F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80),F(thumb80), - F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88), // F(88) - F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88), - F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88), - F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88),F(thumb88), - F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90), // F(90) - F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90), - F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90), - F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90),F(thumb90), - F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98), // F(98) - F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98), - F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98), - F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98),F(thumb98), - F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0), // F(A0) - F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0), - F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0), - F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0),F(thumbA0), - F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8), // F(A8) - F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8), - F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8), - F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8),F(thumbA8), - F(thumbB0),F(thumbB0),F(thumbB0),F(thumbB0),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI), // F(B0) - F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI), - F(thumbB4),F(thumbB4),F(thumbB4),F(thumbB4),F(thumbB5),F(thumbB5),F(thumbB5),F(thumbB5), - F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI), - F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI), // F(B8) - F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI), - F(thumbBC),F(thumbBC),F(thumbBC),F(thumbBC),F(thumbBD),F(thumbBD),F(thumbBD),F(thumbBD), - F(thumbBP),F(thumbBP),F(thumbBP),F(thumbBP),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI), - F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0), // F(C0) - F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0), - F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0), - F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0),F(thumbC0), - F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8), // F(C8) - F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8), - F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8), - F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8),F(thumbC8), - F(thumbD0),F(thumbD0),F(thumbD0),F(thumbD0),F(thumbD1),F(thumbD1),F(thumbD1),F(thumbD1), // F(D0) - F(thumbD2),F(thumbD2),F(thumbD2),F(thumbD2),F(thumbD3),F(thumbD3),F(thumbD3),F(thumbD3), - F(thumbD4),F(thumbD4),F(thumbD4),F(thumbD4),F(thumbD5),F(thumbD5),F(thumbD5),F(thumbD5), - F(thumbD6),F(thumbD6),F(thumbD6),F(thumbD6),F(thumbD7),F(thumbD7),F(thumbD7),F(thumbD7), - F(thumbD8),F(thumbD8),F(thumbD8),F(thumbD8),F(thumbD9),F(thumbD9),F(thumbD9),F(thumbD9), // F(D8) - F(thumbDA),F(thumbDA),F(thumbDA),F(thumbDA),F(thumbDB),F(thumbDB),F(thumbDB),F(thumbDB), - F(thumbDC),F(thumbDC),F(thumbDC),F(thumbDC),F(thumbDD),F(thumbDD),F(thumbDD),F(thumbDD), - F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbDF),F(thumbDF),F(thumbDF),F(thumbDF), - F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0), // F(E0) - F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0), - F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0), - F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0),F(thumbE0), - F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI), // F(E8) - F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI), - F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI), - F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI),F(thumbUI), - F(thumbF0),F(thumbF0),F(thumbF0),F(thumbF0),F(thumbF0),F(thumbF0),F(thumbF0),F(thumbF0), // F(F0) - F(thumbF0),F(thumbF0),F(thumbF0),F(thumbF0),F(thumbF0),F(thumbF0),F(thumbF0),F(thumbF0), - F(thumbF4),F(thumbF4),F(thumbF4),F(thumbF4),F(thumbF4),F(thumbF4),F(thumbF4),F(thumbF4), - F(thumbF4),F(thumbF4),F(thumbF4),F(thumbF4),F(thumbF4),F(thumbF4),F(thumbF4),F(thumbF4), - F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8), // F(F8) - F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8), - F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8), - F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8),F(thumbF8), -}; - -#undef F diff --git a/vbanext/port.h b/vbanext/port.h deleted file mode 100644 index 3b2457042e..0000000000 --- a/vbanext/port.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef PORT_H -#define PORT_H - -#include "types.h" - -/* if a >= 0 return x else y*/ -#define isel(a, x, y) ((x & (~(a >> 31))) + (y & (a >> 31))) - -#ifdef FRONTEND_SUPPORTS_RGB565 -/* 16bit color - RGB565 */ -#define RED_MASK 0xf800 -#define GREEN_MASK 0x7e0 -#define BLUE_MASK 0x1f -#define RED_EXPAND 3 -#define GREEN_EXPAND 2 -#define BLUE_EXPAND 3 -#define RED_SHIFT 11 -#define GREEN_SHIFT 5 -#define BLUE_SHIFT 0 -#define CONVERT_COLOR(color) (((color & 0x001f) << 11) | ((color & 0x03e0) << 1) | ((color & 0x0200) >> 4) | ((color & 0x7c00) >> 10)) -#else -/* 16bit color - RGB555 */ -#define RED_MASK 0x7c00 -#define GREEN_MASK 0x3e0 -#define BLUE_MASK 0x1f -#define RED_EXPAND 3 -#define GREEN_EXPAND 3 -#define BLUE_EXPAND 3 -#define RED_SHIFT 10 -#define GREEN_SHIFT 5 -#define BLUE_SHIFT 0 -#define CONVERT_COLOR(color) ((((color & 0x1f) << 10) | (((color & 0x3e0) >> 5) << 5) | (((color & 0x7c00) >> 10))) & 0x7fff) -#endif - -#ifdef _MSC_VER -#include -#define strcasecmp _stricmp -#endif - -#ifdef USE_CACHE_PREFETCH -#if defined(__ANDROID__) -#define CACHE_PREFETCH(prefetch) prefetch(&prefetch); -#elif defined(_XBOX) -#define CACHE_PREFETCH(prefetch) __dcbt(0, &prefetch); -#else -#define CACHE_PREFETCH(prefetch) __dcbt(&prefetch); -#endif -#else -#define CACHE_PREFETCH(prefetch) -#endif - -#define READ16LE(x) *((u16 *)x) -#define READ32LE(x) *((u32 *)x) -#define WRITE16LE(x,v) *((u16 *)x) = (v) -#define WRITE32LE(x,v) *((u32 *)x) = (v) - -#endif diff --git a/vbanext/sound_blargg.h b/vbanext/sound_blargg.h deleted file mode 100644 index c80d61e18e..0000000000 --- a/vbanext/sound_blargg.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef SOUND_BLARGG_H -#define SOUND_BLARGG_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 - -#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_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 - typedef int bool; - const bool true = 1; - const bool false = 0; -#endif - -/* HAVE_STDINT_H: If defined, use for int8_t etc.*/ -#if defined (HAVE_STDINT_H) - #include -/* HAVE_INTTYPES_H: If defined, use for int8_t etc.*/ -#elif defined (HAVE_INTTYPES_H) - #include -#endif - -// If expr yields non-NULL error string, returns it from current function, -// otherwise continues normally. -#undef RETURN_ERR -#define RETURN_ERR( expr ) do { \ - const char * blargg_return_err_ = (expr); \ - if ( blargg_return_err_ ) return blargg_return_err_; \ - } while ( 0 ) - -#endif // #ifndef SOUND_BLARGG_H diff --git a/vbanext/types.h b/vbanext/types.h deleted file mode 100644 index 8433576dcc..0000000000 --- a/vbanext/types.h +++ /dev/null @@ -1,33 +0,0 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 2008 VBA-M development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef __VBA_TYPES_H__ -#define __VBA_TYPES_H__ - -#include - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; - -#endif // __VBA_TYPES_H__