From e6e70b6e352be10470c8463194445ec05c1873fb Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 31 Mar 2020 23:14:33 -0400 Subject: [PATCH] GBHawk: remove C++ core, not worth it, need to rethink design --- .../GBHawk_new/GBHawkNew.ICodeDataLog.cs | 185 - .../GBHawk_new/GBHawkNew.IDebuggable.cs | 67 - .../GBHawk_new/GBHawkNew.IEmulator.cs | 220 - .../GBHawk_new/GBHawkNew.IInputPollable.cs | 24 - .../GBHawk_new/GBHawkNew.IMemoryDomains.cs | 69 - .../Nintendo/GBHawk_new/GBHawkNew.ISaveRam.cs | 24 - .../GBHawk_new/GBHawkNew.ISettable.cs | 155 - .../GBHawk_new/GBHawkNew.IStatable.cs | 29 - .../Consoles/Nintendo/GBHawk_new/GBHawkNew.cs | 211 - .../GBHawk_new/GBHawkNewControllerDeck.cs | 81 - .../GBHawk_new/GBHawkNewControllers.cs | 216 - .../Consoles/Nintendo/GBHawk_new/LibGBHawk.cs | 349 -- libHawk/GBHawk/GBHawk.sln | 31 - libHawk/GBHawk/GBHawk/Core.h | 659 --- libHawk/GBHawk/GBHawk/GBAudio.h | 1388 ----- libHawk/GBHawk/GBHawk/GBHawk.cpp | 260 - libHawk/GBHawk/GBHawk/GBHawk.h | 5 - libHawk/GBHawk/GBHawk/GBHawk.vcxproj | 177 - libHawk/GBHawk/GBHawk/LR35902.cpp | 31 - libHawk/GBHawk/GBHawk/LR35902.h | 3011 ---------- libHawk/GBHawk/GBHawk/Mappers.h | 3190 ----------- libHawk/GBHawk/GBHawk/Memory.cpp | 999 ---- libHawk/GBHawk/GBHawk/Memory.h | 400 -- libHawk/GBHawk/GBHawk/PPU.cpp | 32 - libHawk/GBHawk/GBHawk/PPU.h | 4853 ----------------- libHawk/GBHawk/GBHawk/SerialPort.h | 210 - libHawk/GBHawk/GBHawk/Timer.h | 221 - libHawk/GBHawk/GBHawk/cpp.hint | 2 - 28 files changed, 17099 deletions(-) delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.ICodeDataLog.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IDebuggable.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IEmulator.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IInputPollable.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IMemoryDomains.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.ISaveRam.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.ISettable.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IStatable.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNewControllerDeck.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNewControllers.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/LibGBHawk.cs delete mode 100644 libHawk/GBHawk/GBHawk.sln delete mode 100644 libHawk/GBHawk/GBHawk/Core.h delete mode 100644 libHawk/GBHawk/GBHawk/GBAudio.h delete mode 100644 libHawk/GBHawk/GBHawk/GBHawk.cpp delete mode 100644 libHawk/GBHawk/GBHawk/GBHawk.h delete mode 100644 libHawk/GBHawk/GBHawk/GBHawk.vcxproj delete mode 100644 libHawk/GBHawk/GBHawk/LR35902.cpp delete mode 100644 libHawk/GBHawk/GBHawk/LR35902.h delete mode 100644 libHawk/GBHawk/GBHawk/Mappers.h delete mode 100644 libHawk/GBHawk/GBHawk/Memory.cpp delete mode 100644 libHawk/GBHawk/GBHawk/Memory.h delete mode 100644 libHawk/GBHawk/GBHawk/PPU.cpp delete mode 100644 libHawk/GBHawk/GBHawk/PPU.h delete mode 100644 libHawk/GBHawk/GBHawk/SerialPort.h delete mode 100644 libHawk/GBHawk/GBHawk/Timer.h delete mode 100644 libHawk/GBHawk/GBHawk/cpp.hint diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.ICodeDataLog.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.ICodeDataLog.cs deleted file mode 100644 index 3bae50108f..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.ICodeDataLog.cs +++ /dev/null @@ -1,185 +0,0 @@ -using System.IO; -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Components.LR35902; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawkNew -{ - /* - public partial class GBHawk : ICodeDataLogger - { - private ICodeDataLog _cdl; - - public void SetCDL(ICodeDataLog cdl) - { - _cdl = cdl; - if (cdl == null) - this.cpu.CDLCallback = null; - else this.cpu.CDLCallback = CDLCpuCallback; - } - - public void NewCDL(ICodeDataLog cdl) - { - cdl["ROM"] = new byte[MemoryDomains["ROM"].Size]; - cdl["HRAM"] = new byte[MemoryDomains["Zero Page RAM"].Size]; - - cdl["WRAM"] = new byte[MemoryDomains["Main RAM"].Size]; - - if (MemoryDomains.Has("Cart RAM")) - { - cdl["CartRAM"] = new byte[MemoryDomains["Cart RAM"].Size]; - } - - cdl.SubType = "GB"; - cdl.SubVer = 0; - } - - [FeatureNotImplemented] - void ICodeDataLogger.DisassembleCDL(Stream s, ICodeDataLog cdl) - { - } - - public void SetCDL(LR35902.eCDLogMemFlags flags, string type, int cdladdr) - { - if (type == null) return; - byte val = (byte)flags; - _cdl[type][cdladdr] |= (byte)flags; - } - - void CDLCpuCallback(ushort addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x8000) - { - //don't record writes to the ROM, it's just noisy - //NOTE: in principle a mapper could mount a useful resource here, but I doubt it) - if ((flags & LR35902.eCDLogMemFlags.Write) != 0) return; - } - - if (ppu.DMA_start) - { - // some of gekkio's tests require these to be accessible during DMA - if (addr < 0x8000) - { - if (ppu.DMA_addr < 0x80) - { - return; - } - else - { - mapper.MapCDL(addr, flags); - return; - } - } - else if ((addr >= 0xE000) && (addr < 0xF000)) - { - SetCDL(flags, "WRAM", addr - 0xE000); - } - else if ((addr >= 0xF000) && (addr < 0xFE00)) - { - SetCDL(flags, "WRAM", (RAM_Bank * 0x1000) + (addr - 0xF000)); - } - else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu.DMA_OAM_access) - { - return; - } - else if ((addr >= 0xFF00) && (addr < 0xFF80)) // The game GOAL! Requires Hardware Regs to be accessible - { - return; - } - else if ((addr >= 0xFF80)) - { - SetCDL(flags, "HRAM", addr - 0xFF80); - } - - } - - if (addr < 0x900) - { - if (addr < 0x100) - { - // return Either BIOS ROM or Game ROM - if ((GB_bios_register & 0x1) == 0) - { - return; - } - else - { - mapper.MapCDL(addr, flags); - return; - } - } - else if (addr >= 0x200) - { - // return Either BIOS ROM or Game ROM - if (((GB_bios_register & 0x1) == 0) && is_GBC) - { - return; - } - else - { - mapper.MapCDL(addr, flags); - return; - } - } - else - { - mapper.MapCDL(addr, flags); - return; - } - } - else if (addr < 0x8000) - { - mapper.MapCDL(addr, flags); - return; - } - else if (addr < 0xA000) - { - return; - } - else if (addr < 0xC000) - { - mapper.MapCDL(addr, flags); - return; - } - else if (addr < 0xD000) - { - return; - } - else if (addr < 0xE000) - { - SetCDL(flags, "WRAM", (RAM_Bank * 0x1000) + (addr - 0xD000)); - } - else if (addr < 0xF000) - { - SetCDL(flags, "WRAM", addr - 0xE000); - } - else if (addr < 0xFE00) - { - SetCDL(flags, "WRAM", (RAM_Bank * 0x1000) + (addr - 0xF000)); - } - else if (addr < 0xFEA0) - { - return; - } - else if (addr < 0xFF00) - { - return; - } - else if (addr < 0xFF80) - { - return; - } - else if (addr < 0xFFFF) - { - SetCDL(flags, "HRAM", addr - 0xFF80); - } - else - { - return; - } - - } - - - } - */ -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IDebuggable.cs deleted file mode 100644 index ba2549c719..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IDebuggable.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawkNew -{ - public partial class GBHawkNew : IDebuggable - { - public IDictionary GetCpuFlagsAndRegisters() - { - return new Dictionary - { - ["PCl"] = LibGBHawk.GB_cpu_get_regs(GB_Pntr, 0), - ["PCh"] = LibGBHawk.GB_cpu_get_regs(GB_Pntr, 1), - ["SPl"] = LibGBHawk.GB_cpu_get_regs(GB_Pntr, 2), - ["SPh"] = LibGBHawk.GB_cpu_get_regs(GB_Pntr, 3), - ["A"] = LibGBHawk.GB_cpu_get_regs(GB_Pntr, 4), - ["F"] = LibGBHawk.GB_cpu_get_regs(GB_Pntr, 5), - ["B"] = LibGBHawk.GB_cpu_get_regs(GB_Pntr, 6), - ["C"] = LibGBHawk.GB_cpu_get_regs(GB_Pntr, 7), - ["D"] = LibGBHawk.GB_cpu_get_regs(GB_Pntr, 8), - ["E"] = LibGBHawk.GB_cpu_get_regs(GB_Pntr, 9), - ["H"] = LibGBHawk.GB_cpu_get_regs(GB_Pntr, 10), - ["L"] = LibGBHawk.GB_cpu_get_regs(GB_Pntr, 11), - ["Flag I"] = LibGBHawk.GB_cpu_get_flags(GB_Pntr, 0), - ["Flag C"] = LibGBHawk.GB_cpu_get_flags(GB_Pntr, 1), - ["Flag H"] = LibGBHawk.GB_cpu_get_flags(GB_Pntr, 2), - ["Flag N"] = LibGBHawk.GB_cpu_get_flags(GB_Pntr, 3), - ["Flag Z"] = LibGBHawk.GB_cpu_get_flags(GB_Pntr, 4) - }; - } - - public void SetCpuRegister(string register, int value) - { - switch (register) - { - case ("PCl"): LibGBHawk.GB_cpu_set_regs(GB_Pntr, 0, (byte)value); break; - case ("PCh"): LibGBHawk.GB_cpu_set_regs(GB_Pntr, 1, (byte)value); break; - case ("SPl"): LibGBHawk.GB_cpu_set_regs(GB_Pntr, 2, (byte)value); break; - case ("SPh"): LibGBHawk.GB_cpu_set_regs(GB_Pntr, 3, (byte)value); break; - case ("A"): LibGBHawk.GB_cpu_set_regs(GB_Pntr, 4, (byte)value); break; - case ("F"): LibGBHawk.GB_cpu_set_regs(GB_Pntr, 5, (byte)value); break; - case ("B"): LibGBHawk.GB_cpu_set_regs(GB_Pntr, 6, (byte)value); break; - case ("C"): LibGBHawk.GB_cpu_set_regs(GB_Pntr, 7, (byte)value); break; - case ("D"): LibGBHawk.GB_cpu_set_regs(GB_Pntr, 8, (byte)value); break; - case ("E"): LibGBHawk.GB_cpu_set_regs(GB_Pntr, 9, (byte)value); break; - case ("H"): LibGBHawk.GB_cpu_set_regs(GB_Pntr, 10, (byte)value); break; - case ("L"): LibGBHawk.GB_cpu_set_regs(GB_Pntr, 11, (byte)value); break; - - case ("Flag I"): LibGBHawk.GB_cpu_set_flags(GB_Pntr, 0, value > 0); break; - case ("Flag C"): LibGBHawk.GB_cpu_set_flags(GB_Pntr, 1, value > 0); break; - case ("Flag H"): LibGBHawk.GB_cpu_set_flags(GB_Pntr, 2, value > 0); break; - case ("Flag N"): LibGBHawk.GB_cpu_set_flags(GB_Pntr, 3, value > 0); break; - case ("Flag Z"): LibGBHawk.GB_cpu_set_flags(GB_Pntr, 4, value > 0); break; - } - } - - public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" }); - - public bool CanStep(StepType type) => false; - - [FeatureNotImplemented] - public void Step(StepType type) => throw new NotImplementedException(); - - public long TotalExecutedCycles => (long)LibGBHawk.GB_cpu_cycles(GB_Pntr); - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IEmulator.cs deleted file mode 100644 index 5d587c41d1..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IEmulator.cs +++ /dev/null @@ -1,220 +0,0 @@ -using BizHawk.Common.NumberExtensions; -using BizHawk.Emulation.Common; -using System; -using System.Runtime.InteropServices; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawkNew -{ - public partial class GBHawkNew : IEmulator, IVideoProvider, ISoundProvider - { - public IEmulatorServiceProvider ServiceProvider { get; } - - public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; - - public byte controller_state; - public ushort Acc_X_state; - public ushort Acc_Y_state; - public bool in_vblank_old; - public bool in_vblank; - public bool vblank_rise; - - public bool FrameAdvance(IController controller, bool render, bool rendersound) - { - //Console.WriteLine("-----------------------FRAME-----------------------"); - - //Update the color palette if a setting changed - if (_settings.Palette == GBSettings.PaletteType.BW) - { - color_palette[0] = color_palette_BW[0]; - color_palette[1] = color_palette_BW[1]; - color_palette[2] = color_palette_BW[2]; - color_palette[3] = color_palette_BW[3]; - } - else - { - color_palette[0] = color_palette_Gr[0]; - color_palette[1] = color_palette_Gr[1]; - color_palette[2] = color_palette_Gr[2]; - color_palette[3] = color_palette_Gr[3]; - } - - if (Tracer.Enabled) - { - tracecb = MakeTrace; - } - else - { - tracecb = null; - } - - LibGBHawk.GB_settracecallback(GB_Pntr, tracecb); - - _frame++; - - if (controller.IsPressed("P1 Power")) - { - HardReset(); - } - - _islag = true; - - _islag = do_frame(controller); - - if (_islag) - { - _lagcount++; - } - - return true; - } - - public bool do_frame(IController controller) - { - return LibGBHawk.GB_frame_advance(GB_Pntr, _controllerDeck.ReadPort1(controller), - _controllerDeck.ReadAccX1(controller), - _controllerDeck.ReadAccY1(controller), true, true); - } - - public void do_single_step() - { - LibGBHawk.GB_do_single_step(GB_Pntr); - } - - public void do_controller_check() - { - - } - - public void GetControllerState(IController controller) - { - InputCallbacks.Call(); - controller_state = _controllerDeck.ReadPort1(controller); - - Acc_X_state = _controllerDeck.ReadAccX1(controller); - Acc_Y_state = _controllerDeck.ReadAccY1(controller); - } - - public int Frame => _frame; - - public string SystemId => "GB"; - - public bool DeterministicEmulation { get; set; } - - public void ResetCounters() - { - _frame = 0; - _lagcount = 0; - _islag = false; - } - - public void Dispose() - { - DisposeSound(); - - if (GB_Pntr != IntPtr.Zero) - { - LibGBHawk.GB_destroy(GB_Pntr); - GB_Pntr = IntPtr.Zero; - } - } - - #region Video provider - - public int[] frame_buffer; - - public int[] GetVideoBuffer() - { - LibGBHawk.GB_get_video(GB_Pntr, frame_buffer); - return frame_buffer; - } - - public int VirtualWidth => 160; - public int VirtualHeight => 144; - public int BufferWidth => 160; - public int BufferHeight => 144; - public int BackgroundColor => unchecked((int)0xFF000000); - public int VsyncNumerator => 262144; - public int VsyncDenominator => 4389; - - public static readonly uint[] color_palette_BW = { 0xFFFFFFFF , 0xFFAAAAAA, 0xFF555555, 0xFF000000 }; - public static readonly uint[] color_palette_Gr = { 0xFFA4C505, 0xFF88A905, 0xFF1D551D, 0xFF052505 }; - - public uint[] color_palette = new uint[4]; - - #endregion - - #region Audio - - public BlipBuffer blip_L = new BlipBuffer(25000); - public BlipBuffer blip_R = new BlipBuffer(25000); - - public int[] Aud_L = new int[25000]; - public int[] Aud_R = new int[25000]; - public uint num_samp_L; - public uint num_samp_R; - - const int blipbuffsize = 9000; - - public bool CanProvideAsync => false; - - public void SetSyncMode(SyncSoundMode mode) - { - if (mode != SyncSoundMode.Sync) - { - throw new NotSupportedException("Only sync mode is supported"); - } - } - - public void GetSamplesAsync(short[] samples) - { - throw new NotSupportedException("Async not supported"); - } - - public SyncSoundMode SyncMode => SyncSoundMode.Sync; - - public void GetSamplesSync(out short[] samples, out int nsamp) - { - uint f_clock = LibGBHawk.GB_get_audio(GB_Pntr, Aud_L, ref num_samp_L, Aud_R, ref num_samp_R); - - for (int i = 0; i < num_samp_L; i++) - { - blip_L.AddDelta((uint)Aud_L[i * 2], Aud_L[i * 2 + 1]); - } - - for (int i = 0; i < num_samp_R; i++) - { - blip_R.AddDelta((uint)Aud_R[i * 2], Aud_R[i * 2 + 1]); - } - - blip_L.EndFrame(f_clock); - blip_R.EndFrame(f_clock); - - nsamp = blip_L.SamplesAvailable(); - samples = new short[nsamp * 2]; - - if (nsamp != 0) - { - blip_L.ReadSamplesLeft(samples, nsamp); - blip_R.ReadSamplesRight(samples, nsamp); - } - } - - public void DiscardSamples() - { - blip_L.Clear(); - blip_R.Clear(); - } - - public void DisposeSound() - { - blip_L.Clear(); - blip_R.Clear(); - blip_L.Dispose(); - blip_R.Dispose(); - blip_L = null; - blip_R = null; - } - - #endregion - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IInputPollable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IInputPollable.cs deleted file mode 100644 index 3c35b77ff6..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IInputPollable.cs +++ /dev/null @@ -1,24 +0,0 @@ -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawkNew -{ - public partial class GBHawkNew : IInputPollable - { - public int LagCount - { - get => _lagcount; - set => _lagcount = value; - } - - public bool IsLagFrame - { - get => _islag; - set => _islag = value; - } - - public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem(); - - public bool _islag = true; - private int _lagcount; - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IMemoryDomains.cs deleted file mode 100644 index 04c8a909a4..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IMemoryDomains.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Collections.Generic; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawkNew -{ - public partial class GBHawkNew - { - private IMemoryDomains MemoryDomains; - - public void SetupMemoryDomains() - { - var domains = new List - { - new MemoryDomainDelegate( - "WRAM", - 0x8000, - MemoryDomain.Endian.Little, - addr => LibGBHawk.GB_getram(GB_Pntr, (int)(addr & 0xFFFF)), - (addr, value) => LibGBHawk.GB_setram(GB_Pntr, (int)(addr & 0xFFFF), value), - 1), - new MemoryDomainDelegate( - "ROM", - _rom.Length, - MemoryDomain.Endian.Little, - addr => _rom[addr], - (addr, value) => _rom[addr] = value, - 1), - new MemoryDomainDelegate( - "VRAM", - 0x4000, - MemoryDomain.Endian.Little, - addr => LibGBHawk.GB_getvram(GB_Pntr, (int)(addr & 0xFFFF)), - (addr, value) => LibGBHawk.GB_setvram(GB_Pntr, (int)(addr & 0xFFFF), value), - 1), - new MemoryDomainDelegate( - "OAM", - 0xA0, - MemoryDomain.Endian.Little, - addr => LibGBHawk.GB_getoam(GB_Pntr, (int)(addr & 0xFFFF)), - (addr, value) => LibGBHawk.GB_setoam(GB_Pntr, (int)(addr & 0xFFFF), value), - 1), - new MemoryDomainDelegate( - "HRAM", - 0x80, - MemoryDomain.Endian.Little, - addr => LibGBHawk.GB_gethram(GB_Pntr, (int)(addr & 0xFFFF)), - (addr, value) => LibGBHawk.GB_sethram(GB_Pntr, (int)(addr & 0xFFFF), value), - 1), - new MemoryDomainDelegate( - "System Bus", - 0X10000, - MemoryDomain.Endian.Little, - addr => LibGBHawk.GB_getsysbus(GB_Pntr, (int)(addr & 0xFFFF)), - (addr, value) => LibGBHawk.GB_setsysbus(GB_Pntr, (int)(addr & 0xFFFF), value), - 1), - }; - /* - if (cart_RAM != null) - { - var CartRam = new MemoryDomainByteArray("CartRAM", MemoryDomain.Endian.Little, cart_RAM, true, 1); - domains.Add(CartRam); - } - */ - - MemoryDomains = new MemoryDomainList(domains); - (ServiceProvider as BasicServiceProvider).Register(MemoryDomains); - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.ISaveRam.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.ISaveRam.cs deleted file mode 100644 index 78b086362b..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.ISaveRam.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawkNew -{ - public partial class GBHawkNew : ISaveRam - { - public byte[] CloneSaveRam() - { - return null;// (byte[])cart_RAM?.Clone(); - } - - public void StoreSaveRam(byte[] data) - { - if (_syncSettings.Use_SRAM) - { - //Buffer.BlockCopy(data, 0, cart_RAM, 0, data.Length); - Console.WriteLine("loading SRAM here"); - } - } - - public bool SaveRamModified => false;//has_bat & _syncSettings.Use_SRAM; - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.ISettable.cs deleted file mode 100644 index 3f688ccedd..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.ISettable.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System; -using System.ComponentModel; - -using Newtonsoft.Json; - -using BizHawk.Common; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawkNew -{ - public partial class GBHawkNew : IEmulator, ISettable - { - public GBSettings GetSettings() - { - return _settings.Clone(); - } - - public GBSyncSettings GetSyncSettings() - { - return _syncSettings.Clone(); - } - - public bool PutSettings(GBSettings o) - { - _settings = o; - return false; - } - - public bool PutSyncSettings(GBSyncSettings o) - { - bool ret = GBSyncSettings.NeedsReboot(_syncSettings, o); - _syncSettings = o; - return ret; - } - - private GBSettings _settings = new GBSettings(); - public GBSyncSettings _syncSettings = new GBSyncSettings(); - - public class GBSettings - { - public enum PaletteType - { - BW, - Gr - } - - [DisplayName("Color Mode")] - [Description("Pick Between Green scale and Grey scale colors")] - [DefaultValue(PaletteType.BW)] - public PaletteType Palette { get; set; } - - public GBSettings Clone() - { - return (GBSettings)MemberwiseClone(); - } - - public GBSettings() - { - SettingsUtil.SetDefaultValues(this); - } - } - - public class GBSyncSettings - { - [JsonIgnore] - public string Port1 = GBHawkNewControllerDeck.DefaultControllerName; - - public enum ControllerType - { - Default, - Tilt - } - - [JsonIgnore] - private ControllerType _GBController; - - [DisplayName("Controller")] - [Description("Select Controller Type")] - [DefaultValue(ControllerType.Default)] - public ControllerType GBController - { - get => _GBController; - set - { - if (value == ControllerType.Default) { Port1 = GBHawkNewControllerDeck.DefaultControllerName; } - else { Port1 = "Gameboy Controller + Tilt"; } - - _GBController = value; - } - } - - public enum ConsoleModeType - { - Auto, - GB, - GBC - } - - [DisplayName("Console Mode")] - [Description("Pick which console to run, 'Auto' chooses from ROM extension, 'GB' and 'GBC' chooses the respective system")] - [DefaultValue(ConsoleModeType.Auto)] - public ConsoleModeType ConsoleMode { get; set; } - - [DisplayName("CGB in GBA")] - [Description("Emulate GBA hardware running a CGB game, instead of CGB hardware. Relevant only for titles that detect the presense of a GBA, such as Shantae.")] - [DefaultValue(false)] - public bool GBACGB { get; set; } - - [DisplayName("RTC Initial Time")] - [Description("Set the initial RTC time in terms of elapsed seconds.")] - [DefaultValue(0)] - public int RTCInitialTime - { - get => _RTCInitialTime; - set => _RTCInitialTime = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); - } - - [DisplayName("RTC Offset")] - [Description("Set error in RTC clocking (-127 to 127)")] - [DefaultValue(0)] - public int RTCOffset - { - get => _RTCOffset; - set => _RTCOffset = Math.Max(-127, Math.Min(127, value)); - } - - [DisplayName("Use Existing SaveRAM")] - [Description("When true, existing SaveRAM will be loaded at boot up")] - [DefaultValue(false)] - public bool Use_SRAM { get; set; } - - [JsonIgnore] - private int _RTCInitialTime; - [JsonIgnore] - private int _RTCOffset; - [JsonIgnore] - public ushort _DivInitialTime = 8; - - public GBSyncSettings Clone() - { - return (GBSyncSettings)MemberwiseClone(); - } - - public GBSyncSettings() - { - SettingsUtil.SetDefaultValues(this); - } - - public static bool NeedsReboot(GBSyncSettings x, GBSyncSettings y) - { - return !DeepEquality.DeepEquals(x, y); - } - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IStatable.cs deleted file mode 100644 index e1cd913e19..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.IStatable.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.IO; -using BizHawk.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawkNew -{ - public partial class GBHawkNew - { - private void SyncState(Serializer ser) - { - ser.BeginSection("GB"); - - ser.Sync("Frame", ref _frame); - ser.Sync("LagCount", ref _lagCount); - - ser.EndSection(); - - if (ser.IsReader) - { - ser.Sync(nameof(GB_core), ref GB_core, false); - LibGBHawk.GB_load_state(GB_Pntr, GB_core); - } - else - { - LibGBHawk.GB_save_state(GB_Pntr, GB_core); - ser.Sync(nameof(GB_core), ref GB_core, false); - } - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.cs deleted file mode 100644 index 09151bbed9..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNew.cs +++ /dev/null @@ -1,211 +0,0 @@ -using System; -using System.Text; - -using BizHawk.Common.BufferExtensions; -using BizHawk.Emulation.Common; - -using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy; -using System.Runtime.InteropServices; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawkNew -{ - [Core( - "GBHawkNew", - "", - isPorted: false, - isReleased: true)] - [ServiceNotApplicable(new[] { typeof(IDriveLight) })] - public partial class GBHawkNew : IEmulator, ISaveRam, IDebuggable, IInputPollable, IRegionable, IGameboyCommon, - ISettable - { - public IntPtr GB_Pntr { get; set; } = IntPtr.Zero; - byte[] GB_core = new byte[0x80000]; - - private int _frame = 0; - public int _lagCount = 0; - public bool is_GBC = false; - - public byte[] _bios; - public readonly byte[] _rom; - - [CoreConstructor(new[] { "GB", "GBC" })] - public GBHawkNew(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings) - { - ServiceProvider = new BasicServiceProvider(this); - _settings = (GBSettings)settings ?? new GBSettings(); - _syncSettings = (GBSyncSettings)syncSettings ?? new GBSyncSettings(); - _controllerDeck = new GBHawkNewControllerDeck(_syncSettings.Port1); - - byte[] Bios = null; - - // Load up a BIOS and initialize the correct PPU - if (_syncSettings.ConsoleMode == GBSyncSettings.ConsoleModeType.Auto) - { - if (game.System == "GB") - { - Bios = comm.CoreFileProvider.GetFirmware("GB", "World", true, "BIOS Not Found, Cannot Load"); - } - else - { - Bios = comm.CoreFileProvider.GetFirmware("GBC", "World", true, "BIOS Not Found, Cannot Load"); - is_GBC = true; - } - - } - else if (_syncSettings.ConsoleMode == GBSyncSettings.ConsoleModeType.GB) - { - Bios = comm.CoreFileProvider.GetFirmware("GB", "World", true, "BIOS Not Found, Cannot Load"); - } - else - { - Bios = comm.CoreFileProvider.GetFirmware("GBC", "World", true, "BIOS Not Found, Cannot Load"); - is_GBC = true; - } - - if (Bios == null) - { - throw new MissingFirmwareException("Missing Gamboy Bios"); - } - - _bios = Bios; - _rom = rom; - - GB_Pntr = LibGBHawk.GB_create(); - - char[] MD5_temp = rom.HashMD5(0, rom.Length).ToCharArray(); - - LibGBHawk.GB_load_bios(GB_Pntr, _bios, is_GBC, _syncSettings.GBACGB); - LibGBHawk.GB_load(GB_Pntr, rom, (uint)rom.Length, MD5_temp, (uint)_syncSettings.RTCInitialTime, (uint)_syncSettings.RTCOffset); - - blip_L.SetRates(4194304, 44100); - blip_R.SetRates(4194304, 44100); - - (ServiceProvider as BasicServiceProvider).Register(this); - - SetupMemoryDomains(); - - Header_Length = LibGBHawk.GB_getheaderlength(GB_Pntr); - Disasm_Length = LibGBHawk.GB_getdisasmlength(GB_Pntr); - Reg_String_Length = LibGBHawk.GB_getregstringlength(GB_Pntr); - - var newHeader = new StringBuilder(Header_Length); - LibGBHawk.GB_getheader(GB_Pntr, newHeader, Header_Length); - - Console.WriteLine(Header_Length + " " + Disasm_Length + " " + Reg_String_Length); - - Tracer = new TraceBuffer { Header = newHeader.ToString() }; - - var serviceProvider = ServiceProvider as BasicServiceProvider; - serviceProvider.Register(Tracer); - serviceProvider.Register(new StateSerializer(SyncState)); - - Console.WriteLine("MD5: " + rom.HashMD5(0, rom.Length)); - Console.WriteLine("SHA1: " + rom.HashSHA1(0, rom.Length)); - - HardReset(); - - iptr0 = LibGBHawk.GB_get_ppu_pntrs(GB_Pntr, 0); - iptr1 = LibGBHawk.GB_get_ppu_pntrs(GB_Pntr, 1); - iptr2 = LibGBHawk.GB_get_ppu_pntrs(GB_Pntr, 2); - iptr3 = LibGBHawk.GB_get_ppu_pntrs(GB_Pntr, 3); - - _scanlineCallback = null; - } - - #region GPUViewer - - public bool IsCGBMode() => is_GBC; - - public IntPtr iptr0 = IntPtr.Zero; - public IntPtr iptr1 = IntPtr.Zero; - public IntPtr iptr2 = IntPtr.Zero; - public IntPtr iptr3 = IntPtr.Zero; - - private GPUMemoryAreas _gpuMemory - { - get - { - return new GPUMemoryAreas(iptr0, iptr1, iptr2, iptr3); - } - } - - public LibGBHawk.ScanlineCallback _scanlineCallback; - - public GPUMemoryAreas GetGPU() => _gpuMemory; - - public void SetScanlineCallback(ScanlineCallback callback, int line) - { - if ((callback == null) || (line == -2)) - { - _scanlineCallback = null; - LibGBHawk.GB_setscanlinecallback(GB_Pntr, null, 0); - } - else - { - _scanlineCallback = delegate - { - callback(LibGBHawk.GB_get_LCDC(GB_Pntr)); - }; - LibGBHawk.GB_setscanlinecallback(GB_Pntr, _scanlineCallback, line); - } - - if (line == -2) - { - callback(LibGBHawk.GB_get_LCDC(GB_Pntr)); - } - } - - private PrinterCallback _printerCallback = null; - - public void SetPrinterCallback(PrinterCallback callback) - { - _printerCallback = null; - } - - #endregion - - public DisplayType Region => DisplayType.NTSC; - - private readonly GBHawkNewControllerDeck _controllerDeck; - - public void HardReset() - { - LibGBHawk.GB_Reset(GB_Pntr); - - frame_buffer = new int[VirtualWidth * VirtualHeight]; - } - - private void ExecFetch(ushort addr) - { - uint flags = (uint)(MemoryCallbackFlags.AccessRead); - MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "System Bus"); - } - - #region Trace Logger - public ITraceable Tracer; - - public LibGBHawk.TraceCallback tracecb; - - // these will be constant values assigned during core construction - public int Header_Length; - public int Disasm_Length; - public int Reg_String_Length; - - public void MakeTrace(int t) - { - StringBuilder new_d = new StringBuilder(Disasm_Length); - StringBuilder new_r = new StringBuilder(Reg_String_Length); - - LibGBHawk.GB_getdisassembly(GB_Pntr, new_d, t, Disasm_Length); - LibGBHawk.GB_getregisterstate(GB_Pntr, new_r, t, Reg_String_Length); - - Tracer.Put(new TraceInfo - { - Disassembly = new_d.ToString().PadRight(36), - RegisterInfo = new_r.ToString() - }); - } - - #endregion - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNewControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNewControllerDeck.cs deleted file mode 100644 index 92ff214e9d..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNewControllerDeck.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -using BizHawk.Common; -using BizHawk.Common.ReflectionExtensions; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawkNew -{ - public class GBHawkNewControllerDeck - { - public GBHawkNewControllerDeck(string controller1Name) - { - if (!ValidControllerTypes.ContainsKey(controller1Name)) - { - throw new InvalidOperationException("Invalid controller type: " + controller1Name); - } - - Port1 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller1Name], 1); - - Definition = new ControllerDefinition - { - Name = Port1.Definition.Name, - BoolButtons = Port1.Definition.BoolButtons - .ToList() - }; - - Definition.AxisControls.AddRange(Port1.Definition.AxisControls); - - Definition.AxisRanges.AddRange(Port1.Definition.AxisRanges); - } - - public byte ReadPort1(IController c) - { - return Port1.Read(c); - } - - public ushort ReadAccX1(IController c) - { - return Port1.ReadAccX(c); - } - - public ushort ReadAccY1(IController c) - { - return Port1.ReadAccY(c); - } - - public ControllerDefinition Definition { get; } - - public void SyncState(Serializer ser) - { - ser.BeginSection(nameof(Port1)); - Port1.SyncState(ser); - ser.EndSection(); - } - - private readonly IPort Port1; - - private static Dictionary _controllerTypes; - - public static Dictionary ValidControllerTypes - { - get - { - if (_controllerTypes == null) - { - _controllerTypes = typeof(GBHawkNewControllerDeck).Assembly - .GetTypes() - .Where(t => typeof(IPort).IsAssignableFrom(t)) - .Where(t => !t.IsAbstract && !t.IsInterface) - .ToDictionary(tkey => tkey.DisplayName()); - } - - return _controllerTypes; - } - } - - public static string DefaultControllerName => typeof(StandardControls).DisplayName(); - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNewControllers.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNewControllers.cs deleted file mode 100644 index d3637c0cde..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/GBHawkNewControllers.cs +++ /dev/null @@ -1,216 +0,0 @@ -using System; -using System.ComponentModel; -using System.Linq; - -using BizHawk.Common; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawkNew -{ - /// - /// Represents a GB add on - /// - public interface IPort - { - byte Read(IController c); - - ushort ReadAccX(IController c); - - ushort ReadAccY(IController c); - - ControllerDefinition Definition { get; } - - void SyncState(Serializer ser); - - int PortNum { get; } - } - - [DisplayName("Gameboy Controller")] - public class StandardControls : IPort - { - public StandardControls(int portNum) - { - PortNum = portNum; - Definition = new ControllerDefinition - { - Name = "Gameboy Controller H", - BoolButtons = BaseDefinition - .Select(b => "P" + PortNum + " " + b) - .ToList() - }; - } - - public int PortNum { get; } - - public ControllerDefinition Definition { get; } - - public byte Read(IController c) - { - byte result = 0xFF; - - if (c.IsPressed(Definition.BoolButtons[0])) - { - result -= 4; - } - if (c.IsPressed(Definition.BoolButtons[1])) - { - result -= 8; - } - if (c.IsPressed(Definition.BoolButtons[2])) - { - result -= 2; - } - if (c.IsPressed(Definition.BoolButtons[3])) - { - result -= 1; - } - if (c.IsPressed(Definition.BoolButtons[4])) - { - result -= 128; - } - if (c.IsPressed(Definition.BoolButtons[5])) - { - result -= 64; - } - if (c.IsPressed(Definition.BoolButtons[6])) - { - result -= 32; - } - if (c.IsPressed(Definition.BoolButtons[7])) - { - result -= 16; - } - - return result; - } - - public ushort ReadAccX(IController c) - { - return 0; - } - - public ushort ReadAccY(IController c) - { - return 0; - } - - private static readonly string[] BaseDefinition = - { - "Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power" - }; - - public void SyncState(Serializer ser) - { - //nothing - } - } - - [DisplayName("Gameboy Controller + Tilt")] - public class StandardTilt : IPort - { - public StandardTilt(int portNum) - { - PortNum = portNum; - Definition = new ControllerDefinition - { - Name = "Gameboy Controller + Tilt", - BoolButtons = BaseDefinition - .Select(b => "P" + PortNum + " " + b) - .ToList(), - AxisControls = { "P" + PortNum + " Tilt X", "P" + PortNum + " Tilt Y" }, - AxisRanges = ControllerDefinition.CreateAxisRangePair(-45, 0, 45, ControllerDefinition.AxisPairOrientation.RightAndUp) //TODO verify direction against hardware - }; - } - - public int PortNum { get; } - - public float theta, phi, theta_prev, phi_prev; - - public ControllerDefinition Definition { get; } - - public byte Read(IController c) - { - byte result = 0xFF; - - if (c.IsPressed(Definition.BoolButtons[0])) - { - result -= 4; - } - if (c.IsPressed(Definition.BoolButtons[1])) - { - result -= 8; - } - if (c.IsPressed(Definition.BoolButtons[2])) - { - result -= 2; - } - if (c.IsPressed(Definition.BoolButtons[3])) - { - result -= 1; - } - if (c.IsPressed(Definition.BoolButtons[4])) - { - result -= 128; - } - if (c.IsPressed(Definition.BoolButtons[5])) - { - result -= 64; - } - if (c.IsPressed(Definition.BoolButtons[6])) - { - result -= 32; - } - if (c.IsPressed(Definition.BoolButtons[7])) - { - result -= 16; - } - - return result; - } - - // acc x is the result of rotating around body y AFTER rotating around body x - // therefore this control scheme gives decreasing sensitivity in X as Y rotation inscreases - public ushort ReadAccX(IController c) - { - theta_prev = theta; - phi_prev = phi; - - theta = (float)(c.AxisValue(Definition.AxisControls[1]) * Math.PI / 180.0); - phi = (float)(c.AxisValue(Definition.AxisControls[0]) * Math.PI / 180.0); - - float temp = (float)(Math.Cos(theta) * Math.Sin(phi)); - - // here we add in rates of change parameters. - // a typical rate of change for a fast rotation is guessed at 0.5 rad / frame - // since rotations about X have less of a moment arm compared to by, we take 1/5 of the effect as a baseline - float temp2 = (float)((phi - phi_prev) / 0.5 * 25); - - return (ushort)(0x81D0 - Math.Floor(temp * 125) - temp2); - } - - // acc y is just the sine of the angle - // we assume that ReadAccX is called first, which updates the the states - public ushort ReadAccY(IController c) - { - float temp = (float)Math.Sin(theta); - - // here we add in rates of change parameters. - // a typical rate of change for a fast rotation is guessed at 0.5 rad / frame - // further it will be assumed that the resulting acceleration is roughly eqvuivalent to gravity - float temp2 = (float)((theta - theta_prev)/0.5 * 125); - - return (ushort)(0x81D0 - Math.Floor(temp * 125) + temp2); - } - - private static readonly string[] BaseDefinition = - { - "Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power" - }; - - public void SyncState(Serializer ser) - { - // since we need rate of change of angle, need to savestate them - ser.Sync(nameof(theta), ref theta); - } - } -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/LibGBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/LibGBHawk.cs deleted file mode 100644 index b73db463b8..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk_new/LibGBHawk.cs +++ /dev/null @@ -1,349 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Text; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawkNew -{ - /// - /// static bindings into GBHawk.dll - /// - public static class LibGBHawk - { - # region Core - /// opaque state pointer - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr GB_create(); - - /// opaque state pointer - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_destroy(IntPtr core); - - /// - /// Load BIOS and BASIC image. each must be 16K in size - /// - /// opaque state pointer - /// the rom data, can be disposed of once this function returns - /// is it GBC console - /// is it in GBA mode - /// 0 on success, negative value on failure. - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern int GB_load_bios(IntPtr core, byte[] bios, bool is_GBC, bool GBC_as_GBA); - - /// - /// Load ROM image. - /// - /// opaque state pointer - /// the rom data, can be disposed of once this function returns - /// length of romdata in bytes - /// Hash used for mapper loading - /// Initial RTC time - /// Clck offset for RTC - /// 0 on success, negative value on failure. - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern int GB_load(IntPtr core, byte[] romdata_1, uint length_1, char[] MD5, uint RTC_init, uint RTC_offset); - - /// - /// Reset. - /// - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_Reset(IntPtr core); - - /// - /// Advance a frame and send controller data. - /// - /// opaque state pointer - /// controller data for player 1 - /// controller data for player 2 - /// length of romdata in bytes - /// Mapper number to load core with - /// 0 on success, negative value on failure. - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern bool GB_frame_advance(IntPtr core, byte ctrl1, uint accx, uint accy, bool render, bool sound); - - /// - /// do a singlt step in the core - /// - /// opaque state pointer - - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_do_single_step(IntPtr core); - - /// - /// Get Video data - /// - /// opaque state pointer - /// where to send video to - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_get_video(IntPtr core, int[] videobuf); - - /// - /// Get Video data - /// - /// opaque state pointer - /// where to send left audio to - /// number of left samples - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern uint GB_get_audio(IntPtr core, int[] aud_buf_L, ref uint n_samp_L, int[] aud_buf_R, ref uint n_samp_R); - - #endregion - - #region State Save / Load - - /// - /// Save State - /// - /// opaque state pointer - /// save buffer - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_save_state(IntPtr core, byte[] saver); - - /// - /// Load State - /// - /// opaque state pointer - /// load buffer - [DllImport("GBHAWK.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_load_state(IntPtr core, byte[] loader); - - #endregion - - #region Memory Domain Functions - - /// - /// Read the RAM - /// - /// opaque state pointer - /// ram address - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern byte GB_getram(IntPtr core, int addr); - - /// - /// Read the VRAM - /// - /// opaque state pointer - /// vram address - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern byte GB_getvram(IntPtr core, int addr); - - /// - /// Read the VRAM - /// - /// opaque state pointer - /// vram address - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern byte GB_getoam(IntPtr core, int addr); - - /// - /// Read the VRAM - /// - /// opaque state pointer - /// vram address - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern byte GB_gethram(IntPtr core, int addr); - - /// - /// Read the system bus - /// - /// opaque state pointer - /// system bus address - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern byte GB_getsysbus(IntPtr core, int addr); - - /// - /// Read the RAM - /// - /// opaque state pointer - /// ram address - /// write value - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_setram(IntPtr core, int addr, byte value); - - /// - /// Read the VRAM - /// - /// opaque state pointer - /// vram address - /// write value - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_setvram(IntPtr core, int addr, byte value); - - /// - /// Read the VRAM - /// - /// opaque state pointer - /// vram address - /// write value - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_setoam(IntPtr core, int addr, byte value); - - /// - /// Read the VRAM - /// - /// opaque state pointer - /// vram address - /// write value - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_sethram(IntPtr core, int addr, byte value); - - /// - /// Read the system bus - /// - /// opaque state pointer - /// system bus address - /// write value - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_setsysbus(IntPtr core, int addr, byte value); - - #endregion - - #region Tracer - /// - /// type of the cpu trace callback - /// - /// type of event - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void TraceCallback(int t); - - /// - /// set a callback for trace logging - /// - /// opaque state pointer - /// null to clear - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_settracecallback(IntPtr core, TraceCallback callback); - - /// - /// get the trace logger header length - /// - /// opaque state pointer - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern int GB_getheaderlength(IntPtr core); - - /// - /// get the trace logger disassembly length, a constant - /// - /// opaque state pointer - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern int GB_getdisasmlength(IntPtr core); - - /// - /// get the trace logger register string length, a constant - /// - /// opaque state pointer - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern int GB_getregstringlength(IntPtr core); - - /// - /// get the trace logger header - /// - /// opaque state pointer - /// pointer to const char * - /// null to clear - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_getheader(IntPtr core, StringBuilder h, int l); - - /// - /// get the register state from the cpu - /// - /// opaque state pointer - /// pointer to const char * - /// call type - /// copy length, must be obtained from appropriate get legnth function - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_getregisterstate(IntPtr core, StringBuilder h, int t, int l); - - /// - /// get the opcode disassembly - /// - /// opaque state pointer - /// pointer to const char * - /// call type - /// copy length, must be obtained from appropriate get legnth function - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_getdisassembly(IntPtr core, StringBuilder h, int t, int l); - #endregion - - #region PPU_Viewer - - /// - /// type of the cpu trace callback - /// - /// type of event - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void ScanlineCallback(byte lcdc); - - /// - /// Get PPU Pointers - /// - /// opaque state pointer - /// region to get - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr GB_get_ppu_pntrs(IntPtr core, int sel); - - /// - /// Get PPU Pointers - /// - /// opaque state pointer - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern byte GB_get_LCDC(IntPtr core); - - /// - /// set a callback to occur when ly reaches a particular scanline (so at the beginning of the scanline). - /// when the LCD is active, typically 145 will be the first callback after the beginning of frame advance, - /// and 144 will be the last callback right before frame advance returns - /// - /// opaque state pointer - /// null to clear - /// 0-153 inclusive - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_setscanlinecallback(IntPtr core, ScanlineCallback callback, int sl); - - #endregion - - #region debuggable funcitons - - /// - /// get the current cpu cycle count - /// - /// opaque state pointer - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern int GB_cpu_cycles(IntPtr core); - - /// - /// get the registers - /// - /// opaque state pointer - /// reg number (see the DLL) - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern byte GB_cpu_get_regs(IntPtr core, int reg); - - /// - /// get the flags - /// - /// opaque state pointer - /// flag number (see the DLL) - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern bool GB_cpu_get_flags(IntPtr core, int flag); - - /// - /// get the registers - /// - /// opaque state pointer - /// reg number (see the DLL) - /// value to set - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_cpu_set_regs(IntPtr core, int reg, byte value); - - /// - /// get the flags - /// - /// opaque state pointer - /// flag number (see the DLL) - /// value to set - [DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void GB_cpu_set_flags(IntPtr core, int flag, bool value); - - #endregion - - } -} diff --git a/libHawk/GBHawk/GBHawk.sln b/libHawk/GBHawk/GBHawk.sln deleted file mode 100644 index 3a944659dd..0000000000 --- a/libHawk/GBHawk/GBHawk.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29709.97 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GBHawk", "GBHawk\GBHawk.vcxproj", "{FA59603F-32AB-429A-9186-B46114851290}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {FA59603F-32AB-429A-9186-B46114851290}.Debug|x64.ActiveCfg = Debug|x64 - {FA59603F-32AB-429A-9186-B46114851290}.Debug|x64.Build.0 = Debug|x64 - {FA59603F-32AB-429A-9186-B46114851290}.Debug|x86.ActiveCfg = Debug|Win32 - {FA59603F-32AB-429A-9186-B46114851290}.Debug|x86.Build.0 = Debug|Win32 - {FA59603F-32AB-429A-9186-B46114851290}.Release|x64.ActiveCfg = Release|x64 - {FA59603F-32AB-429A-9186-B46114851290}.Release|x64.Build.0 = Release|x64 - {FA59603F-32AB-429A-9186-B46114851290}.Release|x86.ActiveCfg = Release|Win32 - {FA59603F-32AB-429A-9186-B46114851290}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {ED770D9B-8735-46CA-B51E-F85B00A9C744} - EndGlobalSection -EndGlobal diff --git a/libHawk/GBHawk/GBHawk/Core.h b/libHawk/GBHawk/GBHawk/Core.h deleted file mode 100644 index e76d548b33..0000000000 --- a/libHawk/GBHawk/GBHawk/Core.h +++ /dev/null @@ -1,659 +0,0 @@ -#include -#include -#include -#include - -#include "LR35902.h" -#include "GBAudio.h" -#include "Memory.h" -#include "Timer.h" -#include "SerialPort.h" -#include "Mappers.h" -#include "PPU.h" - -namespace GBHawk -{ - class GBCore - { - public: - GBCore() - { - ppu = nullptr; - mapper = nullptr; - }; - - PPU* ppu; - LR35902 cpu; - GBAudio psg; - MemoryManager MemMap; - Timer timer; - SerialPort serialport; - Mapper* mapper; - - void Load_BIOS(uint8_t* bios, bool GBC_console, bool GBC_as_GBA) - { - MemMap.Load_BIOS(bios, GBC_console, GBC_as_GBA); - } - - void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1, string MD5, uint32_t RTC_initial, uint32_t RTC_offset) - { - MemMap.Load_ROM(ext_rom_1, ext_rom_size_1); - - // After we load the ROM we need to initialize the rest of the components (ppu and mapper) - // tell the cpu the console type - cpu.is_GBC = MemMap.is_GBC; - - //initialize system components - // initialize the proper ppu - if (MemMap.is_GBC) - { - if ((MemMap.header[0x43] != 0x80) && (MemMap.header[0x43] != 0xC0)) - { - ppu = new GBC_GB_PPU(); - } - else - { - ppu = new GBC_PPU(); - } - } - else - { - ppu = new GB_PPU(); - } - - MemMap.ppu_pntr = &ppu[0]; - ppu->mem_ctrl = &MemMap; - - // initialize the proper mapper - Setup_Mapper(MD5, RTC_initial, RTC_offset); - - MemMap.mapper_pntr = &mapper[0]; - - // set up pointers - MemMap.cpu_pntr = &cpu; - MemMap.psg_pntr = &psg; - MemMap.timer_pntr = &timer; - MemMap.serialport_pntr = &serialport; - cpu.mem_ctrl = &MemMap; - - ppu->FlagI = &cpu.FlagI; - ppu->in_vblank = &MemMap.in_vblank; - ppu->vblank_rise = &MemMap.vblank_rise; - ppu->cpu_LY = &cpu.LY; - ppu->REG_FFFF = &MemMap.REG_FFFF; - ppu->REG_FF0F = &MemMap.REG_FF0F; - ppu->_scanlineCallbackLine = &MemMap._scanlineCallbackLine; - ppu->OAM = &MemMap.OAM[0]; - ppu->VRAM = &MemMap.VRAM[0]; - ppu->VRAM_Bank = &MemMap.VRAM_Bank; - ppu->cpu_halted = &cpu.halted; - ppu->_vidbuffer = &MemMap.vidbuffer[0]; - ppu->color_palette = &MemMap.color_palette[0]; - ppu->HDMA_transfer = &MemMap.HDMA_transfer; - ppu->GBC_compat = &MemMap.GBC_compat; - - timer.FlagI = &cpu.FlagI; - timer.REG_FFFF = &MemMap.REG_FFFF; - timer.REG_FF0F = &MemMap.REG_FF0F; - timer.CPU_cycle_pntr = &cpu.TotalExecutedCycles; - - serialport.GBC_compat = &MemMap.GBC_compat; - serialport.FlagI = &cpu.FlagI; - serialport.REG_FFFF = &MemMap.REG_FFFF; - serialport.REG_FF0F = &MemMap.REG_FF0F; - - psg.is_GBC = &MemMap.is_GBC; - psg.double_speed = &MemMap.double_speed; - psg.timer_div_reg = &timer.divider_reg; - - MemMap.mapper_pntr->addr_access = &MemMap.addr_access; - MemMap.mapper_pntr->Acc_X_state = &MemMap.Acc_X_state; - MemMap.mapper_pntr->Acc_Y_state = &MemMap.Acc_Y_state; - MemMap.mapper_pntr->ROM_Length = &MemMap.ROM_Length; - MemMap.mapper_pntr->Cart_RAM_Length = &MemMap.Cart_RAM_Length; - MemMap.mapper_pntr->ROM = &MemMap.ROM[0]; - MemMap.mapper_pntr->Cart_RAM = &MemMap.Cart_RAM[0]; - } - - void Reset() - { - MemMap.GB_bios_register = 0; // bios enable - MemMap.GBC_compat = MemMap.is_GBC; - MemMap.in_vblank = true; // we start off in vblank since the LCD is off - MemMap.in_vblank_old = true; - MemMap.double_speed = false; - MemMap.VRAM_Bank = 0; - MemMap.RAM_Bank = 1; // RAM bank always starts as 1 (even writing zero still sets 1) - - MemMap.Register_Reset(); - timer.Reset(); - ppu->Reset(); - psg.Reset(); - serialport.Reset(); - mapper->Reset(); - cpu.Reset(); - } - - bool FrameAdvance(uint8_t new_controller_1, uint32_t new_accx, uint32_t new_accy, bool render, bool rendersound) - { - int temp_check = 0; - /* - if (cpu.TotalExecutedCycles < 25280600) { - temp_check = 70224; - } - else if (cpu.TotalExecutedCycles < 25347500) { - temp_check = 1000; - } - else { - temp_check = 5; - } - */ - MemMap.new_controller_1 = new_controller_1; - MemMap.new_accx = new_accx; - MemMap.new_accy = new_accy; - - temp_check = 70224; - - for (int i = 0; i < temp_check; i++) - { - // These things do not change speed in GBC double spped mode - psg.tick(); - ppu->tick(); - if (MemMap.Use_MT) { mapper->Mapper_Tick(); } - - if (!MemMap.HDMA_transfer) - { - // These things all tick twice as fast in GBC double speed mode - if (ppu->DMA_start && !cpu.halted) { ppu->DMA_tick(); } - serialport.serial_transfer_tick(); - cpu.ExecuteOne(&MemMap.REG_FF0F, &MemMap.REG_FFFF); - timer.tick(); - - if (MemMap.double_speed) - { - if (ppu->DMA_start && !cpu.halted) { ppu->DMA_tick(); } - serialport.serial_transfer_tick(); - cpu.ExecuteOne(&MemMap.REG_FF0F, &MemMap.REG_FFFF); - timer.tick(); - } - } - else - { - cpu.TotalExecutedCycles++; - timer.tick(); - - if (MemMap.double_speed) - { - cpu.TotalExecutedCycles++; - timer.tick(); - } - } - - MemMap.REG_FF0F_OLD = MemMap.REG_FF0F; - } - - // turn off the screen so the image doesnt persist - // but don't turn off blank_frame yet, it still needs to be true until the next VBL - // this doesn't run for GBC, some games, ex MIB the series 2, rely on the screens persistence while off to make video look smooth. - // But some GB gams, ex Battletoads, turn off the screen for a long time from the middle of the frame, so need to be cleared. - if (ppu->clear_screen) - { - for (int j = 0; j < (160 * 144); j++) { MemMap.frame_buffer[j] = (int)MemMap.color_palette[0]; } - ppu->clear_screen = false; - } - - return MemMap.lagged; - } - - void do_single_step() - { - // These things do not change speed in GBC double spped mode - psg.tick(); - ppu->tick(); - if (MemMap.Use_MT) { mapper->Mapper_Tick(); } - - if (!MemMap.HDMA_transfer) - { - // These things all tick twice as fast in GBC double speed mode - // Note that DMA is halted when the CPU is halted - if (ppu->DMA_start && !cpu.halted) { ppu->DMA_tick(); } - serialport.serial_transfer_tick(); - cpu.ExecuteOne(&MemMap.REG_FF0F, &MemMap.REG_FFFF); - timer.tick(); - - if (MemMap.double_speed) - { - if (ppu->DMA_start && !cpu.halted) { ppu->DMA_tick(); } - serialport.serial_transfer_tick(); - cpu.ExecuteOne(&MemMap.REG_FF0F, &MemMap.REG_FFFF); - timer.tick(); - } - } - else - { - cpu.TotalExecutedCycles++; - timer.tick(); - - if (MemMap.double_speed) - { - cpu.TotalExecutedCycles++; - timer.tick(); - } - } - - if (MemMap.in_vblank && !MemMap.in_vblank_old) - { - MemMap.vblank_rise = true; - } - - MemMap.in_vblank_old = MemMap.in_vblank; - MemMap.REG_FF0F_OLD = MemMap.REG_FF0F; - } - - void GetVideo(uint32_t* dest) - { - uint32_t* src = MemMap.frame_buffer; - uint32_t* dst = dest; - - std::memcpy(dst, src, sizeof uint32_t * 160 * 144); - } - - uint32_t GetAudio(int32_t* dest_L, int32_t* n_samp_L, int32_t* dest_R, int32_t* n_samp_R) - { - int32_t* src = psg.samples_L; - int32_t* dst = dest_L; - - std::memcpy(dst, src, sizeof int32_t * psg.num_samples_L * 2); - n_samp_L[0] = psg.num_samples_L; - - src = psg.samples_R; - dst = dest_R; - - std::memcpy(dst, src, sizeof int32_t * psg.num_samples_R * 2); - n_samp_R[0] = psg.num_samples_R; - - uint32_t temp_int = psg.master_audio_clock; - psg.master_audio_clock = 0; - - psg.num_samples_L = 0; - psg.num_samples_R = 0; - - return temp_int; - } - - void Setup_Mapper(string MD5, uint32_t RTC_initial, uint32_t RTC_offset) - { - // setup up mapper based on header entry - string mppr; - - switch (MemMap.header[0x47]) - { - case 0x0: mapper = new Mapper_Default(); mppr = "NROM"; break; - case 0x1: mapper = new Mapper_MBC1(); mppr = "MBC1"; break; - case 0x2: mapper = new Mapper_MBC1(); mppr = "MBC1"; break; - case 0x3: mapper = new Mapper_MBC1(); mppr = "MBC1"; MemMap.has_bat = true; break; - case 0x5: mapper = new Mapper_MBC2(); mppr = "MBC2"; break; - case 0x6: mapper = new Mapper_MBC2(); mppr = "MBC2"; MemMap.has_bat = true; break; - case 0x8: mapper = new Mapper_Default(); mppr = "NROM"; break; - case 0x9: mapper = new Mapper_Default(); mppr = "NROM"; MemMap.has_bat = true; break; - case 0xB: mapper = new Mapper_MMM01(); mppr = "MMM01"; break; - case 0xC: mapper = new Mapper_MMM01(); mppr = "MMM01"; break; - case 0xD: mapper = new Mapper_MMM01(); mppr = "MMM01"; MemMap.has_bat = true; break; - case 0xF: mapper = new Mapper_MBC3(); mppr = "MBC3"; MemMap.has_bat = true; break; - case 0x10: mapper = new Mapper_MBC3(); mppr = "MBC3"; MemMap.has_bat = true; break; - case 0x11: mapper = new Mapper_MBC3(); mppr = "MBC3"; break; - case 0x12: mapper = new Mapper_MBC3(); mppr = "MBC3"; break; - case 0x13: mapper = new Mapper_MBC3(); mppr = "MBC3"; MemMap.has_bat = true; break; - case 0x19: mapper = new Mapper_MBC5(); mppr = "MBC5"; break; - case 0x1A: mapper = new Mapper_MBC5(); mppr = "MBC5"; MemMap.has_bat = true; break; - case 0x1B: mapper = new Mapper_MBC5(); mppr = "MBC5"; break; - case 0x1C: mapper = new Mapper_MBC5(); mppr = "MBC5"; break; - case 0x1D: mapper = new Mapper_MBC5(); mppr = "MBC5"; break; - case 0x1E: mapper = new Mapper_MBC5(); mppr = "MBC5"; MemMap.has_bat = true; break; - case 0x20: mapper = new Mapper_MBC6(); mppr = "MBC6"; break; - case 0x22: mapper = new Mapper_MBC7(); mppr = "MBC7"; MemMap.has_bat = true; break; - case 0xFC: mapper = new Mapper_Camera(); mppr = "CAM"; MemMap.has_bat = true; break; - case 0xFD: mapper = new Mapper_TAMA5(); mppr = "TAMA5"; MemMap.has_bat = true; break; - case 0xFE: mapper = new Mapper_HuC3(); mppr = "HuC3"; break; - case 0xFF: mapper = new Mapper_HuC1(); mppr = "HuC1"; break; - - // Bootleg mappers - // NOTE: Sachen mapper selection does not account for scrambling, so if another bootleg mapper - // identifies itself as 0x31, this will need to be modified - case 0x31: mapper = new Mapper_Sachen2(); mppr = "Schn2"; break; - - case 0x4: - case 0x7: - case 0xA: - case 0xE: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x1F: - case 0x21: - default: - // mapper not implemented - mapper = nullptr; - } - - // special case for multi cart mappers - if ((MD5 == "97122B9B183AAB4079C8D36A4CE6E9C1") || - (MD5 == "9FB9C42CF52DCFDCFBAD5E61AE1B5777") || - (MD5 == "CF1F58AB72112716D3C615A553B2F481") - ) - { - mapper = new Mapper_MBC1_Multi(); - } - - // Wisdom Tree does not identify their mapper, so use hash instead - if ((MD5 == "2C07CAEE51A1F0C91C72C7C6F380B0F6") || // Joshua - (MD5 == "37E017C8D1A45BAB609FB5B43FB64337") || // Spiritual Warfare - (MD5 == "AB1FA0ED0207B1D0D5F401F0CD17BEBF") || // Exodus - (MD5 == "BA2AC3587B3E1B36DE52E740274071B0") || // Bible - KJV - (MD5 == "8CDDB8B2DCD3EC1A3FDD770DF8BDA07C") // Bible - NIV - ) - { - mapper = new Mapper_WT(); - mppr = "Wtree"; - } - - // special case for bootlegs - if ((MD5 == "CAE0998A899DF2EE6ABA8E7695C2A096")) - { - mapper = new Mapper_RM8(); - } - if ((MD5 == "D3C1924D847BC5D125BF54C2076BE27A")) - { - mapper = new Mapper_Sachen1(); - mppr = "Schn1"; - } - - MemMap.Cart_RAM = nullptr; - - switch (MemMap.header[0x49]) - { - case 1: - MemMap.Cart_RAM = new uint8_t[0x800]; - MemMap.Cart_RAM_Length = 0x800; - break; - case 2: - MemMap.Cart_RAM = new uint8_t[0x2000]; - MemMap.Cart_RAM_Length = 0x2000; - break; - case 3: - MemMap.Cart_RAM = new uint8_t[0x8000]; - MemMap.Cart_RAM_Length = 0x8000; - break; - case 4: - MemMap.Cart_RAM = new uint8_t[0x20000]; - MemMap.Cart_RAM_Length = 0x20000; - break; - case 5: - MemMap.Cart_RAM = new uint8_t[0x10000]; - MemMap.Cart_RAM_Length = 0x10000; - break; - case 0: - MemMap.has_bat = false; - break; - } - - // Sachen maper not known to have RAM - if ((mppr == "Schn1") || (mppr == "Schn2")) - { - MemMap.Cart_RAM = nullptr; - MemMap.Use_MT = true; - } - - // mbc2 carts have built in RAM - if (mppr == "MBC2") - { - MemMap.Cart_RAM = new uint8_t[0x200]; - MemMap.Cart_RAM_Length = 0x200; - } - - // mbc7 has 256 bytes of RAM, regardless of any header info - if (mppr == "MBC7") - { - MemMap.Cart_RAM = new uint8_t[0x100]; - MemMap.Cart_RAM_Length = 0x100; - MemMap.has_bat = true; - } - - // TAMA5 has 0x1000 bytes of RAM, regardless of any header info - if (mppr == "TAMA5") - { - MemMap.Cart_RAM = new uint8_t[0x20]; - MemMap.Cart_RAM_Length = 0x20; - MemMap.has_bat = true; - } - - if (MemMap.Cart_RAM != nullptr && (mppr != "MBC7")) - { - for (uint32_t i = 0; i < MemMap.Cart_RAM_Length; i++) - { - MemMap.Cart_RAM[i] = 0xFF; - } - } - - // Extra RTC initialization for mbc3, HuC3, and TAMA5 - if (mppr == "MBC3") - { - MemMap.Use_MT = true; - - mapper->RTC_Get(RTC_offset, 5); - - int days = (int)floor(RTC_initial / 86400.0); - - int days_upper = ((days & 0x100) >> 8) | ((days & 0x200) >> 2); - - mapper->RTC_Get(days_upper, 4); - mapper->RTC_Get(days & 0xFF, 3); - - int remaining = RTC_initial - (days * 86400); - - int hours = (int)floor(remaining / 3600.0); - - mapper->RTC_Get(hours & 0xFF, 2); - - remaining = remaining - (hours * 3600); - - int minutes = (int)floor(remaining / 60.0); - - mapper->RTC_Get(minutes & 0xFF, 1); - - remaining = remaining - (minutes * 60); - - mapper->RTC_Get(remaining & 0xFF, 0); - } - - if (mppr == "HuC3") - { - MemMap.Use_MT = true; - - int years = (int)floor(RTC_initial / 31536000.0); - - mapper->RTC_Get(years, 24); - - int remaining = RTC_initial - (years * 31536000); - - int days = (int)floor(remaining / 86400.0); - int days_upper = (days >> 8) & 0xF; - - mapper->RTC_Get(days_upper, 20); - mapper->RTC_Get(days & 0xFF, 12); - - remaining = remaining - (days * 86400); - - int minutes = (int)floor(remaining / 60.0); - int minutes_upper = (minutes >> 8) & 0xF; - - mapper->RTC_Get(minutes_upper, 8); - mapper->RTC_Get(remaining & 0xFF, 0); - } - - if (mppr == "TAMA5") - { - MemMap.Use_MT = true; - - // currently no date / time input for TAMA5 - - } - } - - #pragma region State Save / Load - - void SaveState(uint8_t* saver) - { - saver = MemMap.SaveState(saver); - saver = ppu->SaveState(saver); - saver = cpu.SaveState(saver); - - saver = psg.SaveState(saver); - saver = timer.SaveState(saver); - saver = serialport.SaveState(saver); - saver = mapper->SaveState(saver); - } - - void LoadState(uint8_t* loader) - { - loader = MemMap.LoadState(loader); - loader = ppu->LoadState(loader); - loader = cpu.LoadState(loader); - - loader = psg.LoadState(loader); - loader = timer.LoadState(loader); - loader = serialport.LoadState(loader); - loader = mapper->LoadState(loader); - } - - #pragma endregion - - #pragma region Memory Domain Functions - - - uint8_t GetRAM(uint32_t addr) - { - return MemMap.RAM[addr & 0x7FFF]; - } - - uint8_t GetVRAM(uint32_t addr) - { - return MemMap.VRAM[addr & 0x3FFF]; - } - - uint8_t GetOAM(uint32_t addr) - { - return MemMap.OAM[addr]; - } - - uint8_t GetHRAM(uint32_t addr) - { - return MemMap.ZP_RAM[addr & 0x7F]; - } - - uint8_t GetSysBus(uint32_t addr) - { - return MemMap.PeekMemory(addr); - } - - void SetRAM(uint32_t addr, uint8_t value) - { - MemMap.RAM[addr & 0x7FFF] = value; - } - - void SetVRAM(uint32_t addr, uint8_t value) - { - MemMap.VRAM[addr & 0x3FFF] = value; - } - - void SetOAM(uint32_t addr, uint8_t value) - { - MemMap.OAM[addr] = value; - } - - void SetHRAM(uint32_t addr, uint8_t value) - { - MemMap.ZP_RAM[addr & 0x7F] = value; - } - - void SetSysBus(uint32_t addr, uint8_t value) - { - // make poke? - MemMap.WriteMemory(addr, value); - } - - #pragma endregion - - #pragma region Tracer - - void SetTraceCallback(void (*callback)(int)) - { - cpu.TraceCallback = callback; - } - - void SetScanlineCallback(void (*callback)(void), int sl) - { - ppu->scanlineCallback = callback; - MemMap._scanlineCallbackLine = sl; - } - - int GetHeaderLength() - { - return 105 + 1; - } - - int GetDisasmLength() - { - return 48 + 1; - } - - int GetRegStringLength() - { - return 81 + 1; - } - - void GetHeader(char* h, int l) - { - memcpy(h, cpu.TraceHeader, l); - } - - // the copy length l must be supplied ahead of time from GetRegStrngLength - void GetRegisterState(char* r, int t, int l) - { - if (t == 0) - { - memcpy(r, cpu.CPURegisterState().c_str(), l); - } - else - { - memcpy(r, cpu.No_Reg, l); - } - } - - // the copy length l must be supplied ahead of time from GetDisasmLength - void GetDisassembly(char* d, int t, int l) - { - if (t == 0) - { - memcpy(d, cpu.CPUDisassembly().c_str(), l); - } - else if (t == 1) - { - memcpy(d, cpu.Un_halt_event, l); - } - else if (t == 2) - { - memcpy(d, cpu.IRQ_event, l); - } - else - { - memcpy(d, cpu.Un_halt_event, l); - } - } - - #pragma endregion - }; -} - diff --git a/libHawk/GBHawk/GBHawk/GBAudio.h b/libHawk/GBHawk/GBHawk/GBAudio.h deleted file mode 100644 index 7ed2b6d2e1..0000000000 --- a/libHawk/GBHawk/GBHawk/GBAudio.h +++ /dev/null @@ -1,1388 +0,0 @@ -#include -#include -#include -#include - -using namespace std; - -namespace GBHawk -{ - class GBAudio - { - public: - - #pragma region GBAudio - - // Core variables - bool* is_GBC = nullptr; - bool* double_speed = nullptr; - uint32_t* timer_div_reg = nullptr; - - uint32_t num_samples_L, num_samples_R; - int32_t samples_L[25000] = {}; - int32_t samples_R[25000] = {}; - - bool DUTY_CYCLES[32] = {false, false, false, false, false, false, false, true, - true, false, false, false, false, false, false, true, - true, false, false, false, false, true, true, true, - false, true, true, true, true, true, true, false}; - - uint32_t DIVISOR[8] = { 8, 16, 32, 48, 64, 80, 96, 112 }; - - - uint32_t NR10 = 0; - uint32_t NR11 = 1; - uint32_t NR12 = 2; - uint32_t NR13 = 3; - uint32_t NR14 = 4; - uint32_t NR21 = 5; - uint32_t NR22 = 6; - uint32_t NR23 = 7; - uint32_t NR24 = 8; - uint32_t NR30 = 9; - uint32_t NR31 = 10; - uint32_t NR32 = 11; - uint32_t NR33 = 12; - uint32_t NR34 = 13; - uint32_t NR41 = 14; - uint32_t NR42 = 15; - uint32_t NR43 = 16; - uint32_t NR44 = 17; - uint32_t NR50 = 18; - uint32_t NR51 = 19; - uint32_t NR52 = 20; - - uint32_t unused_bits[21] = { 0x80, 0x3F, 0x00, 0xFF, 0xBF, - 0x3F, 0x00, 0xFF, 0xBF, - 0x7F, 0xFF, 0x9F, 0xFF, 0xBF, - 0xFF, 0x00, 0x00, 0xBF, - 0x00, 0x00, 0x70}; - - uint8_t Audio_Regs[21]; - - uint8_t Wave_RAM[16]; - - - // Audio Variables - // derived - bool WAVE_DAC_pow; - bool NOISE_wdth_md; - bool SQ1_negate; - bool SQ1_trigger, SQ2_trigger, WAVE_trigger, NOISE_trigger; - bool SQ1_len_en, SQ2_len_en, WAVE_len_en, NOISE_len_en; - bool SQ1_env_add, SQ2_env_add, NOISE_env_add; - uint8_t WAVE_vol_code; - uint8_t NOISE_clk_shft; - uint8_t NOISE_div_code; - uint8_t SQ1_shift; - uint8_t SQ1_duty, SQ2_duty; - uint8_t SQ1_st_vol, SQ2_st_vol, NOISE_st_vol; - uint8_t SQ1_per, SQ2_per, NOISE_per; - uint8_t SQ1_swp_prd; - uint32_t SQ1_frq, SQ2_frq, WAVE_frq; - uint32_t SQ1_length, SQ2_length, WAVE_length, NOISE_length; - // state - bool WAVE_can_get; - bool SQ1_calc_done; - bool SQ1_swp_enable; - bool SQ1_vol_done, SQ2_vol_done, NOISE_vol_done; - bool SQ1_enable, SQ2_enable, WAVE_enable, NOISE_enable; - uint8_t SQ1_vol_state, SQ2_vol_state, NOISE_vol_state; - uint8_t SQ1_duty_cntr, SQ2_duty_cntr; - uint8_t WAVE_wave_cntr; - uint32_t SQ1_frq_shadow; - uint32_t SQ1_intl_cntr, SQ2_intl_cntr, WAVE_intl_cntr, NOISE_intl_cntr; - uint32_t SQ1_vol_per, SQ2_vol_per, NOISE_vol_per; - uint32_t SQ1_intl_swp_cnt; - uint32_t NOISE_LFSR; - uint32_t SQ1_len_cntr, SQ2_len_cntr, WAVE_len_cntr, NOISE_len_cntr; - // computed - uint32_t SQ1_output, SQ2_output, WAVE_output, NOISE_output; - - // Contol Variables - bool AUD_CTRL_vin_L_en = false; - bool AUD_CTRL_vin_R_en = false; - bool AUD_CTRL_sq1_L_en = false; - bool AUD_CTRL_sq2_L_en = false; - bool AUD_CTRL_wave_L_en = false; - bool AUD_CTRL_noise_L_en = false; - bool AUD_CTRL_sq1_R_en = false; - bool AUD_CTRL_sq2_R_en = false; - bool AUD_CTRL_wave_R_en = false; - bool AUD_CTRL_noise_R_en = false; - bool AUD_CTRL_power = false; - uint8_t AUD_CTRL_vol_L; - uint8_t AUD_CTRL_vol_R; - - uint32_t sequencer_len, sequencer_vol, sequencer_swp; - bool timer_bit_old = false; - - uint8_t sample; - - uint32_t master_audio_clock; - - uint32_t latched_sample_L, latched_sample_R; - - uint32_t SQ1_bias_gain, SQ2_bias_gain, WAVE_bias_gain, NOISE_bias_gain; - - uint8_t ReadReg(int addr) - { - uint8_t ret = 0; - - switch (addr) - { - case 0xFF10: ret = (uint8_t)(Audio_Regs[NR10] | unused_bits[NR10]); break; // NR10 (sweep) - case 0xFF11: ret = (uint8_t)(Audio_Regs[NR11] | unused_bits[NR11]); break; // NR11 (sound length / wave pattern duty %) - case 0xFF12: ret = (uint8_t)(Audio_Regs[NR12] | unused_bits[NR12]); break; // NR12 (envelope) - case 0xFF13: ret = (uint8_t)(Audio_Regs[NR13] | unused_bits[NR13]); break; // NR13 (freq low) - case 0xFF14: ret = (uint8_t)(Audio_Regs[NR14] | unused_bits[NR14]); break; // NR14 (freq hi) - case 0xFF16: ret = (uint8_t)(Audio_Regs[NR21] | unused_bits[NR21]); break; // NR21 (sound length / wave pattern duty %) - case 0xFF17: ret = (uint8_t)(Audio_Regs[NR22] | unused_bits[NR22]); break; // NR22 (envelope) - case 0xFF18: ret = (uint8_t)(Audio_Regs[NR23] | unused_bits[NR23]); break; // NR23 (freq low) - case 0xFF19: ret = (uint8_t)(Audio_Regs[NR24] | unused_bits[NR24]); break; // NR24 (freq hi) - case 0xFF1A: ret = (uint8_t)(Audio_Regs[NR30] | unused_bits[NR30]); break; // NR30 (on/off) - case 0xFF1B: ret = (uint8_t)(Audio_Regs[NR31] | unused_bits[NR31]); break; // NR31 (length) - case 0xFF1C: ret = (uint8_t)(Audio_Regs[NR32] | unused_bits[NR32]); break; // NR32 (level output) - case 0xFF1D: ret = (uint8_t)(Audio_Regs[NR33] | unused_bits[NR33]); break; // NR33 (freq low) - case 0xFF1E: ret = (uint8_t)(Audio_Regs[NR34] | unused_bits[NR34]); break; // NR34 (freq hi) - case 0xFF20: ret = (uint8_t)(Audio_Regs[NR41] | unused_bits[NR41]); break; // NR41 (length) - case 0xFF21: ret = (uint8_t)(Audio_Regs[NR42] | unused_bits[NR42]); break; // NR42 (envelope) - case 0xFF22: ret = (uint8_t)(Audio_Regs[NR43] | unused_bits[NR43]); break; // NR43 (shift) - case 0xFF23: ret = (uint8_t)(Audio_Regs[NR44] | unused_bits[NR44]); break; // NR44 (trigger) - case 0xFF24: ret = (uint8_t)(Audio_Regs[NR50] | unused_bits[NR50]); break; // NR50 (ctrl) - case 0xFF25: ret = (uint8_t)(Audio_Regs[NR51] | unused_bits[NR51]); break; // NR51 (ctrl) - case 0xFF26: ret = (uint8_t)(Read_NR52() | unused_bits[NR52]); break; // NR52 (ctrl) - - // wave ram table - case 0xFF30: - case 0xFF31: - case 0xFF32: - case 0xFF33: - case 0xFF34: - case 0xFF35: - case 0xFF36: - case 0xFF37: - case 0xFF38: - case 0xFF39: - case 0xFF3A: - case 0xFF3B: - case 0xFF3C: - case 0xFF3D: - case 0xFF3E: - case 0xFF3F: - if (WAVE_enable) - { - if (WAVE_can_get || is_GBC[0]) { ret = Wave_RAM[WAVE_wave_cntr >> 1]; } - else { ret = 0xFF; } - } - else { ret = Wave_RAM[addr & 0x0F]; } - - break; - } - - return ret; - } - - void WriteReg(int addr, uint8_t value) - { - // while power is on, everything is writable - //Console.WriteLine((addr & 0xFF) + " " + value); - if (AUD_CTRL_power) - { - switch (addr) - { - case 0xFF10: // NR10 (sweep) - Audio_Regs[NR10] = value; - SQ1_swp_prd = (uint8_t)((value & 0x70) >> 4); - SQ1_negate = (value & 8) > 0; - SQ1_shift = (uint8_t)(value & 7); - - if (!SQ1_negate && SQ1_calc_done) { SQ1_enable = false; calculate_bias_gain_1(); } - break; - case 0xFF11: // NR11 (sound length / wave pattern duty %) - Audio_Regs[NR11] = value; - SQ1_duty = (uint8_t)((value & 0xC0) >> 6); - SQ1_length = (uint32_t)(64 - (value & 0x3F)); - SQ1_len_cntr = SQ1_length; - break; - case 0xFF12: // NR12 (envelope) - SQ1_st_vol = (uint8_t)((value & 0xF0) >> 4); - SQ1_env_add = (value & 8) > 0; - SQ1_per = (uint8_t)(value & 7); - - // several glitchy effects happen when writing to NRx2 during audio playing - if (((Audio_Regs[NR12] & 7) == 0) && !SQ1_vol_done) { SQ1_vol_state++; } - else if ((Audio_Regs[NR12] & 8) == 0) { SQ1_vol_state += 2; } - - if (((Audio_Regs[NR12] ^ value) & 8) > 0) { SQ1_vol_state = (uint8_t)(0x10 - SQ1_vol_state); } - - SQ1_vol_state &= 0xF; - - if ((value & 0xF8) == 0) { SQ1_enable = SQ1_swp_enable = false; } - Audio_Regs[NR12] = value; - - calculate_bias_gain_1(); - break; - case 0xFF13: // NR13 (freq low) - Audio_Regs[NR13] = value; - SQ1_frq &= 0x700; - SQ1_frq |= value; - break; - case 0xFF14: // NR14 (freq hi) - Audio_Regs[NR14] = value; - SQ1_trigger = (value & 0x80) > 0; - SQ1_frq &= 0xFF; - SQ1_frq |= (uint32_t)((value & 7) << 8); - - if (((sequencer_len & 1) > 0)) - { - if (!SQ1_len_en && ((value & 0x40) > 0) && (SQ1_len_cntr > 0)) - { - SQ1_len_cntr--; - if ((SQ1_len_cntr == 0) && !SQ1_trigger) { SQ1_enable = SQ1_swp_enable = false; } - } - } - - if (SQ1_trigger) - { - SQ1_enable = true; - SQ1_vol_done = false; - if (SQ1_len_cntr == 0) - { - SQ1_len_cntr = 64; - if (((value & 0x40) > 0) && ((sequencer_len & 1) > 0)) { SQ1_len_cntr--; } - } - SQ1_vol_state = SQ1_st_vol; - SQ1_vol_per = (SQ1_per > 0) ? SQ1_per : 8; - SQ1_frq_shadow = SQ1_frq; - SQ1_intl_cntr = (2048 - SQ1_frq_shadow) * 4; - - SQ1_intl_swp_cnt = SQ1_swp_prd > 0 ? SQ1_swp_prd : 8; - SQ1_calc_done = false; - - if ((SQ1_shift > 0) || (SQ1_swp_prd > 0)) - { - SQ1_swp_enable = true; - } - else - { - SQ1_swp_enable = false; - } - - if (SQ1_shift > 0) - { - int shadow_frq = SQ1_frq_shadow; - shadow_frq = shadow_frq >> SQ1_shift; - if (SQ1_negate) { shadow_frq = -shadow_frq; } - shadow_frq += SQ1_frq_shadow; - - // disable channel if overflow - if ((uint32_t)shadow_frq > 2047) - { - SQ1_enable = SQ1_swp_enable = false; - } - - // set negate mode flag that disables channel is negate clerar - if (SQ1_negate) { SQ1_calc_done = true; } - } - - if ((SQ1_vol_state == 0) && !SQ1_env_add) { SQ1_enable = SQ1_swp_enable = false; } - } - - calculate_bias_gain_1(); - SQ1_len_en = (value & 0x40) > 0; - break; - case 0xFF16: // NR21 (sound length / wave pattern duty %) - Audio_Regs[NR21] = value; - SQ2_duty = (uint8_t)((value & 0xC0) >> 6); - SQ2_length = (uint32_t)(64 - (value & 0x3F)); - SQ2_len_cntr = SQ2_length; - break; - case 0xFF17: // NR22 (envelope) - SQ2_st_vol = (uint8_t)((value & 0xF0) >> 4); - SQ2_env_add = (value & 8) > 0; - SQ2_per = (uint8_t)(value & 7); - - // several glitchy effects happen when writing to NRx2 during audio playing - if (((Audio_Regs[NR22] & 7) == 0) && !SQ2_vol_done) { SQ2_vol_state++; } - else if ((Audio_Regs[NR22] & 8) == 0) { SQ2_vol_state += 2; } - - if (((Audio_Regs[NR22] ^ value) & 8) > 0) { SQ2_vol_state = (uint8_t)(0x10 - SQ2_vol_state); } - - SQ2_vol_state &= 0xF; - if ((value & 0xF8) == 0) { SQ2_enable = false; } - Audio_Regs[NR22] = value; - - calculate_bias_gain_2(); - break; - case 0xFF18: // NR23 (freq low) - Audio_Regs[NR23] = value; - SQ2_frq &= 0x700; - SQ2_frq |= value; - break; - case 0xFF19: // NR24 (freq hi) - Audio_Regs[NR24] = value; - SQ2_trigger = (value & 0x80) > 0; - SQ2_frq &= 0xFF; - SQ2_frq |= (uint32_t)((value & 7) << 8); - - if ((sequencer_len & 1) > 0) - { - if (!SQ2_len_en && ((value & 0x40) > 0) && (SQ2_len_cntr > 0)) - { - SQ2_len_cntr--; - if ((SQ2_len_cntr == 0) && !SQ2_trigger) { SQ2_enable = false; } - } - } - - if (SQ2_trigger) - { - SQ2_enable = true; - SQ2_vol_done = false; - - if (SQ2_len_cntr == 0) - { - SQ2_len_cntr = 64; - if (((value & 0x40) > 0) && ((sequencer_len & 1) > 0)) { SQ2_len_cntr--; } - } - SQ2_intl_cntr = (2048 - SQ2_frq) * 4; - SQ2_vol_state = SQ2_st_vol; - SQ2_vol_per = (SQ2_per > 0) ? SQ2_per : 8; - if ((SQ2_vol_state == 0) && !SQ2_env_add) { SQ2_enable = false; } - } - calculate_bias_gain_2(); - SQ2_len_en = (value & 0x40) > 0; - break; - case 0xFF1A: // NR30 (on/off) - Audio_Regs[NR30] = value; - WAVE_DAC_pow = (value & 0x80) > 0; - if (!WAVE_DAC_pow) { WAVE_enable = false; } - //calculate_bias_gain_w(); - break; - case 0xFF1B: // NR31 (length) - Audio_Regs[NR31] = value; - WAVE_length = (uint32_t)(256 - value); - WAVE_len_cntr = WAVE_length; - break; - case 0xFF1C: // NR32 (level output) - Audio_Regs[NR32] = value; - WAVE_vol_code = (uint8_t)((value & 0x60) >> 5); - break; - case 0xFF1D: // NR33 (freq low) - Audio_Regs[NR33] = value; - WAVE_frq &= 0x700; - WAVE_frq |= value; - break; - case 0xFF1E: // NR34 (freq hi) - Audio_Regs[NR34] = value; - WAVE_trigger = (value & 0x80) > 0; - WAVE_frq &= 0xFF; - WAVE_frq |= (uint32_t)((value & 7) << 8); - - if ((sequencer_len & 1) > 0) - { - if (!WAVE_len_en && ((value & 0x40) > 0) && (WAVE_len_cntr > 0)) - { - WAVE_len_cntr--; - if ((WAVE_len_cntr == 0) && !WAVE_trigger) { WAVE_enable = false; } - } - } - - if (WAVE_trigger) - { - // some corruption occurs if triggering while reading - if (WAVE_enable && (WAVE_intl_cntr == 2) && !is_GBC[0]) - { - // we want to use the previous wave cntr value since it was just incremented - int t_wave_cntr = (WAVE_wave_cntr + 1) & 31; - if ((t_wave_cntr >> 1) < 4) - { - Wave_RAM[0] = Wave_RAM[t_wave_cntr >> 1]; - } - else - { - Wave_RAM[0] = Wave_RAM[(t_wave_cntr >> 3) * 4]; - Wave_RAM[1] = Wave_RAM[(t_wave_cntr >> 3) * 4 + 1]; - Wave_RAM[2] = Wave_RAM[(t_wave_cntr >> 3) * 4 + 2]; - Wave_RAM[3] = Wave_RAM[(t_wave_cntr >> 3) * 4 + 3]; - } - } - - WAVE_enable = true; - - if (WAVE_len_cntr == 0) - { - WAVE_len_cntr = 256; - if (((value & 0x40) > 0) && ((sequencer_len & 1) > 0)) { WAVE_len_cntr--; } - } - WAVE_intl_cntr = (2048 - WAVE_frq) * 2 + 6; // trigger delay for wave channel - WAVE_wave_cntr = 0; - if (!WAVE_DAC_pow) { WAVE_enable = false; } - } - - //calculate_bias_gain_w(); - WAVE_len_en = (value & 0x40) > 0; - break; - case 0xFF20: // NR41 (length) - Audio_Regs[NR41] = value; - NOISE_length = (uint32_t)(64 - (value & 0x3F)); - NOISE_len_cntr = NOISE_length; - break; - case 0xFF21: // NR42 (envelope) - NOISE_st_vol = (uint8_t)((value & 0xF0) >> 4); - NOISE_env_add = (value & 8) > 0; - NOISE_per = (uint8_t)(value & 7); - - // several glitchy effects happen when writing to NRx2 during audio playing - if (((Audio_Regs[NR42] & 7) == 0) && !NOISE_vol_done) { NOISE_vol_state++; } - else if ((Audio_Regs[NR42] & 8) == 0) { NOISE_vol_state += 2; } - - if (((Audio_Regs[NR42] ^ value) & 8) > 0) { NOISE_vol_state = (uint8_t)(0x10 - NOISE_vol_state); } - - NOISE_vol_state &= 0xF; - if ((value & 0xF8) == 0) { NOISE_enable = false; } - Audio_Regs[NR42] = value; - - calculate_bias_gain_n(); - break; - case 0xFF22: // NR43 (shift) - Audio_Regs[NR43] = value; - NOISE_clk_shft = (uint8_t)((value & 0xF0) >> 4); - NOISE_wdth_md = (value & 8) > 0; - NOISE_div_code = (uint8_t)(value & 7); - break; - case 0xFF23: // NR44 (trigger) - Audio_Regs[NR44] = value; - NOISE_trigger = (value & 0x80) > 0; - - if ((sequencer_len & 1) > 0) - { - if (!NOISE_len_en && ((value & 0x40) > 0) && (NOISE_len_cntr > 0)) - { - NOISE_len_cntr--; - if ((NOISE_len_cntr == 0) && !NOISE_trigger) { NOISE_enable = false; } - } - } - - if (NOISE_trigger) - { - NOISE_enable = true; - NOISE_vol_done = false; - - if (NOISE_len_cntr == 0) - { - NOISE_len_cntr = 64; - if (((value & 0x40) > 0) && ((sequencer_len & 1) > 0)) { NOISE_len_cntr--; } - } - NOISE_intl_cntr = (DIVISOR[NOISE_div_code] << NOISE_clk_shft); - NOISE_vol_state = NOISE_st_vol; - NOISE_vol_per = (NOISE_per > 0) ? NOISE_per : 8; - NOISE_LFSR = 0x7FFF; - if ((NOISE_vol_state == 0) && !NOISE_env_add) { NOISE_enable = false; } - } - - calculate_bias_gain_n(); - NOISE_len_en = (value & 0x40) > 0; - break; - case 0xFF24: // NR50 (ctrl) - Audio_Regs[NR50] = value; - AUD_CTRL_vin_L_en = (value & 0x80) > 0; - AUD_CTRL_vol_L = (uint8_t)((value & 0x70) >> 4); - AUD_CTRL_vin_R_en = (value & 8) > 0; - AUD_CTRL_vol_R = (uint8_t)(value & 7); - - calculate_bias_gain_a(); - break; - case 0xFF25: // NR51 (ctrl) - Audio_Regs[NR51] = value; - AUD_CTRL_noise_L_en = (value & 0x80) > 0; - AUD_CTRL_wave_L_en = (value & 0x40) > 0; - AUD_CTRL_sq2_L_en = (value & 0x20) > 0; - AUD_CTRL_sq1_L_en = (value & 0x10) > 0; - AUD_CTRL_noise_R_en = (value & 8) > 0; - AUD_CTRL_wave_R_en = (value & 4) > 0; - AUD_CTRL_sq2_R_en = (value & 2) > 0; - AUD_CTRL_sq1_R_en = (value & 1) > 0; - - calculate_bias_gain_a(); - break; - case 0xFF26: // NR52 (ctrl) - // NOTE: Make sure to do the power off first since it will call the write_reg function again - if ((value & 0x80) == 0) { power_off(); } - AUD_CTRL_power = (value & 0x80) > 0; - break; - - // wave ram table - case 0xFF30: - case 0xFF31: - case 0xFF32: - case 0xFF33: - case 0xFF34: - case 0xFF35: - case 0xFF36: - case 0xFF37: - case 0xFF38: - case 0xFF39: - case 0xFF3A: - case 0xFF3B: - case 0xFF3C: - case 0xFF3D: - case 0xFF3E: - case 0xFF3F: - if (WAVE_enable) - { - if (WAVE_can_get || is_GBC[0]) { Wave_RAM[WAVE_wave_cntr >> 1] = value; } - } - else - { - Wave_RAM[addr & 0xF] = value; - } - - break; - } - } - // when power is off, only length counters and waveRAM are effected by writes - // ON GBC, length counters cannot be written to either - else - { - switch (addr) - { - case 0xFF11: // NR11 (sound length / wave pattern duty %) - if (!is_GBC[0]) - { - SQ1_length = (uint32_t)(64 - (value & 0x3F)); - SQ1_len_cntr = SQ1_length; - } - break; - case 0xFF16: // NR21 (sound length / wave pattern duty %) - if (!is_GBC[0]) - { - SQ2_length = (uint32_t)(64 - (value & 0x3F)); - SQ2_len_cntr = SQ2_length; - } - break; - case 0xFF1B: // NR31 (length) - if (!is_GBC[0]) - { - WAVE_length = (uint32_t)(256 - value); - WAVE_len_cntr = WAVE_length; - } - break; - case 0xFF20: // NR41 (length) - if (!is_GBC[0]) - { - NOISE_length = (uint32_t)(64 - (value & 0x3F)); - NOISE_len_cntr = NOISE_length; - } - break; - case 0xFF26: // NR52 (ctrl) - AUD_CTRL_power = (value & 0x80) > 0; - if (AUD_CTRL_power) - { - sequencer_vol = 0; - sequencer_len = 0; - sequencer_swp = 0; - } - break; - - // wave ram table - case 0xFF30: - case 0xFF31: - case 0xFF32: - case 0xFF33: - case 0xFF34: - case 0xFF35: - case 0xFF36: - case 0xFF37: - case 0xFF38: - case 0xFF39: - case 0xFF3A: - case 0xFF3B: - case 0xFF3C: - case 0xFF3D: - case 0xFF3E: - case 0xFF3F: - Wave_RAM[addr & 0x0F] = value; - break; - } - } - } - - void tick() - { - // calculate square1's output - if (SQ1_enable) - { - SQ1_intl_cntr--; - if (SQ1_intl_cntr == 0) - { - SQ1_intl_cntr = (2048 - SQ1_frq) * 4; - SQ1_duty_cntr++; - SQ1_duty_cntr &= 7; - - SQ1_output = DUTY_CYCLES[SQ1_duty * 8 + SQ1_duty_cntr] ? SQ1_vol_state : SQ1_bias_gain; - - // avoid aliasing at high frequenices - //if (SQ1_frq > 0x7F0) { SQ1_output = 0; } - } - } - - // calculate square2's output - if (SQ2_enable) - { - SQ2_intl_cntr--; - if (SQ2_intl_cntr == 0) - { - SQ2_intl_cntr = (2048 - SQ2_frq) * 4; - SQ2_duty_cntr++; - SQ2_duty_cntr &= 7; - - SQ2_output = DUTY_CYCLES[SQ2_duty * 8 + SQ2_duty_cntr] ? SQ2_vol_state : SQ2_bias_gain; - - // avoid aliasing at high frequenices - //if (SQ2_frq > 0x7F0) { SQ2_output = 0; } - } - } - - // calculate wave output - WAVE_can_get = false; - if (WAVE_enable) - { - WAVE_intl_cntr--; - - if (WAVE_intl_cntr == 0) - { - WAVE_can_get = true; - - WAVE_intl_cntr = (2048 - WAVE_frq) * 2; - - if ((WAVE_wave_cntr & 1) == 0) - { - sample = (uint8_t)(sample >> 4); - } - - if (WAVE_vol_code == 0) - { - sample = (uint8_t)((sample & 0xF) >> 4); - } - else if (WAVE_vol_code == 1) - { - sample = (uint8_t)(sample & 0xF); - } - else if (WAVE_vol_code == 2) - { - sample = (uint8_t)((sample & 0xF) >> 1); - } - else - { - sample = (uint8_t)((sample & 0xF) >> 2); - } - - WAVE_output = sample; - - // NOTE: The sample buffer is only reloaded after the current sample is played, even if just triggered - WAVE_wave_cntr++; - WAVE_wave_cntr &= 0x1F; - sample = Wave_RAM[WAVE_wave_cntr >> 1]; - } - } - - // calculate noise output - if (NOISE_enable) - { - NOISE_intl_cntr--; - if (NOISE_intl_cntr == 0) - { - NOISE_intl_cntr = (DIVISOR[NOISE_div_code] << NOISE_clk_shft); - int bit_lfsr = (NOISE_LFSR & 1) ^ ((NOISE_LFSR & 2) >> 1); - - NOISE_LFSR = (NOISE_LFSR >> 1) & 0x3FFF; - NOISE_LFSR |= (bit_lfsr << 14); - - if (NOISE_wdth_md) - { - NOISE_LFSR = NOISE_LFSR & 0x7FBF; - NOISE_LFSR |= (bit_lfsr << 6); - } - - NOISE_output = (NOISE_LFSR & 1) > 0 ? NOISE_bias_gain : NOISE_vol_state; - } - } - - // add up components to each channel - int L_final = 0; - int R_final = 0; - - if (AUD_CTRL_sq1_L_en) { L_final += SQ1_output; } - if (AUD_CTRL_sq2_L_en) { L_final += SQ2_output; } - if (AUD_CTRL_wave_L_en) { L_final += WAVE_output; } - if (AUD_CTRL_noise_L_en) { L_final += NOISE_output; } - - if (AUD_CTRL_sq1_R_en) { R_final += SQ1_output; } - if (AUD_CTRL_sq2_R_en) { R_final += SQ2_output; } - if (AUD_CTRL_wave_R_en) { R_final += WAVE_output; } - if (AUD_CTRL_noise_R_en) { R_final += NOISE_output; } - - L_final *= (AUD_CTRL_vol_L + 1) * 40; - R_final *= (AUD_CTRL_vol_R + 1) * 40; - - if (L_final != latched_sample_L) - { - samples_L[num_samples_L * 2] = master_audio_clock; - samples_L[num_samples_L * 2 + 1] = L_final - latched_sample_L; - - num_samples_L++; - - latched_sample_L = L_final; - } - - if (R_final != latched_sample_R) - { - samples_R[num_samples_R * 2] = master_audio_clock; - samples_R[num_samples_R * 2 + 1] = R_final - latched_sample_R; - - num_samples_R++; - - latched_sample_R = R_final; - } - - master_audio_clock++; - - // frame sequencer ticks at a rate of 512 hz (or every time a 13 bit counter rolls over) - // the sequencer is actually the timer DIV register - // so if it's constantly written to, these values won't update - bool check = double_speed[0] ? ((timer_div_reg[0] & 0x2000) > 0) : ((timer_div_reg[0] & 0x1000) > 0); - - if (check && !timer_bit_old) - { - sequencer_vol++; sequencer_vol &= 0x7; - sequencer_len++; sequencer_len &= 0x7; - sequencer_swp++; sequencer_swp &= 0x7; - - // clock the lengths - if ((sequencer_len & 1) > 0) - { - if (SQ1_len_en && SQ1_len_cntr > 0) - { - SQ1_len_cntr--; - if (SQ1_len_cntr == 0) { SQ1_enable = SQ1_swp_enable = false; calculate_bias_gain_1(); } - } - if (SQ2_len_en && SQ2_len_cntr > 0) - { - SQ2_len_cntr--; - if (SQ2_len_cntr == 0) { SQ2_enable = false; calculate_bias_gain_2(); } - } - if (WAVE_len_en && WAVE_len_cntr > 0) - { - WAVE_len_cntr--; - if (WAVE_len_cntr == 0) { WAVE_enable = false; calculate_bias_gain_w(); } - } - if (NOISE_len_en && NOISE_len_cntr > 0) - { - NOISE_len_cntr--; - if (NOISE_len_cntr == 0) { NOISE_enable = false; calculate_bias_gain_n(); } - } - } - - // clock the sweep - if ((sequencer_swp == 3) || (sequencer_swp == 7)) - { - SQ1_intl_swp_cnt--; - if ((SQ1_intl_swp_cnt == 0) && SQ1_swp_enable) - { - SQ1_intl_swp_cnt = SQ1_swp_prd > 0 ? SQ1_swp_prd : 8; - - if ((SQ1_swp_prd > 0)) - { - int shadow_frq = SQ1_frq_shadow; - shadow_frq = shadow_frq >> SQ1_shift; - if (SQ1_negate) { shadow_frq = -shadow_frq; } - shadow_frq += SQ1_frq_shadow; - - // set negate mode flag that disables channel is negate clerar - if (SQ1_negate) { SQ1_calc_done = true; } - - // disable channel if overflow - if ((uint32_t)shadow_frq > 2047) - { - SQ1_enable = SQ1_swp_enable = false; calculate_bias_gain_1(); - } - else - { - if (SQ1_shift > 0) - { - shadow_frq &= 0x7FF; - SQ1_frq = shadow_frq; - SQ1_frq_shadow = shadow_frq; - - // note that we also write back the frequency to the actual register - Audio_Regs[NR13] = (uint8_t)(SQ1_frq & 0xFF); - Audio_Regs[NR14] &= 0xF8; - Audio_Regs[NR14] |= (uint8_t)((SQ1_frq >> 8) & 7); - - // after writing, we repeat the process and do another overflow check - shadow_frq = SQ1_frq_shadow; - shadow_frq = shadow_frq >> SQ1_shift; - if (SQ1_negate) { shadow_frq = -shadow_frq; } - shadow_frq += SQ1_frq_shadow; - - if ((uint32_t)shadow_frq > 2047) - { - SQ1_enable = SQ1_swp_enable = false; calculate_bias_gain_1(); - } - } - } - } - } - } - - // clock the volume envelope - if (sequencer_vol == 0) - { - if (SQ1_per > 0) - { - SQ1_vol_per--; - if (SQ1_vol_per == 0) - { - SQ1_vol_per = (SQ1_per > 0) ? SQ1_per : 8; - if (!SQ1_vol_done) - { - if (SQ1_env_add) - { - if (SQ1_vol_state < 15) { SQ1_vol_state++; } - else { SQ1_vol_done = true; } - } - else - { - if (SQ1_vol_state >= 1) { SQ1_vol_state--; } - else { SQ1_vol_done = true; } - } - } - } - } - - if (SQ2_per > 0) - { - SQ2_vol_per--; - if (SQ2_vol_per == 0) - { - SQ2_vol_per = (SQ2_per > 0) ? SQ2_per : 8; - if (!SQ2_vol_done) - { - if (SQ2_env_add) - { - if (SQ2_vol_state < 15) { SQ2_vol_state++; } - else { SQ2_vol_done = true; } - } - else - { - if (SQ2_vol_state >= 1) { SQ2_vol_state--; } - else { SQ2_vol_done = true; } - } - } - } - } - - if (NOISE_per > 0) - { - NOISE_vol_per--; - if (NOISE_vol_per == 0) - { - NOISE_vol_per = (NOISE_per > 0) ? NOISE_per : 8; - if (!NOISE_vol_done) - { - if (NOISE_env_add) - { - if (NOISE_vol_state < 15) { NOISE_vol_state++; } - else { NOISE_vol_done = true; } - } - else - { - if (NOISE_vol_state >= 1) { NOISE_vol_state--; } - else { NOISE_vol_done = true; } - } - } - } - } - } - } - timer_bit_old = double_speed[0] ? ((timer_div_reg[0] & 0x2000) > 0) : ((timer_div_reg[0] & 0x1000) > 0); - } - - void power_off() - { - for (int i = 0; i < 0x16; i++) - { - WriteReg(0xFF10 + i, 0); - } - - calculate_bias_gain_a(); - - // duty and length are reset - SQ1_duty_cntr = SQ2_duty_cntr = 0; - - // reset state variables - SQ1_enable = SQ1_swp_enable = SQ2_enable = WAVE_enable = NOISE_enable = false; - - SQ1_len_en = SQ2_len_en = WAVE_len_en = NOISE_len_en = false; - - SQ1_output = SQ2_output = WAVE_output = NOISE_output = 0; - - // on GBC, lengths are also reset - if (is_GBC[0]) - { - SQ1_length = SQ2_length = WAVE_length = NOISE_length = 0; - SQ1_len_cntr = SQ2_len_cntr = WAVE_len_cntr = NOISE_len_cntr = 0; - } - - sequencer_len = 0; - sequencer_vol = 0; - sequencer_swp = 0; - } - - void Reset() - { - if (is_GBC[0]) - { - Wave_RAM[0] = 0; Wave_RAM[2] = 0; Wave_RAM[4] = 0; Wave_RAM[6] = 0; - Wave_RAM[8] = 0; Wave_RAM[10] = 0; Wave_RAM[12] = 0; Wave_RAM[14] = 0; - - Wave_RAM[1] = 0xFF; Wave_RAM[3] = 0xFF; Wave_RAM[5] = 0xFF; Wave_RAM[7] = 0xFF; - Wave_RAM[9] = 0xFF; Wave_RAM[11] = 0xFF; Wave_RAM[13] = 0xFF; Wave_RAM[15] = 0xFF; - } - else - { - Wave_RAM[0] = 0x84; Wave_RAM[1] = 0x40; Wave_RAM[2] = 0x43; Wave_RAM[3] = 0xAA; - Wave_RAM[4] = 0x2D; Wave_RAM[5] = 0x78; Wave_RAM[6] = 0x92; Wave_RAM[7] = 0x3C; - - Wave_RAM[8] = 0x60; Wave_RAM[9] = 0x59; Wave_RAM[10] = 0x59; Wave_RAM[11] = 0xB0; - Wave_RAM[12] = 0x34; Wave_RAM[13] = 0xB8; Wave_RAM[14] = 0x2E; Wave_RAM[15] = 0xDA; - } - - for (int i = 0; i < 21; i++) - { - Audio_Regs[i] = 0; - } - - for (int i = 0; i < 0x16; i++) - { - WriteReg(0xFF10 + i, 0); - } - - calculate_bias_gain_a(); - - SQ1_duty_cntr = SQ2_duty_cntr = 0; - - SQ1_enable = SQ1_swp_enable = SQ2_enable = WAVE_enable = NOISE_enable = false; - - SQ1_len_en = SQ2_len_en = WAVE_len_en = NOISE_len_en = false; - - SQ1_output = SQ2_output = WAVE_output = NOISE_output = 0; - - SQ1_length = SQ2_length = WAVE_length = NOISE_length = 0; - SQ1_len_cntr = SQ2_len_cntr = WAVE_len_cntr = NOISE_len_cntr = 0; - - master_audio_clock = 0; - - sequencer_len = 0; - sequencer_swp = 0; - sequencer_vol = 0; - - sample = 0; - } - - void calculate_bias_gain_a() - { - if ((AUD_CTRL_sq1_R_en | AUD_CTRL_sq1_L_en) && ((Audio_Regs[NR12] & 0xF8) > 0)) - { - SQ1_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; - } - else - { - SQ1_bias_gain = 0; - } - if ((AUD_CTRL_sq2_R_en | AUD_CTRL_sq2_L_en) && ((Audio_Regs[NR22] & 0xF8) > 0)) - { - SQ2_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; - } - else - { - SQ2_bias_gain = 0; - } - if ((AUD_CTRL_wave_R_en | AUD_CTRL_wave_L_en) && WAVE_DAC_pow) - { - WAVE_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; - } - else - { - WAVE_bias_gain = 0; - } - if ((AUD_CTRL_noise_R_en | AUD_CTRL_noise_L_en) && ((Audio_Regs[NR42] & 0xF8) > 0)) - { - NOISE_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; - } - else - { - NOISE_bias_gain = 0; - } - - if (!SQ1_enable) { SQ1_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; } - if (!SQ2_enable) { SQ2_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; } - //if (!WAVE_enable) { WAVE_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; } - if (!NOISE_enable) { NOISE_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; } - } - - void calculate_bias_gain_1() - { - if ((AUD_CTRL_sq1_R_en | AUD_CTRL_sq1_L_en) && ((Audio_Regs[NR12] & 0xF8) > 0)) - { - SQ1_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 3; - } - else - { - SQ1_bias_gain = 0; - } - - if (!SQ1_enable) { SQ1_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; } - } - - void calculate_bias_gain_2() - { - if ((AUD_CTRL_sq2_R_en | AUD_CTRL_sq2_L_en) && ((Audio_Regs[NR22] & 0xF8) > 0)) - { - SQ2_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 3; - } - else - { - SQ2_bias_gain = 0; - } - - if (!SQ2_enable) { SQ2_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; } - } - - void calculate_bias_gain_w() - { - if ((AUD_CTRL_wave_R_en | AUD_CTRL_wave_L_en) && WAVE_DAC_pow) - { - WAVE_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 3; - } - else - { - WAVE_bias_gain = 0; - } - - if (!WAVE_enable) { WAVE_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; } - } - - void calculate_bias_gain_n() - { - if ((AUD_CTRL_noise_R_en | AUD_CTRL_noise_L_en) && ((Audio_Regs[NR42] & 0xF8) > 0)) - { - NOISE_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 3; - } - else - { - NOISE_bias_gain = 0; - } - - if (!NOISE_enable) { NOISE_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; } - } - - uint8_t Read_NR52() - { - return (uint8_t)( - ((AUD_CTRL_power ? 1 : 0) << 7) | - (SQ1_enable ? 1 : 0) | - ((SQ2_enable ? 1 : 0) << 1) | - ((WAVE_enable ? 1 : 0) << 2) | - ((NOISE_enable ? 1 : 0) << 3)); - } - - #pragma endregion - - - #pragma region State Save / Load - - uint8_t* SaveState(uint8_t* saver) - { - for (int i = 0; i < 21; i++) - { - saver = byte_saver(Audio_Regs[i], saver); - } - - for (int i = 0; i < 16; i++) - { - saver = byte_saver(Wave_RAM[i], saver); - } - - saver = bool_saver(SQ1_vol_done, saver); - saver = bool_saver(SQ1_calc_done, saver); - saver = bool_saver(SQ1_swp_enable, saver); - saver = bool_saver(SQ1_enable, saver); - saver = byte_saver(SQ1_vol_state, saver); - saver = byte_saver(SQ1_duty_cntr, saver); - saver = int_saver(SQ1_frq_shadow, saver); - saver = int_saver(SQ1_intl_cntr, saver); - saver = int_saver(SQ1_vol_per, saver); - saver = int_saver(SQ1_intl_swp_cnt, saver); - saver = int_saver(SQ1_len_cntr, saver); - saver = bool_saver(SQ1_negate, saver); - saver = bool_saver(SQ1_trigger, saver); - saver = bool_saver(SQ1_len_en, saver); - saver = bool_saver(SQ1_env_add, saver); - saver = byte_saver(SQ1_shift, saver); - saver = byte_saver(SQ1_duty, saver); - saver = byte_saver(SQ1_st_vol, saver); - saver = byte_saver(SQ1_per, saver); - saver = byte_saver(SQ1_swp_prd, saver); - saver = int_saver(SQ1_frq, saver); - saver = int_saver(SQ1_length, saver); - saver = int_saver(SQ1_output, saver); - - saver = bool_saver(SQ2_vol_done, saver); - saver = bool_saver(SQ2_enable, saver); - saver = byte_saver(SQ2_vol_state, saver); - saver = byte_saver(SQ2_duty_cntr, saver); - saver = int_saver(SQ2_intl_cntr, saver); - saver = int_saver(SQ2_vol_per, saver); - saver = int_saver(SQ2_len_cntr, saver); - saver = bool_saver(SQ2_trigger, saver); - saver = bool_saver(SQ2_len_en, saver); - saver = bool_saver(SQ2_env_add, saver); - saver = byte_saver(SQ2_duty, saver); - saver = byte_saver(SQ2_st_vol, saver); - saver = byte_saver(SQ2_per, saver); - saver = int_saver(SQ2_frq, saver); - saver = int_saver(SQ2_length, saver); - saver = int_saver(SQ2_output, saver); - - saver = bool_saver(WAVE_can_get, saver); - saver = bool_saver(WAVE_enable, saver); - saver = byte_saver(WAVE_wave_cntr, saver); - saver = int_saver(WAVE_intl_cntr, saver); - saver = int_saver(WAVE_len_cntr, saver); - saver = bool_saver(WAVE_DAC_pow, saver); - saver = bool_saver(WAVE_trigger, saver); - saver = bool_saver(WAVE_len_en, saver); - saver = byte_saver(WAVE_vol_code, saver); - saver = int_saver(WAVE_frq, saver); - saver = int_saver(WAVE_length, saver); - saver = int_saver(WAVE_output, saver); - - saver = bool_saver(NOISE_vol_done, saver); - saver = bool_saver(NOISE_enable, saver); - saver = byte_saver(NOISE_vol_state, saver); - saver = int_saver(NOISE_intl_cntr, saver); - saver = int_saver(NOISE_vol_per, saver); - saver = int_saver(NOISE_LFSR, saver); - saver = int_saver(NOISE_len_cntr, saver); - saver = bool_saver(NOISE_wdth_md, saver); - saver = bool_saver(NOISE_trigger, saver); - saver = bool_saver(NOISE_len_en, saver); - saver = bool_saver(NOISE_env_add, saver); - saver = byte_saver(NOISE_clk_shft, saver); - saver = byte_saver(NOISE_div_code, saver); - saver = byte_saver(NOISE_st_vol, saver); - saver = byte_saver(NOISE_per, saver); - saver = int_saver(NOISE_length, saver); - saver = int_saver(NOISE_output, saver); - - saver = int_saver(sequencer_len, saver); - saver = int_saver(sequencer_vol, saver); - saver = int_saver(sequencer_swp, saver); - saver = bool_saver(timer_bit_old, saver); - - saver = int_saver(master_audio_clock, saver); - - saver = byte_saver(sample, saver); - saver = int_saver(latched_sample_L, saver); - saver = int_saver(latched_sample_R, saver); - saver = int_saver(num_samples_L, saver); - saver = int_saver(num_samples_R, saver); - - saver = bool_saver(AUD_CTRL_vin_L_en, saver); - saver = bool_saver(AUD_CTRL_vin_R_en, saver); - saver = bool_saver(AUD_CTRL_sq1_L_en, saver); - saver = bool_saver(AUD_CTRL_sq2_L_en, saver); - saver = bool_saver(AUD_CTRL_wave_L_en, saver); - saver = bool_saver(AUD_CTRL_noise_L_en, saver); - saver = bool_saver(AUD_CTRL_sq1_R_en, saver); - saver = bool_saver(AUD_CTRL_sq2_R_en, saver); - saver = bool_saver(AUD_CTRL_wave_R_en, saver); - saver = bool_saver(AUD_CTRL_noise_R_en, saver); - saver = bool_saver(AUD_CTRL_power, saver); - saver = byte_saver(AUD_CTRL_vol_L, saver); - saver = byte_saver(AUD_CTRL_vol_R, saver); - - saver = int_saver(SQ1_bias_gain, saver); - saver = int_saver(SQ2_bias_gain, saver); - saver = int_saver(WAVE_bias_gain, saver); - saver = int_saver(NOISE_bias_gain, saver); - return saver; - } - - uint8_t* LoadState(uint8_t* loader) - { - for (int i = 0; i < 21; i++) - { - loader = byte_loader(&Audio_Regs[i], loader); - } - - for (int i = 0; i < 16; i++) - { - loader = byte_loader(&Wave_RAM[i], loader); - } - - loader = bool_loader(&SQ1_vol_done, loader); - loader = bool_loader(&SQ1_calc_done, loader); - loader = bool_loader(&SQ1_swp_enable, loader); - loader = bool_loader(&SQ1_enable, loader); - loader = byte_loader(&SQ1_vol_state, loader); - loader = byte_loader(&SQ1_duty_cntr, loader); - loader = int_loader(&SQ1_frq_shadow, loader); - loader = int_loader(&SQ1_intl_cntr, loader); - loader = int_loader(&SQ1_vol_per, loader); - loader = int_loader(&SQ1_intl_swp_cnt, loader); - loader = int_loader(&SQ1_len_cntr, loader); - loader = bool_loader(&SQ1_negate, loader); - loader = bool_loader(&SQ1_trigger, loader); - loader = bool_loader(&SQ1_len_en, loader); - loader = bool_loader(&SQ1_env_add, loader); - loader = byte_loader(&SQ1_shift, loader); - loader = byte_loader(&SQ1_duty, loader); - loader = byte_loader(&SQ1_st_vol, loader); - loader = byte_loader(&SQ1_per, loader); - loader = byte_loader(&SQ1_swp_prd, loader); - loader = int_loader(&SQ1_frq, loader); - loader = int_loader(&SQ1_length, loader); - loader = int_loader(&SQ1_output, loader); - - loader = bool_loader(&SQ2_vol_done, loader); - loader = bool_loader(&SQ2_enable, loader); - loader = byte_loader(&SQ2_vol_state, loader); - loader = byte_loader(&SQ2_duty_cntr, loader); - loader = int_loader(&SQ2_intl_cntr, loader); - loader = int_loader(&SQ2_vol_per, loader); - loader = int_loader(&SQ2_len_cntr, loader); - loader = bool_loader(&SQ2_trigger, loader); - loader = bool_loader(&SQ2_len_en, loader); - loader = bool_loader(&SQ2_env_add, loader); - loader = byte_loader(&SQ2_duty, loader); - loader = byte_loader(&SQ2_st_vol, loader); - loader = byte_loader(&SQ2_per, loader); - loader = int_loader(&SQ2_frq, loader); - loader = int_loader(&SQ2_length, loader); - loader = int_loader(&SQ2_output, loader); - - loader = bool_loader(&WAVE_can_get, loader); - loader = bool_loader(&WAVE_enable, loader); - loader = byte_loader(&WAVE_wave_cntr, loader); - loader = int_loader(&WAVE_intl_cntr, loader); - loader = int_loader(&WAVE_len_cntr, loader); - loader = bool_loader(&WAVE_DAC_pow, loader); - loader = bool_loader(&WAVE_trigger, loader); - loader = bool_loader(&WAVE_len_en, loader); - loader = byte_loader(&WAVE_vol_code, loader); - loader = int_loader(&WAVE_frq, loader); - loader = int_loader(&WAVE_length, loader); - loader = int_loader(&WAVE_output, loader); - - loader = bool_loader(&NOISE_vol_done, loader); - loader = bool_loader(&NOISE_enable, loader); - loader = byte_loader(&NOISE_vol_state, loader); - loader = int_loader(&NOISE_intl_cntr, loader); - loader = int_loader(&NOISE_vol_per, loader); - loader = int_loader(&NOISE_LFSR, loader); - loader = int_loader(&NOISE_len_cntr, loader); - loader = bool_loader(&NOISE_wdth_md, loader); - loader = bool_loader(&NOISE_trigger, loader); - loader = bool_loader(&NOISE_len_en, loader); - loader = bool_loader(&NOISE_env_add, loader); - loader = byte_loader(&NOISE_clk_shft, loader); - loader = byte_loader(&NOISE_div_code, loader); - loader = byte_loader(&NOISE_st_vol, loader); - loader = byte_loader(&NOISE_per, loader); - loader = int_loader(&NOISE_length, loader); - loader = int_loader(&NOISE_output, loader); - - loader = int_loader(&sequencer_len, loader); - loader = int_loader(&sequencer_vol, loader); - loader = int_loader(&sequencer_swp, loader); - loader = bool_loader(&timer_bit_old, loader); - - loader = int_loader(&master_audio_clock, loader); - - loader = byte_loader(&sample, loader); - loader = int_loader(&latched_sample_L, loader); - loader = int_loader(&latched_sample_R, loader); - loader = int_loader(&num_samples_L, loader); - loader = int_loader(&num_samples_R, loader); - - loader = bool_loader(&AUD_CTRL_vin_L_en, loader); - loader = bool_loader(&AUD_CTRL_vin_R_en, loader); - loader = bool_loader(&AUD_CTRL_sq1_L_en, loader); - loader = bool_loader(&AUD_CTRL_sq2_L_en, loader); - loader = bool_loader(&AUD_CTRL_wave_L_en, loader); - loader = bool_loader(&AUD_CTRL_noise_L_en, loader); - loader = bool_loader(&AUD_CTRL_sq1_R_en, loader); - loader = bool_loader(&AUD_CTRL_sq2_R_en, loader); - loader = bool_loader(&AUD_CTRL_wave_R_en, loader); - loader = bool_loader(&AUD_CTRL_noise_R_en, loader); - loader = bool_loader(&AUD_CTRL_power, loader); - loader = byte_loader(&AUD_CTRL_vol_L, loader); - loader = byte_loader(&AUD_CTRL_vol_R, loader); - - loader = int_loader(&SQ1_bias_gain, loader); - loader = int_loader(&SQ2_bias_gain, loader); - loader = int_loader(&WAVE_bias_gain, loader); - loader = int_loader(&NOISE_bias_gain, loader); - return loader; - } - - uint8_t* bool_saver(bool to_save, uint8_t* saver) - { - *saver = (uint8_t)(to_save ? 1 : 0); saver++; - - return saver; - } - - uint8_t* byte_saver(uint8_t to_save, uint8_t* saver) - { - *saver = to_save; saver++; - - return saver; - } - - uint8_t* int_saver(uint32_t to_save, uint8_t* saver) - { - *saver = (uint8_t)(to_save & 0xFF); saver++; *saver = (uint8_t)((to_save >> 8) & 0xFF); saver++; - *saver = (uint8_t)((to_save >> 16) & 0xFF); saver++; *saver = (uint8_t)((to_save >> 24) & 0xFF); saver++; - - return saver; - } - - uint8_t* bool_loader(bool* to_load, uint8_t* loader) - { - to_load[0] = *to_load == 1; loader++; - - return loader; - } - - uint8_t* byte_loader(uint8_t* to_load, uint8_t* loader) - { - to_load[0] = *loader; loader++; - - return loader; - } - - uint8_t* int_loader(uint32_t* to_load, uint8_t* loader) - { - to_load[0] = *loader; loader++; to_load[0] |= (*loader << 8); loader++; - to_load[0] |= (*loader << 16); loader++; to_load[0] |= (*loader << 24); loader++; - - return loader; - } - - #pragma endregion - }; -} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/GBHawk.cpp b/libHawk/GBHawk/GBHawk/GBHawk.cpp deleted file mode 100644 index a8734675f6..0000000000 --- a/libHawk/GBHawk/GBHawk/GBHawk.cpp +++ /dev/null @@ -1,260 +0,0 @@ -// GBHawk.cpp : Defines the exported functions for the DLL. -// - -#include "GBHawk.h" -#include "Core.h" - -#include -#include -#include -#include - -using namespace GBHawk; - -#pragma region Core -// Create pointer to a core instance -GBHawk_EXPORT GBCore* GB_create() -{ - return new GBCore(); -} - -// free the memory from the core pointer -GBHawk_EXPORT void GB_destroy(GBCore* p) -{ - delete p->MemMap.bios_rom; - delete p->MemMap.ROM; - std::free(p); -} - -// load bios into the core -GBHawk_EXPORT void GB_load_bios(GBCore* p, uint8_t* bios, bool GBC_console, bool GBC_as_GBA) -{ - p->Load_BIOS(bios, GBC_console, GBC_as_GBA); -} - -// load a rom into the core -GBHawk_EXPORT void GB_load(GBCore* p, uint8_t* rom_1, uint32_t size_1, char* MD5, uint32_t RTC_initial, uint32_t RTC_offset) -{ - string MD5_s(MD5, 32); - - p->Load_ROM(rom_1, size_1, MD5_s, RTC_initial, RTC_offset); -} - -// Hard reset (note: does not change RTC, that only happens on load) -GBHawk_EXPORT void GB_Reset(GBCore* p) -{ - p->Reset(); -} - -// advance a frame -GBHawk_EXPORT bool GB_frame_advance(GBCore* p, uint8_t new_ctrl1, uint32_t new_accx, uint32_t new_accy, bool render, bool sound) -{ - return p->FrameAdvance(new_ctrl1, new_accx, new_accy, render, sound); -} - -// advance a single step -GBHawk_EXPORT void GB_do_single_step(GBCore* p) -{ - p->do_single_step(); -} - -// send video data to external video provider -GBHawk_EXPORT void GB_get_video(GBCore* p, uint32_t* dest) -{ - p->GetVideo(dest); -} - -// send audio data to external audio provider -GBHawk_EXPORT uint32_t GB_get_audio(GBCore* p, int32_t* dest_L, int32_t* n_samp_L, int32_t* dest_R, int32_t* n_samp_R) -{ - return p->GetAudio(dest_L, n_samp_L, dest_R, n_samp_R); -} -#pragma endregion - -#pragma region State Save / Load - -// save state -GBHawk_EXPORT void GB_save_state(GBCore* p, uint8_t* saver) -{ - p->SaveState(saver); -} - -// load state -GBHawk_EXPORT void GB_load_state(GBCore* p, uint8_t* loader) -{ - p->LoadState(loader); -} - -#pragma endregion - -#pragma region Memory Domain Functions - -GBHawk_EXPORT uint8_t GB_getram(GBCore* p, uint32_t addr) { - return p->GetRAM(addr); -} - -GBHawk_EXPORT uint8_t GB_getvram(GBCore* p, uint32_t addr) { - return p->GetVRAM(addr); -} - -GBHawk_EXPORT uint8_t GB_getoam(GBCore* p, uint32_t addr) { - return p->GetOAM(addr); -} - -GBHawk_EXPORT uint8_t GB_gethram(GBCore* p, uint32_t addr) { - return p->GetHRAM(addr); -} - -GBHawk_EXPORT uint8_t GB_getsysbus(GBCore* p, uint32_t addr) { - return p->GetSysBus(addr); -} - -GBHawk_EXPORT void GB_setram(GBCore* p, uint32_t addr, uint8_t value) { - p->SetRAM(addr, value); -} - -GBHawk_EXPORT void GB_setvram(GBCore* p, uint32_t addr, uint8_t value) { - p->SetVRAM(addr, value); -} - -GBHawk_EXPORT void GB_setoam(GBCore* p, uint32_t addr, uint8_t value) { - p->SetOAM(addr, value); -} - -GBHawk_EXPORT void GB_sethram(GBCore* p, uint32_t addr, uint8_t value) { - p->SetHRAM(addr, value); -} - -GBHawk_EXPORT void GB_setsysbus(GBCore* p, uint32_t addr, uint8_t value) { - p->SetSysBus(addr, value); -} - -#pragma endregion - -#pragma region Tracer - -// set tracer callback -GBHawk_EXPORT void GB_settracecallback(GBCore* p, void (*callback)(int)) { - p->SetTraceCallback(callback); -} - -// return the cpu trace header length -GBHawk_EXPORT int GB_getheaderlength(GBCore* p) { - return p->GetHeaderLength(); -} - -// return the cpu disassembly length -GBHawk_EXPORT int GB_getdisasmlength(GBCore* p) { - return p->GetDisasmLength(); -} - -// return the cpu register string length -GBHawk_EXPORT int GB_getregstringlength(GBCore* p) { - return p->GetRegStringLength(); -} - -// return the cpu trace header -GBHawk_EXPORT void GB_getheader(GBCore* p, char* h, int l) { - p->GetHeader(h, l); -} - -// return the cpu register state -GBHawk_EXPORT void GB_getregisterstate(GBCore* p, char* r, int t, int l) { - p->GetRegisterState(r, t, l); -} - -// return the cpu disassembly -GBHawk_EXPORT void GB_getdisassembly(GBCore* p, char* d, int t, int l) { - p->GetDisassembly(d, t, l); -} - -#pragma endregion - -#pragma region PPU Viewer - -// set tracer callback -GBHawk_EXPORT uint8_t* GB_get_ppu_pntrs(GBCore* p, int sel) { - - if (p->MemMap.is_GBC) - { - switch (sel) - { - case 0: return p->MemMap.VRAM; break; - case 1: return p->MemMap.OAM; break; - case 2: return (uint8_t*)p->ppu->OBJ_palette; break; - case 3: return (uint8_t*)p->ppu->BG_palette; break; - } - } - else - { - switch (sel) - { - case 0: return p->MemMap.VRAM; break; - case 1: return p->MemMap.OAM; break; - case 2: return (uint8_t*)p->MemMap.color_palette_OBJ; break; - case 3: return (uint8_t*)p->MemMap.color_palette_BG; break; - } - } - - return nullptr; -} - -// return LCDC state for the ppu viewer -GBHawk_EXPORT uint8_t GB_get_LCDC(GBCore* p) { - return p->ppu->LCDC; -} - -// set scanline callback -GBHawk_EXPORT void GB_setscanlinecallback(GBCore* p, void (*callback)(void), int sl) { - p->SetScanlineCallback(callback, sl); -} - -#pragma endregion - -#pragma region Debuggable functions - -// return cpu cycle count -GBHawk_EXPORT uint64_t GB_cpu_cycles(GBCore* p) { - return p->cpu.TotalExecutedCycles; -} - -// return cpu registers -GBHawk_EXPORT uint8_t GB_cpu_get_regs(GBCore* p, int reg) { - return p->cpu.Regs[reg]; -} - -// return cpu flags -GBHawk_EXPORT bool GB_cpu_get_flags(GBCore* p, int reg) { - bool ret = false; - - switch (reg) - { - case (0): ret = p->cpu.FlagI; break; - case (1): ret = p->cpu.FlagCget(); break; - case (2): ret = p->cpu.FlagHget(); break; - case (3): ret = p->cpu.FlagNget(); break; - case (4): ret = p->cpu.FlagZget(); break; - } - - return ret; -} - -// set cpu registers -GBHawk_EXPORT void GB_cpu_set_regs(GBCore* p, int reg, uint8_t value) { - p->cpu.Regs[reg] = value; -} - -// set cpu flags -GBHawk_EXPORT void GB_cpu_set_flags(GBCore* p, int reg, bool value) { - - switch (reg) - { - case (0): p->cpu.FlagI = value; break; - case (1): p->cpu.FlagCset(value); break; - case (2): p->cpu.FlagHset(value); break; - case (3): p->cpu.FlagNset(value); break; - case (4): p->cpu.FlagZset(value); break; - } -} - -#pragma endregion \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/GBHawk.h b/libHawk/GBHawk/GBHawk/GBHawk.h deleted file mode 100644 index 36ab931b4b..0000000000 --- a/libHawk/GBHawk/GBHawk/GBHawk.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifdef _WIN32 -#define GBHawk_EXPORT extern "C" __declspec(dllexport) -#elif __linux__ -#define GBHawk_EXPORT extern "C" -#endif diff --git a/libHawk/GBHawk/GBHawk/GBHawk.vcxproj b/libHawk/GBHawk/GBHawk/GBHawk.vcxproj deleted file mode 100644 index 6cc7eb9047..0000000000 --- a/libHawk/GBHawk/GBHawk/GBHawk.vcxproj +++ /dev/null @@ -1,177 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - {FA59603F-32AB-429A-9186-B46114851290} - Win32Proj - GBHawk - 10.0 - - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - ..\..\..\output\dll\ - - - - Use - Level3 - true - WIN32;_DEBUG;GBHAWK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - pch.h - - - Windows - true - false - - - - - Use - Level3 - true - _DEBUG;GBHAWK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - pch.h - - - Windows - true - false - - - - - Use - Level3 - true - true - true - WIN32;NDEBUG;GBHAWK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - pch.h - - - Windows - true - true - true - false - - - - - NotUsing - Level3 - true - true - true - NDEBUG;GBHAWK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - pch.h - - - Windows - true - true - true - false - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/LR35902.cpp b/libHawk/GBHawk/GBHawk/LR35902.cpp deleted file mode 100644 index eecf5b4857..0000000000 --- a/libHawk/GBHawk/GBHawk/LR35902.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include - -#include "Memory.h" -#include "LR35902.h" - -using namespace std; - -namespace GBHawk -{ - void LR35902::WriteMemory(uint32_t addr, uint8_t value) - { - mem_ctrl->WriteMemory(addr, value); - } - - uint8_t LR35902::ReadMemory(uint32_t addr) - { - return mem_ctrl->ReadMemory(addr); - } - - uint8_t LR35902::PeekMemory(uint32_t addr) - { - return mem_ctrl->PeekMemory(addr); - } - - uint8_t LR35902::SpeedFunc(uint32_t val) - { - return mem_ctrl->SpeedFunc(val); - } -} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/LR35902.h b/libHawk/GBHawk/GBHawk/LR35902.h deleted file mode 100644 index 39178a0201..0000000000 --- a/libHawk/GBHawk/GBHawk/LR35902.h +++ /dev/null @@ -1,3011 +0,0 @@ -#include -#include -#include -#include - -using namespace std; - -namespace GBHawk -{ - class MemoryManager; - - class LR35902 - { - public: - - #pragma region Variable Declarations - - // pointer to controlling memory manager goes here - // this will be iplementation dependent - MemoryManager* mem_ctrl; - - void WriteMemory(uint32_t, uint8_t); - uint8_t ReadMemory(uint32_t); - uint8_t PeekMemory(uint32_t); - uint8_t SpeedFunc(uint32_t); - - // State variables - bool interrupts_enabled; - bool CB_prefix; - bool halted; - bool stopped; - bool jammed; - bool was_FlagI, FlagI; - - uint8_t Regs[14] = {}; - uint8_t EI_pending; - uint8_t LY; - uint8_t opcode; - - uint32_t instr_pntr = 0; - - uint64_t TotalExecutedCycles; - - // non-state variables - bool checker; - bool temp2; - uint32_t cur_instr[60] = {}; // only used for building - uint32_t instr_table[256 * 2 * 60 + 60 * 8] = {}; // compiled instruction table - - // local variables for operations, not stated - bool imm; - uint8_t a_d; - uint32_t Reg16_d, Reg16_s, c; - uint32_t ans, ans_l, ans_h, temp; - uint32_t bit_check; - - #pragma endregion - - #pragma region Constant Declarations - // operations that can take place in an instruction - const static uint32_t IDLE = 0; - const static uint32_t OP = 1; - const static uint32_t RD = 2; - const static uint32_t WR = 3; - const static uint32_t TR = 4; - const static uint32_t ADD16 = 5; - const static uint32_t ADD8 = 6; - const static uint32_t SUB8 = 7; - const static uint32_t ADC8 = 8; - const static uint32_t SBC8 = 9; - const static uint32_t INC16 = 10; - const static uint32_t INC8 = 11; - const static uint32_t DEC16 = 12; - const static uint32_t DEC8 = 13; - const static uint32_t RLC = 14; - const static uint32_t RL = 15; - const static uint32_t RRC = 16; - const static uint32_t RR = 17; - const static uint32_t CPL = 18; - const static uint32_t DA = 19; - const static uint32_t SCF = 20; - const static uint32_t CCF = 21; - const static uint32_t AND8 = 22; - const static uint32_t XOR8 = 23; - const static uint32_t OR8 = 24; - const static uint32_t CP8 = 25; - const static uint32_t SLA = 26; - const static uint32_t SRA = 27; - const static uint32_t SRL = 28; - const static uint32_t SWAP = 29; - const static uint32_t BIT = 30; - const static uint32_t RES = 31; - const static uint32_t SET = 32; - const static uint32_t EI = 33; - const static uint32_t DI = 34; - const static uint32_t HALT = 35; - const static uint32_t STOP = 36; - const static uint32_t PREFIX = 37; - const static uint32_t ASGN = 38; - const static uint32_t ADDS = 39; // signed 16 bit operation used in 2 instructions - const static uint32_t OP_G = 40; // glitchy opcode read performed by halt when interrupts disabled - const static uint32_t JAM = 41; // all undocumented opcodes jam the machine - const static uint32_t RD_F = 42; // special read case to pop value into F - const static uint32_t EI_RETI = 43; // reti has no delay in interrupt enable - const static uint32_t INT_GET = 44; - const static uint32_t HALT_CHK = 45; // when in halt mode, actually check I Flag here - const static uint32_t IRQ_CLEAR = 46; - const static uint32_t COND_CHECK = 47; - const static uint32_t HALT_FUNC = 48; - - // test conditions - const static uint32_t ALWAYS_T = 0; - const static uint32_t ALWAYS_F = 1; - const static uint32_t FLAG_Z = 2; - const static uint32_t FLAG_NZ = 3; - const static uint32_t FLAG_C = 4; - const static uint32_t FLAG_NC = 5; - - // registers - - const static uint32_t PCl = 0; - const static uint32_t PCh = 1; - const static uint32_t SPl = 2; - const static uint32_t SPh = 3; - const static uint32_t A = 4; - const static uint32_t F = 5; - const static uint32_t B = 6; - const static uint32_t C = 7; - const static uint32_t D = 8; - const static uint32_t E = 9; - const static uint32_t H = 10; - const static uint32_t L = 11; - const static uint32_t W = 12; - const static uint32_t Z = 13; - const static uint32_t Aim = 14; // use this indicator for RLCA etc., since the Z flag is reset on those - - #pragma endregion - - #pragma region LR35902 functions - - inline bool FlagCget() { return (Regs[5] & 0x10) != 0; }; - inline void FlagCset(bool value) { Regs[5] = (uint8_t)((Regs[5] & ~0x10) | (value ? 0x10 : 0x00)); } - - inline bool FlagHget() { return (Regs[5] & 0x20) != 0; }; - inline void FlagHset(bool value) { Regs[5] = (uint8_t)((Regs[5] & ~0x20) | (value ? 0x20 : 0x00)); } - - inline bool FlagNget() { return (Regs[5] & 0x40) != 0; }; - inline void FlagNset(bool value) { Regs[5] = (uint8_t)((Regs[5] & ~0x40) | (value ? 0x40 : 0x00)); } - - inline bool FlagZget() { return (Regs[5] & 0x80) != 0; }; - inline void FlagZset(bool value) { Regs[5] = (uint8_t)((Regs[5] & ~0x80) | (value ? 0x80 : 0x00)); } - - inline uint32_t RegPCget() { return (uint32_t)(Regs[0] | (Regs[1] << 8)); } - inline void RegPCset(uint32_t value) { Regs[0] = (uint8_t)(value & 0xFF); Regs[1] = (uint8_t)((value >> 8) & 0xFF); } - - LR35902() - { - ResetRegisters(); - ResetInterrupts(); - BuildInstructionTable(); - TotalExecutedCycles = 8; - stop_check = false; - instr_pntr = 256 * 60 * 2; // point to reset - stopped = jammed = halted = FlagI = false; - EI_pending = 0; - CB_prefix = false; - } - - - - void Reset() - { - ResetRegisters(); - ResetInterrupts(); - BuildInstructionTable(); - TotalExecutedCycles = 8; - stop_check = false; - instr_pntr = 256 * 60 * 2; // point to reset - stopped = jammed = halted = FlagI = false; - EI_pending = 0; - CB_prefix = false; - } - - inline void FetchInstruction(uint8_t op) - { - opcode = op; - - instr_pntr = 0; - - if (CB_prefix) { instr_pntr += 256 * 60; } - - instr_pntr += op * 60; - - CB_prefix = false; - - was_FlagI = FlagI; - } - - // Execute instructions - void ExecuteOne(uint8_t* interrupt_src, uint8_t* interrupt_enable) - { - switch (instr_table[instr_pntr++]) - { - case IDLE: - // do nothing - break; - case OP: - // Read the opcode of the next instruction - if (EI_pending > 0 && !CB_prefix) - { - EI_pending--; - if (EI_pending == 0) - { - interrupts_enabled = true; - } - } - - if (I_use && interrupts_enabled && !CB_prefix && !jammed) - { - interrupts_enabled = false; - - if (TraceCallback) { TraceCallback(2); } - - // call interrupt processor - // lowest bit set is highest priority - instr_pntr = 256 * 60 * 2 + 60 * 6; // point to Interrupt - } - else - { - //OnExecFetch ? .Invoke(RegPC); - if (TraceCallback && !CB_prefix) { TraceCallback(0); } - //CDLCallback ? .Invoke(RegPC, eCDLogMemFlags.FetchFirst); - FetchInstruction(ReadMemory(RegPCget())); - RegPCset(RegPCget() + 1); - } - I_use = false; - break; - case RD: - Read_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1], instr_table[instr_pntr + 2]); - instr_pntr += 3; - break; - case WR: - Write_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1], instr_table[instr_pntr + 2]); - instr_pntr += 3; - break; - case TR: - TR_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case ADD16: - ADD16_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1], instr_table[instr_pntr + 2], instr_table[instr_pntr + 3]); - instr_pntr += 4; - break; - case ADD8: - ADD8_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case SUB8: - SUB8_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case ADC8: - ADC8_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case SBC8: - SBC8_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case INC16: - INC16_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case INC8: - INC8_Func(instr_table[instr_pntr++]); - break; - case DEC16: - DEC16_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case DEC8: - DEC8_Func(instr_table[instr_pntr++]); - break; - case RLC: - RLC_Func(instr_table[instr_pntr++]); - break; - case RL: - RL_Func(instr_table[instr_pntr++]); - break; - case RRC: - RRC_Func(instr_table[instr_pntr++]); - break; - case RR: - RR_Func(instr_table[instr_pntr++]); - break; - case CPL: - CPL_Func(instr_table[instr_pntr++]); - break; - case DA: - DA_Func(instr_table[instr_pntr++]); - break; - case SCF: - SCF_Func(instr_table[instr_pntr++]); - break; - case CCF: - CCF_Func(instr_table[instr_pntr++]); - break; - case AND8: - AND8_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case XOR8: - XOR8_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case OR8: - OR8_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case CP8: - CP8_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case SLA: - SLA_Func(instr_table[instr_pntr++]); - break; - case SRA: - SRA_Func(instr_table[instr_pntr++]); - break; - case SRL: - SRL_Func(instr_table[instr_pntr++]); - break; - case SWAP: - SWAP_Func(instr_table[instr_pntr++]); - break; - case BIT: - BIT_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case RES: - RES_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case SET: - SET_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case EI: - if (EI_pending == 0) { EI_pending = 2; } - break; - case DI: - interrupts_enabled = false; - EI_pending = 0; - break; - case HALT: - halted = true; - - temp2 = false; - - if (instr_table[instr_pntr++] == 1) - { - temp2 = FlagI; - } - else - { - temp2 = I_use; - } - - if (EI_pending > 0 && !CB_prefix) - { - EI_pending--; - if (EI_pending == 0) - { - interrupts_enabled = true; - } - } - - // if the I flag is asserted at the time of halt, don't halt - if (temp2 && interrupts_enabled && !CB_prefix && !jammed) - { - interrupts_enabled = false; - - if (TraceCallback) { TraceCallback(2); } - - halted = false; - - if (is_GBC) - { - // call the interrupt processor after 4 extra cycles - if (!Halt_bug_3) - { - instr_pntr = 256 * 60 * 2 + 60 * 7; // point to Interrupt for GBC - } - else - { - instr_pntr = 256 * 60 * 2 + 60 * 6; // point to Interrupt - Halt_bug_3 = false; - //Console.WriteLine("Hit INT"); - } - } - else - { - // call interrupt processor - instr_pntr = 256 * 60 * 2 + 60 * 6; // point to Interrupt - Halt_bug_3 = false; - } - } - else if (temp2) - { - // even if interrupt servicing is disabled, any interrupt flag raised still resumes execution - if (TraceCallback) { TraceCallback(1); } - halted = false; - - if (is_GBC) - { - // extra 4 cycles for GBC - if (Halt_bug_3) - { - //OnExecFetch ? .Invoke(RegPC); - if (TraceCallback) { TraceCallback(0); } - //CDLCallback ? .Invoke(RegPC, eCDLogMemFlags.FetchFirst); - - RegPCset(RegPCget() + 1); - FetchInstruction(ReadMemory(RegPCget())); - Halt_bug_3 = false; - //Console.WriteLine("Hit un"); - } - else - { - instr_pntr = 256 * 60 * 2 + 60; // point to halt loop - } - } - else - { - //OnExecFetch ? .Invoke(RegPC); - if (TraceCallback) { TraceCallback(0); } - //CDLCallback ? .Invoke(RegPC, eCDLogMemFlags.FetchFirst); - - if (Halt_bug_3) - { - //special variant of halt bug where RegPC also isn't incremented post fetch - RegPCset(RegPCget() + 1); - FetchInstruction(ReadMemory(RegPCget())); - Halt_bug_3 = false; - } - else - { - FetchInstruction(ReadMemory(RegPCget())); - RegPCset(RegPCget() + 1); - } - } - } - else - { - if (skip_once) - { - instr_pntr = 256 * 60 * 2 + 60 * 2; // point to skipped loop - skip_once = false; - } - else - { - if (is_GBC) - { - instr_pntr = 256 * 60 * 2 + 60 * 3; // point to GBC Halt loop - } - else - { - instr_pntr = 256 * 60 * 2 + 60 * 4; // point to spec Halt loop - } - } - } - I_use = false; - break; - case STOP: - stopped = true; - if (!stop_check) - { - stop_time = SpeedFunc(0); - stop_check = true; - } - - if (stop_time > 0) - { - stop_time--; - if (stop_time == 0) - { - if (TraceCallback) { TraceCallback(3); } - - stopped = false; - //OnExecFetch ? .Invoke(RegPC); - if (TraceCallback) { TraceCallback(0); } - //CDLCallback ? .Invoke(RegPC, eCDLogMemFlags.FetchFirst); - FetchInstruction(ReadMemory(RegPCget())); - RegPCset(RegPCget() + 1); - stop_check = false; - } - else - { - instr_pntr = 256 * 60 * 2 + 60 * 5; // point to stop loop - } - } - else if ((interrupt_src[0] & 0x10) > 0) // button pressed, not actually an interrupt though - { - if (TraceCallback) { TraceCallback(3); } - - stopped = false; - //OnExecFetch ? .Invoke(RegPC); - if (TraceCallback) { TraceCallback(0); } - //CDLCallback ? .Invoke(RegPC, eCDLogMemFlags.FetchFirst); - FetchInstruction(ReadMemory(RegPCget())); - RegPCset(RegPCget() + 1); - - stop_check = false; - } - else - { - instr_pntr = 256 * 60 * 2 + 60 * 5; // point to stop loop - } - break; - case PREFIX: - CB_prefix = true; - break; - case ASGN: - ASGN_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1]); - instr_pntr += 2; - break; - case ADDS: - ADDS_Func(instr_table[instr_pntr], instr_table[instr_pntr + 1], instr_table[instr_pntr + 2], instr_table[instr_pntr + 3]); - instr_pntr += 4; - break; - case OP_G: - //OnExecFetch ? .Invoke(RegPC); - if (TraceCallback) { TraceCallback(0); } - //CDLCallback ? .Invoke(RegPC, eCDLogMemFlags.FetchFirst); - - FetchInstruction(ReadMemory(RegPCget())); // note no increment - break; - case JAM: - jammed = true; - instr_pntr--; - break; - case RD_F: - Read_Func_F(instr_table[instr_pntr], instr_table[instr_pntr + 1], instr_table[instr_pntr + 2]); - instr_pntr += 3; - break; - case EI_RETI: - EI_pending = 1; - break; - case INT_GET: - // check if any interrupts got cancelled along the way - // interrupt src = 5 sets the PC to zero as observed - // also the triggering interrupt seems like it is held low (i.e. cannot trigger I flag) until the interrupt is serviced - bit_check = instr_table[instr_pntr]; - instr_pntr++; - //Console.WriteLine(interrupt_src + " " + interrupt_enable + " " + TotalExecutedCycles); - - if (((interrupt_src[0] & (1 << bit_check)) > 0) && ((interrupt_enable[0] & (1 << bit_check)) > 0)) { int_src = bit_check; int_clear = (uint8_t)(1 << bit_check); } - /* - if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; int_clear = 1; } - else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; int_clear = 2; } - else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; int_clear = 4; } - else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; int_clear = 8; } - else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; int_clear = 16; } - else { int_src = 5; int_clear = 0; } - */ - Regs[instr_table[instr_pntr]] = INT_vectors[int_src]; - instr_pntr++; - break; - case HALT_CHK: - I_use = FlagI; - if (Halt_bug_2 && I_use) - { - RegPCset(RegPCget() - 1); - Halt_bug_3 = true; - //Console.WriteLine("Halt_bug_3"); - //Console.WriteLine(TotalExecutedCycles); - } - - Halt_bug_2 = false; - break; - case IRQ_CLEAR: - if ((interrupt_src[0] & (1 << int_src)) > 0) { interrupt_src[0] -= int_clear; } - - if ((interrupt_src[0] & interrupt_enable[0]) == 0) { FlagI = false; } - - // reset back to default state - int_src = 5; - int_clear = 0; - break; - case COND_CHECK: - checker = false; - switch (instr_table[instr_pntr++]) - { - case ALWAYS_T: - checker = true; - break; - case ALWAYS_F: - checker = false; - break; - case FLAG_Z: - checker = FlagZget(); - break; - case FLAG_NZ: - checker = !FlagZget(); - break; - case FLAG_C: - checker = FlagCget(); - break; - case FLAG_NC: - checker = !FlagCget(); - break; - } - - // true condition is what is represented in the instruction vectors - // jump ahead if false - if (checker) - { - instr_pntr++; - } - else - { - // 0 = JR COND, 1 = JP COND, 2 = RET COND, 3 = CALL - switch (instr_table[instr_pntr++]) - { - case 0: - instr_pntr += 10; - break; - case 1: - instr_pntr += 8; - break; - case 2: - instr_pntr += 22; - break; - case 3: - instr_pntr += 26; - break; - } - } - break; - case HALT_FUNC: - if (was_FlagI && (EI_pending == 0) && !interrupts_enabled) - { - // in GBC mode, the HALT bug is worked around by simply adding a NOP - // so it just takes 4 cycles longer to reach the next instruction - - // otherwise, if interrupts are disabled, - // a glitchy decrement to the program counter happens - - // either way, nothing needs to be done here - } - else - { - instr_pntr += 3; - - if (!is_GBC) { skip_once = true; } - // If the interrupt flag is not currently set, but it does get set in the first check - // then a bug is triggered - // With interrupts enabled, this runs the halt command twice - // when they are disabled, it reads the next byte twice - if (!was_FlagI || (was_FlagI && !interrupts_enabled)) { Halt_bug_2 = true; } - - } - break; - } - TotalExecutedCycles++; - } - - /// - /// Optimization method to set cur_instr - /// - void PopulateCURINSTR(uint32_t d0 = 0, uint32_t d1 = 0, uint32_t d2 = 0, uint32_t d3 = 0, uint32_t d4 = 0, uint32_t d5 = 0, uint32_t d6 = 0, uint32_t d7 = 0, uint32_t d8 = 0, - uint32_t d9 = 0, uint32_t d10 = 0, uint32_t d11 = 0, uint32_t d12 = 0, uint32_t d13 = 0, uint32_t d14 = 0, uint32_t d15 = 0, uint32_t d16 = 0, uint32_t d17 = 0, uint32_t d18 = 0, - uint32_t d19 = 0, uint32_t d20 = 0, uint32_t d21 = 0, uint32_t d22 = 0, uint32_t d23 = 0, uint32_t d24 = 0, uint32_t d25 = 0, uint32_t d26 = 0, uint32_t d27 = 0, uint32_t d28 = 0, - uint32_t d29 = 0, uint32_t d30 = 0, uint32_t d31 = 0, uint32_t d32 = 0, uint32_t d33 = 0, uint32_t d34 = 0, uint32_t d35 = 0, uint32_t d36 = 0, uint32_t d37 = 0, uint32_t d38 = 0, - uint32_t d39 = 0, uint32_t d40 = 0, uint32_t d41 = 0, uint32_t d42 = 0, uint32_t d43 = 0, uint32_t d44 = 0, uint32_t d45 = 0, uint32_t d46 = 0, uint32_t d47 = 0, uint32_t d48 = 0, - uint32_t d49 = 0, uint32_t d50 = 0, uint32_t d51 = 0, uint32_t d52 = 0, uint32_t d53 = 0, uint32_t d54 = 0, uint32_t d55 = 0, uint32_t d56 = 0, uint32_t d57 = 0, uint32_t d58 = 0) - { - cur_instr[0] = d0; cur_instr[1] = d1; cur_instr[2] = d2; - cur_instr[3] = d3; cur_instr[4] = d4; cur_instr[5] = d5; - cur_instr[6] = d6; cur_instr[7] = d7; cur_instr[8] = d8; - cur_instr[9] = d9; cur_instr[10] = d10; cur_instr[11] = d11; - cur_instr[12] = d12; cur_instr[13] = d13; cur_instr[14] = d14; - cur_instr[15] = d15; cur_instr[16] = d16; cur_instr[17] = d17; - cur_instr[18] = d18; cur_instr[19] = d19; cur_instr[20] = d20; - cur_instr[21] = d21; cur_instr[22] = d22; cur_instr[23] = d23; - cur_instr[24] = d24; cur_instr[25] = d25; cur_instr[26] = d26; - cur_instr[27] = d27; cur_instr[28] = d28; cur_instr[29] = d29; - cur_instr[30] = d30; cur_instr[31] = d31; cur_instr[32] = d32; - cur_instr[33] = d33; cur_instr[34] = d34; cur_instr[35] = d35; - cur_instr[36] = d36; cur_instr[37] = d37; cur_instr[38] = d38; - cur_instr[39] = d39; cur_instr[40] = d40; cur_instr[41] = d41; - cur_instr[42] = d42; cur_instr[43] = d43; cur_instr[44] = d44; - cur_instr[45] = d45; cur_instr[46] = d46; cur_instr[47] = d47; - cur_instr[48] = d48; cur_instr[49] = d49; cur_instr[50] = d50; - cur_instr[51] = d51; cur_instr[52] = d52; cur_instr[53] = d53; - cur_instr[54] = d54; cur_instr[55] = d55; cur_instr[56] = d56; - cur_instr[57] = d57; cur_instr[58] = d58; - } - - void ResetRegisters() - { - for (int i = 0; i < 14; i++) - { - Regs[i] = 0; - } - } - - #pragma endregion - - #pragma region Interrupts - void INTERRUPT_() - { - PopulateCURINSTR( - IDLE, - DEC16, SPl, SPh, - IDLE, - WR, SPl, SPh, PCh, - INT_GET, 4, W, - DEC16, SPl, SPh, - INT_GET, 3, W, - WR, SPl, SPh, PCl, - INT_GET, 2, W, - IDLE, - INT_GET, 1, W, - IDLE, - INT_GET, 0, W, - ASGN, PCh, 0, - IDLE, - IDLE, - TR, PCl, W, - IRQ_CLEAR, - IDLE, - OP ); - } - - void INTERRUPT_GBC_NOP() - { - PopulateCURINSTR( - IDLE, - DEC16, SPl, SPh, - IDLE, - WR, SPl, SPh, PCh, - IDLE, - DEC16, SPl, SPh, - IDLE, - WR, SPl, SPh, PCl, - IDLE, - IDLE, - IDLE, - IDLE, - IDLE, - INT_GET, 4, W, - INT_GET, 3, W, - INT_GET, 2, W, - INT_GET, 1, W, - INT_GET, 0, W, - TR, PCl, W, - IDLE, - ASGN, PCh, 0, - IRQ_CLEAR, - IDLE, - OP ); - } - - uint8_t INT_vectors[6] = { 0x40, 0x48, 0x50, 0x58, 0x60, 0x00 }; - - uint32_t int_src; - uint8_t int_clear; - int stop_time; - bool stop_check; - bool is_GBC; // GBC automatically adds a NOP to avoid the HALT bug (according to Sinimas) - bool I_use; // in halt mode, the I flag is checked earlier then when deicision to IRQ is taken - bool skip_once; - bool Halt_bug_2; - bool Halt_bug_3; - - void ResetInterrupts() - { - I_use = false; - skip_once = false; - Halt_bug_2 = false; - Halt_bug_3 = false; - interrupts_enabled = false; - - int_src = 5; - int_clear = 0; - } - #pragma endregion - - #pragma region Indirect Ops - - void INT_OP_IND(uint32_t operation, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, Z, src_l, src_h, - IDLE, - operation, Z, - IDLE, - WR, src_l, src_h, Z, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void BIT_OP_IND(uint32_t operation, uint32_t bit, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, Z, src_l, src_h, - IDLE, - operation, bit, Z, - IDLE, - WR, src_l, src_h, Z, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void BIT_TE_IND(uint32_t operation, uint32_t bit, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, Z, src_l, src_h, - IDLE, - operation, bit, Z, - HALT_CHK, - OP ); - } - - void REG_OP_IND_INC(uint32_t operation, uint32_t dest, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, Z, src_l, src_h, - operation, dest, Z, - INC16, src_l, src_h, - HALT_CHK, - OP ); - } - - void REG_OP_IND(uint32_t operation, uint32_t dest, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, Z, src_l, src_h, - IDLE, - operation, dest, Z, - HALT_CHK, - OP ); - } - - void LD_R_IM(uint32_t dest_l, uint32_t dest_h, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, W, src_l, src_h, - IDLE, - INC16, src_l, src_h, - IDLE, - RD, Z, src_l, src_h, - IDLE, - INC16, src_l, src_h, - IDLE, - WR, W, Z, dest_l, - IDLE, - INC16, W, Z, - IDLE, - WR, W, Z, dest_h, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void LD_8_IND_INC(uint32_t dest_l, uint32_t dest_h, uint32_t src) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - WR, dest_l, dest_h, src, - IDLE, - INC16, dest_l, dest_h, - HALT_CHK, - OP ); - } - - void LD_8_IND_DEC(uint32_t dest_l, uint32_t dest_h, uint32_t src) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - WR, dest_l, dest_h, src, - IDLE, - DEC16, dest_l, dest_h, - HALT_CHK, - OP ); - } - - void LD_8_IND(uint32_t dest_l, uint32_t dest_h, uint32_t src) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - WR, dest_l, dest_h, src, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void LD_8_IND_IND(uint32_t dest_l, uint32_t dest_h, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, Z, src_l, src_h, - IDLE, - INC16, src_l, src_h, - IDLE, - WR, dest_l, dest_h, Z, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void LD_IND_8_INC(uint32_t dest, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, dest, src_l, src_h, - IDLE, - INC16, src_l, src_h, - HALT_CHK, - OP ); - } - - void LD_IND_8_INC_HL(uint32_t dest, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, dest, src_l, src_h, - IDLE, - INC16, src_l, src_h, - HALT_CHK, - OP ); - } - - void LD_IND_8_DEC_HL(uint32_t dest, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, dest, src_l, src_h, - IDLE, - DEC16, src_l, src_h, - HALT_CHK, - OP ); - } - - void LD_IND_16(uint32_t dest_l, uint32_t dest_h, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, dest_l, src_l, src_h, - IDLE, - INC16, src_l, src_h, - IDLE, - RD, dest_h, src_l, src_h, - IDLE, - INC16, src_l, src_h, - HALT_CHK, - OP ); - } - - void INC_8_IND(uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, Z, src_l, src_h, - IDLE, - INC8, Z, - IDLE, - WR, src_l, src_h, Z, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void DEC_8_IND(uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, Z, src_l, src_h, - IDLE, - DEC8, Z, - IDLE, - WR, src_l, src_h, Z, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - - void LD_8_IND_FF(uint32_t dest, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, W, src_l, src_h, - INC16, src_l, src_h, - IDLE, - ASGN, Z , 0xFF, - RD, dest, W, Z, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void LD_FF_IND_8(uint32_t dest_l, uint32_t dest_h, uint32_t src) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, W, dest_l, dest_h, - INC16, dest_l, dest_h, - IDLE, - ASGN, Z , 0xFF, - WR, W, Z, src, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void LD_8_IND_FFC(uint32_t dest, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - ASGN, Z , 0xFF, - RD, dest, C, Z, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void LD_FFC_IND_8(uint32_t dest_l, uint32_t dest_h, uint32_t src) - { - PopulateCURINSTR( - IDLE, - IDLE, - ASGN, Z , 0xFF, - WR, C, Z, src, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void LD_16_IND_FF(uint32_t dest, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, W, src_l, src_h, - IDLE, - INC16, src_l, src_h, - IDLE, - RD, Z, src_l, src_h, - IDLE, - INC16, src_l, src_h, - IDLE, - RD, dest, W, Z, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void LD_FF_IND_16(uint32_t dest_l, uint32_t dest_h, uint32_t src) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, W, dest_l, dest_h, - IDLE, - INC16, dest_l, dest_h, - IDLE, - RD, Z, dest_l, dest_h, - IDLE, - INC16, dest_l, dest_h, - IDLE, - WR, W, Z, src, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - #pragma endregion - - #pragma region Direct Ops - - // this contains the vectors of instruction operations - // NOTE: This list is NOT confirmed accurate for each individual cycle - - void NOP_() - { - PopulateCURINSTR( - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void INC_16(uint32_t srcL, uint32_t srcH) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - INC16, - srcL, - srcH, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void DEC_16(uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - DEC16, - src_l, - src_h, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void ADD_16(uint32_t dest_l, uint32_t dest_h, uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - ADD16, dest_l, dest_h, src_l, src_h, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void REG_OP(uint32_t operation, uint32_t dest, uint32_t src) - { - PopulateCURINSTR( - operation, dest, src, - IDLE, - HALT_CHK, - OP ); - } - - void STOP_() - { - PopulateCURINSTR( - RD, Z, PCl, PCh, - INC16, PCl, PCh, - IDLE, - STOP ); - } - - void HALT_() - { - PopulateCURINSTR( - HALT_FUNC, - IDLE, - IDLE, - OP_G, - HALT_CHK, - IDLE, - HALT, 0 ); - } - - void JR_COND(uint32_t cond) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, W, PCl, PCh, - INC16, PCl, PCh, - COND_CHECK, cond, (uint32_t)0, - IDLE, - ASGN, Z, 0, - IDLE, - ADDS, PCl, PCh, W, Z, - HALT_CHK, - OP ); - } - - void JP_COND(uint32_t cond) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, W, PCl, PCh, - IDLE, - INC16, PCl, PCh, - IDLE, - RD, Z, PCl, PCh, - INC16, PCl, PCh, - COND_CHECK, cond, (uint32_t)1, - IDLE, - TR, PCl, W, - IDLE, - TR, PCh, Z, - HALT_CHK, - OP ); - } - - void RET_() - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, PCl, SPl, SPh, - IDLE, - INC16, SPl, SPh, - IDLE, - RD, PCh, SPl, SPh, - IDLE, - INC16, SPl, SPh, - IDLE, - IDLE, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void RETI_() - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, PCl, SPl, SPh, - IDLE, - INC16, SPl, SPh, - IDLE, - RD, PCh, SPl, SPh, - IDLE, - INC16, SPl, SPh, - IDLE, - EI_RETI, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - - void RET_COND(uint32_t cond) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - IDLE, - IDLE, - COND_CHECK, cond, (uint32_t)2, - IDLE, - RD, PCl, SPl, SPh, - IDLE, - INC16, SPl, SPh, - IDLE, - RD, PCh, SPl, SPh, - IDLE, - INC16, SPl, SPh, - IDLE, - IDLE, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void CALL_COND(uint32_t cond) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, W, PCl, PCh, - INC16, PCl, PCh, - IDLE, - IDLE, - RD, Z, PCl, PCh, - INC16, PCl, PCh, - COND_CHECK, cond, (uint32_t)3, - DEC16, SPl, SPh, - IDLE, - IDLE, - IDLE, - IDLE, - WR, SPl, SPh, PCh, - IDLE, - IDLE, - DEC16, SPl, SPh, - WR, SPl, SPh, PCl, - TR, PCl, W, - TR, PCh, Z, - HALT_CHK, - OP ); - } - - void INT_OP(uint32_t operation, uint32_t src) - { - PopulateCURINSTR( - operation, src, - IDLE, - HALT_CHK, - OP ); - } - - void BIT_OP(uint32_t operation, uint32_t bit, uint32_t src) - { - PopulateCURINSTR( - operation, bit, src, - IDLE, - HALT_CHK, - OP ); - } - - void PUSH_(uint32_t src_l, uint32_t src_h) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - IDLE, - IDLE, - DEC16, SPl, SPh, - IDLE, - WR, SPl, SPh, src_h, - IDLE, - DEC16, SPl, SPh, - IDLE, - WR, SPl, SPh, src_l, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - // NOTE: this is the only instruction that can write to F - // but the bottom 4 bits of F are always 0, so instead of putting a special check for every read op - // let's just put a special operation here specifically for F - void POP_(uint32_t src_l, uint32_t src_h) - { - if (src_l != F) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, src_l, SPl, SPh, - IDLE, - INC16, SPl, SPh, - IDLE, - RD, src_h, SPl, SPh, - IDLE, - INC16, SPl, SPh, - HALT_CHK, - OP ); - } - else - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD_F, src_l, SPl, SPh, - IDLE, - INC16, SPl, SPh, - IDLE, - RD, src_h, SPl, SPh, - IDLE, - INC16, SPl, SPh, - HALT_CHK, - OP ); - } - } - - void RST_(uint32_t n) - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - DEC16, SPl, SPh, - IDLE, - IDLE, - IDLE, - WR, SPl, SPh, PCh, - DEC16, SPl, SPh, - IDLE, - IDLE, - WR, SPl, SPh, PCl, - ASGN, PCh, 0, - ASGN, PCl, n, - HALT_CHK, - OP ); - } - - void PREFIX_() - { - PopulateCURINSTR( - PREFIX, - IDLE, - IDLE, - OP ); - } - - void DI_() - { - PopulateCURINSTR( - DI, - IDLE, - HALT_CHK, - OP ); - } - - void EI_() - { - PopulateCURINSTR( - EI, - IDLE, - HALT_CHK, - OP ); - } - - void JP_HL() - { - PopulateCURINSTR( - TR, PCl, L, - TR, PCh, H, - HALT_CHK, - OP ); - } - - void ADD_SP() - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - IDLE, - IDLE, - RD, W, PCl, PCh, - IDLE, - INC16, PCl, PCh, - IDLE, - ASGN, Z, 0, - IDLE, - ADDS, SPl, SPh, W, Z, - IDLE, - IDLE, - HALT_CHK, - OP ); - } - - void LD_SP_HL() - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - TR, SPl, L, - IDLE, - TR, SPh, H, - HALT_CHK, - OP ); - } - - void LD_HL_SPn() - { - PopulateCURINSTR( - IDLE, - IDLE, - IDLE, - RD, W, PCl, PCh, - IDLE, - INC16, PCl, PCh, - TR, H, SPh, - TR, L, SPl, - ASGN, Z, 0, - ADDS, L, H, W, Z, - HALT_CHK, - OP ); - } - - void JAM_() - { - PopulateCURINSTR( - JAM, - IDLE, - IDLE, - IDLE ); - } - - #pragma endregion - - #pragma region Decode - - void BuildInstructionTable() - { - for (int i = 0; i < 256; i++) - { - switch (i) - { - case 0x00: NOP_(); break; // NOP - case 0x01: LD_IND_16(C, B, PCl, PCh); break; // LD BC, nn - case 0x02: LD_8_IND(C, B, A); break; // LD (BC), A - case 0x03: INC_16(C, B); break; // INC BC - case 0x04: INT_OP(INC8, B); break; // INC B - case 0x05: INT_OP(DEC8, B); break; // DEC B - case 0x06: LD_IND_8_INC(B, PCl, PCh); break; // LD B, n - case 0x07: INT_OP(RLC, Aim); break; // RLCA - case 0x08: LD_R_IM(SPl, SPh, PCl, PCh); break; // LD (imm), SP - case 0x09: ADD_16(L, H, C, B); break; // ADD HL, BC - case 0x0A: REG_OP_IND(TR, A, C, B); break; // LD A, (BC) - case 0x0B: DEC_16(C, B); break; // DEC BC - case 0x0C: INT_OP(INC8, C); break; // INC C - case 0x0D: INT_OP(DEC8, C); break; // DEC C - case 0x0E: LD_IND_8_INC(C, PCl, PCh); break; // LD C, n - case 0x0F: INT_OP(RRC, Aim); break; // RRCA - case 0x10: STOP_(); break; // STOP - case 0x11: LD_IND_16(E, D, PCl, PCh); break; // LD DE, nn - case 0x12: LD_8_IND(E, D, A); break; // LD (DE), A - case 0x13: INC_16(E, D); break; // INC DE - case 0x14: INT_OP(INC8, D); break; // INC D - case 0x15: INT_OP(DEC8, D); break; // DEC D - case 0x16: LD_IND_8_INC(D, PCl, PCh); break; // LD D, n - case 0x17: INT_OP(RL, Aim); break; // RLA - case 0x18: JR_COND(ALWAYS_T); break; // JR, r8 - case 0x19: ADD_16(L, H, E, D); break; // ADD HL, DE - case 0x1A: REG_OP_IND(TR, A, E, D); break; // LD A, (DE) - case 0x1B: DEC_16(E, D); break; // DEC DE - case 0x1C: INT_OP(INC8, E); break; // INC E - case 0x1D: INT_OP(DEC8, E); break; // DEC E - case 0x1E: LD_IND_8_INC(E, PCl, PCh); break; // LD E, n - case 0x1F: INT_OP(RR, Aim); break; // RRA - case 0x20: JR_COND(FLAG_NZ); break; // JR NZ, r8 - case 0x21: LD_IND_16(L, H, PCl, PCh); break; // LD HL, nn - case 0x22: LD_8_IND_INC(L, H, A); break; // LD (HL+), A - case 0x23: INC_16(L, H); break; // INC HL - case 0x24: INT_OP(INC8, H); break; // INC H - case 0x25: INT_OP(DEC8, H); break; // DEC H - case 0x26: LD_IND_8_INC(H, PCl, PCh); break; // LD H, n - case 0x27: INT_OP(DA, A); break; // DAA - case 0x28: JR_COND(FLAG_Z); break; // JR Z, r8 - case 0x29: ADD_16(L, H, L, H); break; // ADD HL, HL - case 0x2A: LD_IND_8_INC_HL(A, L, H); break; // LD A, (HL+) - case 0x2B: DEC_16(L, H); break; // DEC HL - case 0x2C: INT_OP(INC8, L); break; // INC L - case 0x2D: INT_OP(DEC8, L); break; // DEC L - case 0x2E: LD_IND_8_INC(L, PCl, PCh); break; // LD L, n - case 0x2F: INT_OP(CPL, A); break; // CPL - case 0x30: JR_COND(FLAG_NC); break; // JR NC, r8 - case 0x31: LD_IND_16(SPl, SPh, PCl, PCh); break; // LD SP, nn - case 0x32: LD_8_IND_DEC(L, H, A); break; // LD (HL-), A - case 0x33: INC_16(SPl, SPh); break; // INC SP - case 0x34: INC_8_IND(L, H); break; // INC (HL) - case 0x35: DEC_8_IND(L, H); break; // DEC (HL) - case 0x36: LD_8_IND_IND(L, H, PCl, PCh); break; // LD (HL), n - case 0x37: INT_OP(SCF, A); break; // SCF - case 0x38: JR_COND(FLAG_C); break; // JR C, r8 - case 0x39: ADD_16(L, H, SPl, SPh); break; // ADD HL, SP - case 0x3A: LD_IND_8_DEC_HL(A, L, H); break; // LD A, (HL-) - case 0x3B: DEC_16(SPl, SPh); break; // DEC SP - case 0x3C: INT_OP(INC8, A); break; // INC A - case 0x3D: INT_OP(DEC8, A); break; // DEC A - case 0x3E: LD_IND_8_INC(A, PCl, PCh); break; // LD A, n - case 0x3F: INT_OP(CCF, A); break; // CCF - case 0x40: REG_OP(TR, B, B); break; // LD B, B - case 0x41: REG_OP(TR, B, C); break; // LD B, C - case 0x42: REG_OP(TR, B, D); break; // LD B, D - case 0x43: REG_OP(TR, B, E); break; // LD B, E - case 0x44: REG_OP(TR, B, H); break; // LD B, H - case 0x45: REG_OP(TR, B, L); break; // LD B, L - case 0x46: REG_OP_IND(TR, B, L, H); break; // LD B, (HL) - case 0x47: REG_OP(TR, B, A); break; // LD B, A - case 0x48: REG_OP(TR, C, B); break; // LD C, B - case 0x49: REG_OP(TR, C, C); break; // LD C, C - case 0x4A: REG_OP(TR, C, D); break; // LD C, D - case 0x4B: REG_OP(TR, C, E); break; // LD C, E - case 0x4C: REG_OP(TR, C, H); break; // LD C, H - case 0x4D: REG_OP(TR, C, L); break; // LD C, L - case 0x4E: REG_OP_IND(TR, C, L, H); break; // LD C, (HL) - case 0x4F: REG_OP(TR, C, A); break; // LD C, A - case 0x50: REG_OP(TR, D, B); break; // LD D, B - case 0x51: REG_OP(TR, D, C); break; // LD D, C - case 0x52: REG_OP(TR, D, D); break; // LD D, D - case 0x53: REG_OP(TR, D, E); break; // LD D, E - case 0x54: REG_OP(TR, D, H); break; // LD D, H - case 0x55: REG_OP(TR, D, L); break; // LD D, L - case 0x56: REG_OP_IND(TR, D, L, H); break; // LD D, (HL) - case 0x57: REG_OP(TR, D, A); break; // LD D, A - case 0x58: REG_OP(TR, E, B); break; // LD E, B - case 0x59: REG_OP(TR, E, C); break; // LD E, C - case 0x5A: REG_OP(TR, E, D); break; // LD E, D - case 0x5B: REG_OP(TR, E, E); break; // LD E, E - case 0x5C: REG_OP(TR, E, H); break; // LD E, H - case 0x5D: REG_OP(TR, E, L); break; // LD E, L - case 0x5E: REG_OP_IND(TR, E, L, H); break; // LD E, (HL) - case 0x5F: REG_OP(TR, E, A); break; // LD E, A - case 0x60: REG_OP(TR, H, B); break; // LD H, B - case 0x61: REG_OP(TR, H, C); break; // LD H, C - case 0x62: REG_OP(TR, H, D); break; // LD H, D - case 0x63: REG_OP(TR, H, E); break; // LD H, E - case 0x64: REG_OP(TR, H, H); break; // LD H, H - case 0x65: REG_OP(TR, H, L); break; // LD H, L - case 0x66: REG_OP_IND(TR, H, L, H); break; // LD H, (HL) - case 0x67: REG_OP(TR, H, A); break; // LD H, A - case 0x68: REG_OP(TR, L, B); break; // LD L, B - case 0x69: REG_OP(TR, L, C); break; // LD L, C - case 0x6A: REG_OP(TR, L, D); break; // LD L, D - case 0x6B: REG_OP(TR, L, E); break; // LD L, E - case 0x6C: REG_OP(TR, L, H); break; // LD L, H - case 0x6D: REG_OP(TR, L, L); break; // LD L, L - case 0x6E: REG_OP_IND(TR, L, L, H); break; // LD L, (HL) - case 0x6F: REG_OP(TR, L, A); break; // LD L, A - case 0x70: LD_8_IND(L, H, B); break; // LD (HL), B - case 0x71: LD_8_IND(L, H, C); break; // LD (HL), C - case 0x72: LD_8_IND(L, H, D); break; // LD (HL), D - case 0x73: LD_8_IND(L, H, E); break; // LD (HL), E - case 0x74: LD_8_IND(L, H, H); break; // LD (HL), H - case 0x75: LD_8_IND(L, H, L); break; // LD (HL), L - case 0x76: HALT_(); break; // HALT - case 0x77: LD_8_IND(L, H, A); break; // LD (HL), A - case 0x78: REG_OP(TR, A, B); break; // LD A, B - case 0x79: REG_OP(TR, A, C); break; // LD A, C - case 0x7A: REG_OP(TR, A, D); break; // LD A, D - case 0x7B: REG_OP(TR, A, E); break; // LD A, E - case 0x7C: REG_OP(TR, A, H); break; // LD A, H - case 0x7D: REG_OP(TR, A, L); break; // LD A, L - case 0x7E: REG_OP_IND(TR, A, L, H); break; // LD A, (HL) - case 0x7F: REG_OP(TR, A, A); break; // LD A, A - case 0x80: REG_OP(ADD8, A, B); break; // ADD A, B - case 0x81: REG_OP(ADD8, A, C); break; // ADD A, C - case 0x82: REG_OP(ADD8, A, D); break; // ADD A, D - case 0x83: REG_OP(ADD8, A, E); break; // ADD A, E - case 0x84: REG_OP(ADD8, A, H); break; // ADD A, H - case 0x85: REG_OP(ADD8, A, L); break; // ADD A, L - case 0x86: REG_OP_IND(ADD8, A, L, H); break; // ADD A, (HL) - case 0x87: REG_OP(ADD8, A, A); break; // ADD A, A - case 0x88: REG_OP(ADC8, A, B); break; // ADC A, B - case 0x89: REG_OP(ADC8, A, C); break; // ADC A, C - case 0x8A: REG_OP(ADC8, A, D); break; // ADC A, D - case 0x8B: REG_OP(ADC8, A, E); break; // ADC A, E - case 0x8C: REG_OP(ADC8, A, H); break; // ADC A, H - case 0x8D: REG_OP(ADC8, A, L); break; // ADC A, L - case 0x8E: REG_OP_IND(ADC8, A, L, H); break; // ADC A, (HL) - case 0x8F: REG_OP(ADC8, A, A); break; // ADC A, A - case 0x90: REG_OP(SUB8, A, B); break; // SUB A, B - case 0x91: REG_OP(SUB8, A, C); break; // SUB A, C - case 0x92: REG_OP(SUB8, A, D); break; // SUB A, D - case 0x93: REG_OP(SUB8, A, E); break; // SUB A, E - case 0x94: REG_OP(SUB8, A, H); break; // SUB A, H - case 0x95: REG_OP(SUB8, A, L); break; // SUB A, L - case 0x96: REG_OP_IND(SUB8, A, L, H); break; // SUB A, (HL) - case 0x97: REG_OP(SUB8, A, A); break; // SUB A, A - case 0x98: REG_OP(SBC8, A, B); break; // SBC A, B - case 0x99: REG_OP(SBC8, A, C); break; // SBC A, C - case 0x9A: REG_OP(SBC8, A, D); break; // SBC A, D - case 0x9B: REG_OP(SBC8, A, E); break; // SBC A, E - case 0x9C: REG_OP(SBC8, A, H); break; // SBC A, H - case 0x9D: REG_OP(SBC8, A, L); break; // SBC A, L - case 0x9E: REG_OP_IND(SBC8, A, L, H); break; // SBC A, (HL) - case 0x9F: REG_OP(SBC8, A, A); break; // SBC A, A - case 0xA0: REG_OP(AND8, A, B); break; // AND A, B - case 0xA1: REG_OP(AND8, A, C); break; // AND A, C - case 0xA2: REG_OP(AND8, A, D); break; // AND A, D - case 0xA3: REG_OP(AND8, A, E); break; // AND A, E - case 0xA4: REG_OP(AND8, A, H); break; // AND A, H - case 0xA5: REG_OP(AND8, A, L); break; // AND A, L - case 0xA6: REG_OP_IND(AND8, A, L, H); break; // AND A, (HL) - case 0xA7: REG_OP(AND8, A, A); break; // AND A, A - case 0xA8: REG_OP(XOR8, A, B); break; // XOR A, B - case 0xA9: REG_OP(XOR8, A, C); break; // XOR A, C - case 0xAA: REG_OP(XOR8, A, D); break; // XOR A, D - case 0xAB: REG_OP(XOR8, A, E); break; // XOR A, E - case 0xAC: REG_OP(XOR8, A, H); break; // XOR A, H - case 0xAD: REG_OP(XOR8, A, L); break; // XOR A, L - case 0xAE: REG_OP_IND(XOR8, A, L, H); break; // XOR A, (HL) - case 0xAF: REG_OP(XOR8, A, A); break; // XOR A, A - case 0xB0: REG_OP(OR8, A, B); break; // OR A, B - case 0xB1: REG_OP(OR8, A, C); break; // OR A, C - case 0xB2: REG_OP(OR8, A, D); break; // OR A, D - case 0xB3: REG_OP(OR8, A, E); break; // OR A, E - case 0xB4: REG_OP(OR8, A, H); break; // OR A, H - case 0xB5: REG_OP(OR8, A, L); break; // OR A, L - case 0xB6: REG_OP_IND(OR8, A, L, H); break; // OR A, (HL) - case 0xB7: REG_OP(OR8, A, A); break; // OR A, A - case 0xB8: REG_OP(CP8, A, B); break; // CP A, B - case 0xB9: REG_OP(CP8, A, C); break; // CP A, C - case 0xBA: REG_OP(CP8, A, D); break; // CP A, D - case 0xBB: REG_OP(CP8, A, E); break; // CP A, E - case 0xBC: REG_OP(CP8, A, H); break; // CP A, H - case 0xBD: REG_OP(CP8, A, L); break; // CP A, L - case 0xBE: REG_OP_IND(CP8, A, L, H); break; // CP A, (HL) - case 0xBF: REG_OP(CP8, A, A); break; // CP A, A - case 0xC0: RET_COND(FLAG_NZ); break; // Ret NZ - case 0xC1: POP_(C, B); break; // POP BC - case 0xC2: JP_COND(FLAG_NZ); break; // JP NZ - case 0xC3: JP_COND(ALWAYS_T); break; // JP - case 0xC4: CALL_COND(FLAG_NZ); break; // CALL NZ - case 0xC5: PUSH_(C, B); break; // PUSH BC - case 0xC6: REG_OP_IND_INC(ADD8, A, PCl, PCh); break; // ADD A, n - case 0xC7: RST_(0); break; // RST 0 - case 0xC8: RET_COND(FLAG_Z); break; // RET Z - case 0xC9: RET_(); break; // RET - case 0xCA: JP_COND(FLAG_Z); break; // JP Z - case 0xCB: PREFIX_(); break; // PREFIX - case 0xCC: CALL_COND(FLAG_Z); break; // CALL Z - case 0xCD: CALL_COND(ALWAYS_T); break; // CALL - case 0xCE: REG_OP_IND_INC(ADC8, A, PCl, PCh); break; // ADC A, n - case 0xCF: RST_(0x08); break; // RST 0x08 - case 0xD0: RET_COND(FLAG_NC); break; // Ret NC - case 0xD1: POP_(E, D); break; // POP DE - case 0xD2: JP_COND(FLAG_NC); break; // JP NC - case 0xD3: JAM_(); break; // JAM - case 0xD4: CALL_COND(FLAG_NC); break; // CALL NC - case 0xD5: PUSH_(E, D); break; // PUSH DE - case 0xD6: REG_OP_IND_INC(SUB8, A, PCl, PCh); break; // SUB A, n - case 0xD7: RST_(0x10); break; // RST 0x10 - case 0xD8: RET_COND(FLAG_C); break; // RET C - case 0xD9: RETI_(); break; // RETI - case 0xDA: JP_COND(FLAG_C); break; // JP C - case 0xDB: JAM_(); break; // JAM - case 0xDC: CALL_COND(FLAG_C); break; // CALL C - case 0xDD: JAM_(); break; // JAM - case 0xDE: REG_OP_IND_INC(SBC8, A, PCl, PCh); break; // SBC A, n - case 0xDF: RST_(0x18); break; // RST 0x18 - case 0xE0: LD_FF_IND_8(PCl, PCh, A); break; // LD(n), A - case 0xE1: POP_(L, H); break; // POP HL - case 0xE2: LD_FFC_IND_8(PCl, PCh, A); break; // LD(C), A - case 0xE3: JAM_(); break; // JAM - case 0xE4: JAM_(); break; // JAM - case 0xE5: PUSH_(L, H); break; // PUSH HL - case 0xE6: REG_OP_IND_INC(AND8, A, PCl, PCh); break; // AND A, n - case 0xE7: RST_(0x20); break; // RST 0x20 - case 0xE8: ADD_SP(); break; // ADD SP,n - case 0xE9: JP_HL(); break; // JP (HL) - case 0xEA: LD_FF_IND_16(PCl, PCh, A); break; // LD(nn), A - case 0xEB: JAM_(); break; // JAM - case 0xEC: JAM_(); break; // JAM - case 0xED: JAM_(); break; // JAM - case 0xEE: REG_OP_IND_INC(XOR8, A, PCl, PCh); break; // XOR A, n - case 0xEF: RST_(0x28); break; // RST 0x28 - case 0xF0: LD_8_IND_FF(A, PCl, PCh); break; // A, LD(n) - case 0xF1: POP_(F, A); break; // POP AF - case 0xF2: LD_8_IND_FFC(A, PCl, PCh); break; // A, LD(C) - case 0xF3: DI_(); break; // DI - case 0xF4: JAM_(); break; // JAM - case 0xF5: PUSH_(F, A); break; // PUSH AF - case 0xF6: REG_OP_IND_INC(OR8, A, PCl, PCh); break; // OR A, n - case 0xF7: RST_(0x30); break; // RST 0x30 - case 0xF8: LD_HL_SPn(); break; // LD HL, SP+n - case 0xF9: LD_SP_HL(); break; // LD, SP, HL - case 0xFA: LD_16_IND_FF(A, PCl, PCh); break; // A, LD(nn) - case 0xFB: EI_(); break; // EI - case 0xFC: JAM_(); break; // JAM - case 0xFD: JAM_(); break; // JAM - case 0xFE: REG_OP_IND_INC(CP8, A, PCl, PCh); break; // XOR A, n - case 0xFF: RST_(0x38); break; // RST 0x38 - } - - for (int j = 0; j < 60; j++) - { - instr_table[i * 60 + j] = cur_instr[j]; - } - - switch (i) - { - case 0x00: INT_OP(RLC, B); break; // RLC B - case 0x01: INT_OP(RLC, C); break; // RLC C - case 0x02: INT_OP(RLC, D); break; // RLC D - case 0x03: INT_OP(RLC, E); break; // RLC E - case 0x04: INT_OP(RLC, H); break; // RLC H - case 0x05: INT_OP(RLC, L); break; // RLC L - case 0x06: INT_OP_IND(RLC, L, H); break; // RLC (HL) - case 0x07: INT_OP(RLC, A); break; // RLC A - case 0x08: INT_OP(RRC, B); break; // RRC B - case 0x09: INT_OP(RRC, C); break; // RRC C - case 0x0A: INT_OP(RRC, D); break; // RRC D - case 0x0B: INT_OP(RRC, E); break; // RRC E - case 0x0C: INT_OP(RRC, H); break; // RRC H - case 0x0D: INT_OP(RRC, L); break; // RRC L - case 0x0E: INT_OP_IND(RRC, L, H); break; // RRC (HL) - case 0x0F: INT_OP(RRC, A); break; // RRC A - case 0x10: INT_OP(RL, B); break; // RL B - case 0x11: INT_OP(RL, C); break; // RL C - case 0x12: INT_OP(RL, D); break; // RL D - case 0x13: INT_OP(RL, E); break; // RL E - case 0x14: INT_OP(RL, H); break; // RL H - case 0x15: INT_OP(RL, L); break; // RL L - case 0x16: INT_OP_IND(RL, L, H); break; // RL (HL) - case 0x17: INT_OP(RL, A); break; // RL A - case 0x18: INT_OP(RR, B); break; // RR B - case 0x19: INT_OP(RR, C); break; // RR C - case 0x1A: INT_OP(RR, D); break; // RR D - case 0x1B: INT_OP(RR, E); break; // RR E - case 0x1C: INT_OP(RR, H); break; // RR H - case 0x1D: INT_OP(RR, L); break; // RR L - case 0x1E: INT_OP_IND(RR, L, H); break; // RR (HL) - case 0x1F: INT_OP(RR, A); break; // RR A - case 0x20: INT_OP(SLA, B); break; // SLA B - case 0x21: INT_OP(SLA, C); break; // SLA C - case 0x22: INT_OP(SLA, D); break; // SLA D - case 0x23: INT_OP(SLA, E); break; // SLA E - case 0x24: INT_OP(SLA, H); break; // SLA H - case 0x25: INT_OP(SLA, L); break; // SLA L - case 0x26: INT_OP_IND(SLA, L, H); break; // SLA (HL) - case 0x27: INT_OP(SLA, A); break; // SLA A - case 0x28: INT_OP(SRA, B); break; // SRA B - case 0x29: INT_OP(SRA, C); break; // SRA C - case 0x2A: INT_OP(SRA, D); break; // SRA D - case 0x2B: INT_OP(SRA, E); break; // SRA E - case 0x2C: INT_OP(SRA, H); break; // SRA H - case 0x2D: INT_OP(SRA, L); break; // SRA L - case 0x2E: INT_OP_IND(SRA, L, H); break; // SRA (HL) - case 0x2F: INT_OP(SRA, A); break; // SRA A - case 0x30: INT_OP(SWAP, B); break; // SWAP B - case 0x31: INT_OP(SWAP, C); break; // SWAP C - case 0x32: INT_OP(SWAP, D); break; // SWAP D - case 0x33: INT_OP(SWAP, E); break; // SWAP E - case 0x34: INT_OP(SWAP, H); break; // SWAP H - case 0x35: INT_OP(SWAP, L); break; // SWAP L - case 0x36: INT_OP_IND(SWAP, L, H); break; // SWAP (HL) - case 0x37: INT_OP(SWAP, A); break; // SWAP A - case 0x38: INT_OP(SRL, B); break; // SRL B - case 0x39: INT_OP(SRL, C); break; // SRL C - case 0x3A: INT_OP(SRL, D); break; // SRL D - case 0x3B: INT_OP(SRL, E); break; // SRL E - case 0x3C: INT_OP(SRL, H); break; // SRL H - case 0x3D: INT_OP(SRL, L); break; // SRL L - case 0x3E: INT_OP_IND(SRL, L, H); break; // SRL (HL) - case 0x3F: INT_OP(SRL, A); break; // SRL A - case 0x40: BIT_OP(BIT, 0, B); break; // BIT 0, B - case 0x41: BIT_OP(BIT, 0, C); break; // BIT 0, C - case 0x42: BIT_OP(BIT, 0, D); break; // BIT 0, D - case 0x43: BIT_OP(BIT, 0, E); break; // BIT 0, E - case 0x44: BIT_OP(BIT, 0, H); break; // BIT 0, H - case 0x45: BIT_OP(BIT, 0, L); break; // BIT 0, L - case 0x46: BIT_TE_IND(BIT, 0, L, H); break; // BIT 0, (HL) - case 0x47: BIT_OP(BIT, 0, A); break; // BIT 0, A - case 0x48: BIT_OP(BIT, 1, B); break; // BIT 1, B - case 0x49: BIT_OP(BIT, 1, C); break; // BIT 1, C - case 0x4A: BIT_OP(BIT, 1, D); break; // BIT 1, D - case 0x4B: BIT_OP(BIT, 1, E); break; // BIT 1, E - case 0x4C: BIT_OP(BIT, 1, H); break; // BIT 1, H - case 0x4D: BIT_OP(BIT, 1, L); break; // BIT 1, L - case 0x4E: BIT_TE_IND(BIT, 1, L, H); break; // BIT 1, (HL) - case 0x4F: BIT_OP(BIT, 1, A); break; // BIT 1, A - case 0x50: BIT_OP(BIT, 2, B); break; // BIT 2, B - case 0x51: BIT_OP(BIT, 2, C); break; // BIT 2, C - case 0x52: BIT_OP(BIT, 2, D); break; // BIT 2, D - case 0x53: BIT_OP(BIT, 2, E); break; // BIT 2, E - case 0x54: BIT_OP(BIT, 2, H); break; // BIT 2, H - case 0x55: BIT_OP(BIT, 2, L); break; // BIT 2, L - case 0x56: BIT_TE_IND(BIT, 2, L, H); break; // BIT 2, (HL) - case 0x57: BIT_OP(BIT, 2, A); break; // BIT 2, A - case 0x58: BIT_OP(BIT, 3, B); break; // BIT 3, B - case 0x59: BIT_OP(BIT, 3, C); break; // BIT 3, C - case 0x5A: BIT_OP(BIT, 3, D); break; // BIT 3, D - case 0x5B: BIT_OP(BIT, 3, E); break; // BIT 3, E - case 0x5C: BIT_OP(BIT, 3, H); break; // BIT 3, H - case 0x5D: BIT_OP(BIT, 3, L); break; // BIT 3, L - case 0x5E: BIT_TE_IND(BIT, 3, L, H); break; // BIT 3, (HL) - case 0x5F: BIT_OP(BIT, 3, A); break; // BIT 3, A - case 0x60: BIT_OP(BIT, 4, B); break; // BIT 4, B - case 0x61: BIT_OP(BIT, 4, C); break; // BIT 4, C - case 0x62: BIT_OP(BIT, 4, D); break; // BIT 4, D - case 0x63: BIT_OP(BIT, 4, E); break; // BIT 4, E - case 0x64: BIT_OP(BIT, 4, H); break; // BIT 4, H - case 0x65: BIT_OP(BIT, 4, L); break; // BIT 4, L - case 0x66: BIT_TE_IND(BIT, 4, L, H); break; // BIT 4, (HL) - case 0x67: BIT_OP(BIT, 4, A); break; // BIT 4, A - case 0x68: BIT_OP(BIT, 5, B); break; // BIT 5, B - case 0x69: BIT_OP(BIT, 5, C); break; // BIT 5, C - case 0x6A: BIT_OP(BIT, 5, D); break; // BIT 5, D - case 0x6B: BIT_OP(BIT, 5, E); break; // BIT 5, E - case 0x6C: BIT_OP(BIT, 5, H); break; // BIT 5, H - case 0x6D: BIT_OP(BIT, 5, L); break; // BIT 5, L - case 0x6E: BIT_TE_IND(BIT, 5, L, H); break; // BIT 5, (HL) - case 0x6F: BIT_OP(BIT, 5, A); break; // BIT 5, A - case 0x70: BIT_OP(BIT, 6, B); break; // BIT 6, B - case 0x71: BIT_OP(BIT, 6, C); break; // BIT 6, C - case 0x72: BIT_OP(BIT, 6, D); break; // BIT 6, D - case 0x73: BIT_OP(BIT, 6, E); break; // BIT 6, E - case 0x74: BIT_OP(BIT, 6, H); break; // BIT 6, H - case 0x75: BIT_OP(BIT, 6, L); break; // BIT 6, L - case 0x76: BIT_TE_IND(BIT, 6, L, H); break; // BIT 6, (HL) - case 0x77: BIT_OP(BIT, 6, A); break; // BIT 6, A - case 0x78: BIT_OP(BIT, 7, B); break; // BIT 7, B - case 0x79: BIT_OP(BIT, 7, C); break; // BIT 7, C - case 0x7A: BIT_OP(BIT, 7, D); break; // BIT 7, D - case 0x7B: BIT_OP(BIT, 7, E); break; // BIT 7, E - case 0x7C: BIT_OP(BIT, 7, H); break; // BIT 7, H - case 0x7D: BIT_OP(BIT, 7, L); break; // BIT 7, L - case 0x7E: BIT_TE_IND(BIT, 7, L, H); break; // BIT 7, (HL) - case 0x7F: BIT_OP(BIT, 7, A); break; // BIT 7, A - case 0x80: BIT_OP(RES, 0, B); break; // RES 0, B - case 0x81: BIT_OP(RES, 0, C); break; // RES 0, C - case 0x82: BIT_OP(RES, 0, D); break; // RES 0, D - case 0x83: BIT_OP(RES, 0, E); break; // RES 0, E - case 0x84: BIT_OP(RES, 0, H); break; // RES 0, H - case 0x85: BIT_OP(RES, 0, L); break; // RES 0, L - case 0x86: BIT_OP_IND(RES, 0, L, H); break; // RES 0, (HL) - case 0x87: BIT_OP(RES, 0, A); break; // RES 0, A - case 0x88: BIT_OP(RES, 1, B); break; // RES 1, B - case 0x89: BIT_OP(RES, 1, C); break; // RES 1, C - case 0x8A: BIT_OP(RES, 1, D); break; // RES 1, D - case 0x8B: BIT_OP(RES, 1, E); break; // RES 1, E - case 0x8C: BIT_OP(RES, 1, H); break; // RES 1, H - case 0x8D: BIT_OP(RES, 1, L); break; // RES 1, L - case 0x8E: BIT_OP_IND(RES, 1, L, H); break; // RES 1, (HL) - case 0x8F: BIT_OP(RES, 1, A); break; // RES 1, A - case 0x90: BIT_OP(RES, 2, B); break; // RES 2, B - case 0x91: BIT_OP(RES, 2, C); break; // RES 2, C - case 0x92: BIT_OP(RES, 2, D); break; // RES 2, D - case 0x93: BIT_OP(RES, 2, E); break; // RES 2, E - case 0x94: BIT_OP(RES, 2, H); break; // RES 2, H - case 0x95: BIT_OP(RES, 2, L); break; // RES 2, L - case 0x96: BIT_OP_IND(RES, 2, L, H); break; // RES 2, (HL) - case 0x97: BIT_OP(RES, 2, A); break; // RES 2, A - case 0x98: BIT_OP(RES, 3, B); break; // RES 3, B - case 0x99: BIT_OP(RES, 3, C); break; // RES 3, C - case 0x9A: BIT_OP(RES, 3, D); break; // RES 3, D - case 0x9B: BIT_OP(RES, 3, E); break; // RES 3, E - case 0x9C: BIT_OP(RES, 3, H); break; // RES 3, H - case 0x9D: BIT_OP(RES, 3, L); break; // RES 3, L - case 0x9E: BIT_OP_IND(RES, 3, L, H); break; // RES 3, (HL) - case 0x9F: BIT_OP(RES, 3, A); break; // RES 3, A - case 0xA0: BIT_OP(RES, 4, B); break; // RES 4, B - case 0xA1: BIT_OP(RES, 4, C); break; // RES 4, C - case 0xA2: BIT_OP(RES, 4, D); break; // RES 4, D - case 0xA3: BIT_OP(RES, 4, E); break; // RES 4, E - case 0xA4: BIT_OP(RES, 4, H); break; // RES 4, H - case 0xA5: BIT_OP(RES, 4, L); break; // RES 4, L - case 0xA6: BIT_OP_IND(RES, 4, L, H); break; // RES 4, (HL) - case 0xA7: BIT_OP(RES, 4, A); break; // RES 4, A - case 0xA8: BIT_OP(RES, 5, B); break; // RES 5, B - case 0xA9: BIT_OP(RES, 5, C); break; // RES 5, C - case 0xAA: BIT_OP(RES, 5, D); break; // RES 5, D - case 0xAB: BIT_OP(RES, 5, E); break; // RES 5, E - case 0xAC: BIT_OP(RES, 5, H); break; // RES 5, H - case 0xAD: BIT_OP(RES, 5, L); break; // RES 5, L - case 0xAE: BIT_OP_IND(RES, 5, L, H); break; // RES 5, (HL) - case 0xAF: BIT_OP(RES, 5, A); break; // RES 5, A - case 0xB0: BIT_OP(RES, 6, B); break; // RES 6, B - case 0xB1: BIT_OP(RES, 6, C); break; // RES 6, C - case 0xB2: BIT_OP(RES, 6, D); break; // RES 6, D - case 0xB3: BIT_OP(RES, 6, E); break; // RES 6, E - case 0xB4: BIT_OP(RES, 6, H); break; // RES 6, H - case 0xB5: BIT_OP(RES, 6, L); break; // RES 6, L - case 0xB6: BIT_OP_IND(RES, 6, L, H); break; // RES 6, (HL) - case 0xB7: BIT_OP(RES, 6, A); break; // RES 6, A - case 0xB8: BIT_OP(RES, 7, B); break; // RES 7, B - case 0xB9: BIT_OP(RES, 7, C); break; // RES 7, C - case 0xBA: BIT_OP(RES, 7, D); break; // RES 7, D - case 0xBB: BIT_OP(RES, 7, E); break; // RES 7, E - case 0xBC: BIT_OP(RES, 7, H); break; // RES 7, H - case 0xBD: BIT_OP(RES, 7, L); break; // RES 7, L - case 0xBE: BIT_OP_IND(RES, 7, L, H); break; // RES 7, (HL) - case 0xBF: BIT_OP(RES, 7, A); break; // RES 7, A - case 0xC0: BIT_OP(SET, 0, B); break; // SET 0, B - case 0xC1: BIT_OP(SET, 0, C); break; // SET 0, C - case 0xC2: BIT_OP(SET, 0, D); break; // SET 0, D - case 0xC3: BIT_OP(SET, 0, E); break; // SET 0, E - case 0xC4: BIT_OP(SET, 0, H); break; // SET 0, H - case 0xC5: BIT_OP(SET, 0, L); break; // SET 0, L - case 0xC6: BIT_OP_IND(SET, 0, L, H); break; // SET 0, (HL) - case 0xC7: BIT_OP(SET, 0, A); break; // SET 0, A - case 0xC8: BIT_OP(SET, 1, B); break; // SET 1, B - case 0xC9: BIT_OP(SET, 1, C); break; // SET 1, C - case 0xCA: BIT_OP(SET, 1, D); break; // SET 1, D - case 0xCB: BIT_OP(SET, 1, E); break; // SET 1, E - case 0xCC: BIT_OP(SET, 1, H); break; // SET 1, H - case 0xCD: BIT_OP(SET, 1, L); break; // SET 1, L - case 0xCE: BIT_OP_IND(SET, 1, L, H); break; // SET 1, (HL) - case 0xCF: BIT_OP(SET, 1, A); break; // SET 1, A - case 0xD0: BIT_OP(SET, 2, B); break; // SET 2, B - case 0xD1: BIT_OP(SET, 2, C); break; // SET 2, C - case 0xD2: BIT_OP(SET, 2, D); break; // SET 2, D - case 0xD3: BIT_OP(SET, 2, E); break; // SET 2, E - case 0xD4: BIT_OP(SET, 2, H); break; // SET 2, H - case 0xD5: BIT_OP(SET, 2, L); break; // SET 2, L - case 0xD6: BIT_OP_IND(SET, 2, L, H); break; // SET 2, (HL) - case 0xD7: BIT_OP(SET, 2, A); break; // SET 2, A - case 0xD8: BIT_OP(SET, 3, B); break; // SET 3, B - case 0xD9: BIT_OP(SET, 3, C); break; // SET 3, C - case 0xDA: BIT_OP(SET, 3, D); break; // SET 3, D - case 0xDB: BIT_OP(SET, 3, E); break; // SET 3, E - case 0xDC: BIT_OP(SET, 3, H); break; // SET 3, H - case 0xDD: BIT_OP(SET, 3, L); break; // SET 3, L - case 0xDE: BIT_OP_IND(SET, 3, L, H); break; // SET 3, (HL) - case 0xDF: BIT_OP(SET, 3, A); break; // SET 3, A - case 0xE0: BIT_OP(SET, 4, B); break; // SET 4, B - case 0xE1: BIT_OP(SET, 4, C); break; // SET 4, C - case 0xE2: BIT_OP(SET, 4, D); break; // SET 4, D - case 0xE3: BIT_OP(SET, 4, E); break; // SET 4, E - case 0xE4: BIT_OP(SET, 4, H); break; // SET 4, H - case 0xE5: BIT_OP(SET, 4, L); break; // SET 4, L - case 0xE6: BIT_OP_IND(SET, 4, L, H); break; // SET 4, (HL) - case 0xE7: BIT_OP(SET, 4, A); break; // SET 4, A - case 0xE8: BIT_OP(SET, 5, B); break; // SET 5, B - case 0xE9: BIT_OP(SET, 5, C); break; // SET 5, C - case 0xEA: BIT_OP(SET, 5, D); break; // SET 5, D - case 0xEB: BIT_OP(SET, 5, E); break; // SET 5, E - case 0xEC: BIT_OP(SET, 5, H); break; // SET 5, H - case 0xED: BIT_OP(SET, 5, L); break; // SET 5, L - case 0xEE: BIT_OP_IND(SET, 5, L, H); break; // SET 5, (HL) - case 0xEF: BIT_OP(SET, 5, A); break; // SET 5, A - case 0xF0: BIT_OP(SET, 6, B); break; // SET 6, B - case 0xF1: BIT_OP(SET, 6, C); break; // SET 6, C - case 0xF2: BIT_OP(SET, 6, D); break; // SET 6, D - case 0xF3: BIT_OP(SET, 6, E); break; // SET 6, E - case 0xF4: BIT_OP(SET, 6, H); break; // SET 6, H - case 0xF5: BIT_OP(SET, 6, L); break; // SET 6, L - case 0xF6: BIT_OP_IND(SET, 6, L, H); break; // SET 6, (HL) - case 0xF7: BIT_OP(SET, 6, A); break; // SET 6, A - case 0xF8: BIT_OP(SET, 7, B); break; // SET 7, B - case 0xF9: BIT_OP(SET, 7, C); break; // SET 7, C - case 0xFA: BIT_OP(SET, 7, D); break; // SET 7, D - case 0xFB: BIT_OP(SET, 7, E); break; // SET 7, E - case 0xFC: BIT_OP(SET, 7, H); break; // SET 7, H - case 0xFD: BIT_OP(SET, 7, L); break; // SET 7, L - case 0xFE: BIT_OP_IND(SET, 7, L, H); break; // SET 7, (HL) - case 0xFF: BIT_OP(SET, 7, A); break; // SET 7, A - } - - for (int j = 0; j < 60; j++) - { - instr_table[256 * 60 + i * 60 + j] = cur_instr[j]; - } - } - - // other miscellaneous vectors - - // reset - instr_table[256 * 60 * 2] = IDLE; - instr_table[256 * 60 * 2 + 1] = IDLE; - instr_table[256 * 60 * 2 + 2] = HALT_CHK; - instr_table[256 * 60 * 2 + 3] = OP; - - // halt loop - instr_table[256 * 60 * 2 + 60] = IDLE; - instr_table[256 * 60 * 2 + 60 + 1] = IDLE; - instr_table[256 * 60 * 2 + 60 + 2] = IDLE; - instr_table[256 * 60 * 2 + 60 + 3] = OP; - - // skipped loop - instr_table[256 * 60 * 2 + 60 * 2] = IDLE; - instr_table[256 * 60 * 2 + 60 * 2 + 1] = IDLE; - instr_table[256 * 60 * 2 + 60 * 2 + 2] = IDLE; - instr_table[256 * 60 * 2 + 60 * 2 + 3] = HALT; - instr_table[256 * 60 * 2 + 60 * 2 + 4] = (uint32_t)0; - - // GBC Halt loop - instr_table[256 * 60 * 2 + 60 * 3] = IDLE; - instr_table[256 * 60 * 2 + 60 * 3 + 1] = IDLE; - instr_table[256 * 60 * 2 + 60 * 3 + 2] = HALT_CHK; - instr_table[256 * 60 * 2 + 60 * 3 + 3] = HALT; - instr_table[256 * 60 * 2 + 60 * 3 + 4] = (uint32_t)0; - - // spec Halt loop - instr_table[256 * 60 * 2 + 60 * 4] = HALT_CHK; - instr_table[256 * 60 * 2 + 60 * 4 + 1] = IDLE; - instr_table[256 * 60 * 2 + 60 * 4 + 2] = IDLE; - instr_table[256 * 60 * 2 + 60 * 4 + 3] = HALT; - instr_table[256 * 60 * 2 + 60 * 4 + 4] = (uint32_t)0; - - // Stop loop - instr_table[256 * 60 * 2 + 60 * 5] = IDLE; - instr_table[256 * 60 * 2 + 60 * 5 + 1] = IDLE; - instr_table[256 * 60 * 2 + 60 * 5 + 2] = IDLE; - instr_table[256 * 60 * 2 + 60 * 5 + 3] = STOP; - - // interrupt vectors - INTERRUPT_(); - - for (int i = 0; i < 60; i++) - { - instr_table[256 * 60 * 2 + 60 * 6 + i] = cur_instr[i]; - } - - INTERRUPT_GBC_NOP(); - - for (int i = 0; i < 60; i++) - { - instr_table[256 * 60 * 2 + 60 * 7 + i] = cur_instr[i]; - } - - } - - #pragma endregion - - #pragma region Operations - - inline void Read_Func(uint32_t dest, uint32_t src_l, uint32_t src_h) - { - uint32_t addr = (uint32_t)(Regs[src_l] | (Regs[src_h]) << 8); - //if (CDLCallback != null) - //{ - //if (src_l == PCl) CDLCallback(addr, eCDLogMemFlags.FetchOperand); - //else CDLCallback(addr, eCDLogMemFlags.Data); - //} - Regs[dest] = ReadMemory(addr); - } - - // special read for POP AF that always clears the lower 4 bits of F - inline void Read_Func_F(uint32_t dest, uint32_t src_l, uint32_t src_h) - { - Regs[dest] = (ReadMemory((uint32_t)(Regs[src_l] | (Regs[src_h]) << 8)) & 0xF0); - } - - inline void Write_Func(uint32_t dest_l, uint32_t dest_h, uint32_t src) - { - uint32_t addr = (uint32_t)(Regs[dest_l] | (Regs[dest_h]) << 8); - //CDLCallback ? .Invoke(addr, eCDLogMemFlags.Write | eCDLogMemFlags.Data); - WriteMemory(addr, Regs[src]); - } - - inline void TR_Func(uint32_t dest, uint32_t src) - { - Regs[dest] = Regs[src]; - } - - inline void ADD16_Func(uint32_t dest_l, uint32_t dest_h, uint32_t src_l, uint32_t src_h) - { - Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); - Reg16_s = Regs[src_l] | (Regs[src_h] << 8); - - Reg16_d += Reg16_s; - - FlagCset((Reg16_d & 0x10000) > 0); - - ans_l = (uint32_t)(Reg16_d & 0xFF); - ans_h = (uint32_t)((Reg16_d & 0xFF00) >> 8); - - // redo for half carry flag - Reg16_d = Regs[dest_l] | ((Regs[dest_h] & 0x0F) << 8); - Reg16_s = Regs[src_l] | ((Regs[src_h] & 0x0F) << 8); - - Reg16_d += Reg16_s; - - FlagHset((Reg16_d & 0x1000) > 0); - FlagNset(false); - - Regs[dest_l] = (uint8_t)ans_l; - Regs[dest_h] = (uint8_t)ans_h; - } - - inline void ADD8_Func(uint32_t dest, uint32_t src) - { - Reg16_d = Regs[dest]; - Reg16_d += Regs[src]; - - FlagCset((Reg16_d & 0x100) > 0); - FlagZset((Reg16_d & 0xFF) == 0); - - ans = (uint32_t)(Reg16_d & 0xFF); - - // redo for half carry flag - Reg16_d = Regs[dest] & 0xF; - Reg16_d += (Regs[src] & 0xF); - - FlagHset((Reg16_d & 0x10) > 0); - - FlagNset(false); - - Regs[dest] = (uint8_t)ans; - } - - inline void SUB8_Func(uint32_t dest, uint32_t src) - { - Reg16_d = Regs[dest]; - Reg16_d -= Regs[src]; - - FlagCset((Reg16_d & 0x100) > 0); - FlagZset((Reg16_d & 0xFF) == 0); - - ans = (uint32_t)(Reg16_d & 0xFF); - - // redo for half carry flag - Reg16_d = Regs[dest] & 0xF; - Reg16_d -= (Regs[src] & 0xF); - - FlagHset((Reg16_d & 0x10) > 0); - FlagNset(true); - - Regs[dest] = (uint8_t)ans; - } - - inline void BIT_Func(uint32_t bit, uint32_t src) - { - FlagZset(!((Regs[src] & (1 << bit)) > 0)); - FlagHset(true); - FlagNset(false); - } - - inline void SET_Func(uint32_t bit, uint32_t src) - { - Regs[src] |= (uint8_t)(1 << bit); - } - - inline void RES_Func(uint32_t bit, uint32_t src) - { - Regs[src] &= (uint8_t)(0xFF - (1 << bit)); - } - - inline void ASGN_Func(uint32_t src, uint32_t val) - { - Regs[src] = (uint8_t)val; - } - - inline void SWAP_Func(uint32_t src) - { - temp = (uint32_t)((Regs[src] << 4) & 0xF0); - Regs[src] = (uint8_t)(temp | (Regs[src] >> 4)); - - FlagZset(Regs[src] == 0); - FlagHset(false); - FlagNset(false); - FlagCset(false); - } - - inline void SLA_Func(uint32_t src) - { - FlagCset((Regs[src] & 0x80) > 0); - - Regs[src] = (uint8_t)((Regs[src] << 1) & 0xFF); - - FlagZset(Regs[src] == 0); - FlagHset(false); - FlagNset(false); - } - - inline void SRA_Func(uint32_t src) - { - FlagCset((Regs[src] & 1) > 0); - - temp = (uint32_t)(Regs[src] & 0x80); // MSB doesn't change in this operation - - Regs[src] = (uint8_t)((Regs[src] >> 1) | temp); - - FlagZset(Regs[src] == 0); - FlagHset(false); - FlagNset(false); - } - - inline void SRL_Func(uint32_t src) - { - FlagCset((Regs[src] & 1) > 0); - - Regs[src] = (uint8_t)(Regs[src] >> 1); - - FlagZset(Regs[src] == 0); - FlagHset(false); - FlagNset(false); - } - - inline void CPL_Func(uint32_t src) - { - Regs[src] = (uint8_t)((~Regs[src]) & 0xFF); - - FlagHset(true); - FlagNset(true); - } - - inline void CCF_Func(uint32_t src) - { - FlagCset(!FlagCget()); - FlagHset(false); - FlagNset(false); - } - - inline void SCF_Func(uint32_t src) - { - FlagCset(true); - FlagHset(false); - FlagNset(false); - } - - inline void AND8_Func(uint32_t dest, uint32_t src) - { - Regs[dest] = (uint8_t)(Regs[dest] & Regs[src]); - - FlagZset(Regs[dest] == 0); - FlagCset(false); - FlagHset(true); - FlagNset(false); - } - - inline void OR8_Func(uint32_t dest, uint32_t src) - { - Regs[dest] = (uint8_t)(Regs[dest] | Regs[src]); - - FlagZset(Regs[dest] == 0); - FlagCset(false); - FlagHset(false); - FlagNset(false); - } - - inline void XOR8_Func(uint32_t dest, uint32_t src) - { - Regs[dest] = (uint8_t)(Regs[dest] ^ Regs[src]); - - FlagZset(Regs[dest] == 0); - FlagCset(false); - FlagHset(false); - FlagNset(false); - } - - inline void CP8_Func(uint32_t dest, uint32_t src) - { - Reg16_d = Regs[dest]; - Reg16_d -= Regs[src]; - - FlagCset((Reg16_d & 0x100) > 0); - FlagZset((Reg16_d & 0xFF) == 0); - - // redo for half carry flag - Reg16_d = Regs[dest] & 0xF; - Reg16_d -= (Regs[src] & 0xF); - - FlagHset((Reg16_d & 0x10) > 0); - - FlagNset(true); - } - - inline void RRC_Func(uint32_t src) - { - imm = src == Aim; - if (imm) { src = A; } - - FlagCset((Regs[src] & 1) > 0); - - Regs[src] = (uint8_t)((FlagCget() ? 0x80 : 0) | (Regs[src] >> 1)); - - FlagZset(imm ? false : (Regs[src] == 0)); - FlagHset(false); - FlagNset(false); - } - - inline void RR_Func(uint32_t src) - { - imm = src == Aim; - if (imm) { src = A; } - - c = FlagCget() ? 0x80 : 0; - - FlagCset((Regs[src] & 1) > 0); - - Regs[src] = (uint8_t)(c | (Regs[src] >> 1)); - - FlagZset(imm ? false : (Regs[src] == 0)); - FlagHset(false); - FlagNset(false); - } - - inline void RLC_Func(uint32_t src) - { - imm = src == Aim; - if (imm) { src = A; } - - c = (Regs[src] & 0x80) > 0 ? 1 : 0; - FlagCset((Regs[src] & 0x80) > 0); - - Regs[src] = (uint8_t)(((Regs[src] << 1) & 0xFF) | c); - - FlagZset(imm ? false : (Regs[src] == 0)); - FlagHset(false); - FlagNset(false); - } - - inline void RL_Func(uint32_t src) - { - imm = src == Aim; - if (imm) { src = A; } - - c = FlagCget() ? 1 : 0; - FlagCset((Regs[src] & 0x80) > 0); - - Regs[src] = (uint8_t)(((Regs[src] << 1) & 0xFF) | c); - - FlagZset(imm ? false : (Regs[src] == 0)); - FlagHset(false); - FlagNset(false); - } - - inline void INC8_Func(uint32_t src) - { - Reg16_d = Regs[src]; - Reg16_d += 1; - - FlagZset((Reg16_d & 0xFF) == 0); - - ans = (uint32_t)(Reg16_d & 0xFF); - - // redo for half carry flag - Reg16_d = Regs[src] & 0xF; - Reg16_d += 1; - - FlagHset((Reg16_d & 0x10) > 0); - FlagNset(false); - - Regs[src] = (uint8_t)ans; - } - - inline void DEC8_Func(uint32_t src) - { - Reg16_d = Regs[src]; - Reg16_d -= 1; - - FlagZset((Reg16_d & 0xFF) == 0); - - ans = (uint32_t)(Reg16_d & 0xFF); - - // redo for half carry flag - Reg16_d = Regs[src] & 0xF; - Reg16_d -= 1; - - FlagHset((Reg16_d & 0x10) > 0); - FlagNset(true); - - Regs[src] = (uint8_t)ans; - } - - inline void INC16_Func(uint32_t src_l, uint32_t src_h) - { - Reg16_d = Regs[src_l] | (Regs[src_h] << 8); - - Reg16_d += 1; - - Regs[src_l] = (uint8_t)(Reg16_d & 0xFF); - Regs[src_h] = (uint8_t)((Reg16_d & 0xFF00) >> 8); - } - - inline void DEC16_Func(uint32_t src_l, uint32_t src_h) - { - Reg16_d = Regs[src_l] | (Regs[src_h] << 8); - - Reg16_d -= 1; - - Regs[src_l] = (uint8_t)(Reg16_d & 0xFF); - Regs[src_h] = (uint8_t)((Reg16_d & 0xFF00) >> 8); - } - - inline void ADC8_Func(uint32_t dest, uint32_t src) - { - Reg16_d = Regs[dest]; - c = FlagCget() ? 1 : 0; - - Reg16_d += (Regs[src] + c); - - FlagCset((Reg16_d & 0x100) > 0); - FlagZset((Reg16_d & 0xFF) == 0); - - ans = (uint32_t)(Reg16_d & 0xFF); - - // redo for half carry flag - Reg16_d = Regs[dest] & 0xF; - Reg16_d += ((Regs[src] & 0xF) + c); - - FlagHset((Reg16_d & 0x10) > 0); - FlagNset(false); - - Regs[dest] = (uint8_t)ans; - } - - inline void SBC8_Func(uint32_t dest, uint32_t src) - { - Reg16_d = Regs[dest]; - c = FlagCget() ? 1 : 0; - - Reg16_d -= (Regs[src] + c); - - FlagCset((Reg16_d & 0x100) > 0); - FlagZset((Reg16_d & 0xFF) == 0); - - ans = (uint32_t)(Reg16_d & 0xFF); - - // redo for half carry flag - Reg16_d = Regs[dest] & 0xF; - Reg16_d -= ((Regs[src] & 0xF) + c); - - FlagHset((Reg16_d & 0x10) > 0); - FlagNset(true); - - Regs[dest] = (uint8_t)ans; - } - - // DA code courtesy of AWJ: http://forums.nesdev.com/viewtopic.php?f=20&t=15944 - inline void DA_Func(uint32_t src) - { - a_d = (uint8_t)Regs[src]; - - if (!FlagNget()) - { // after an addition, adjust if (half-)carry occurred or if result is out of bounds - if (FlagCget() || a_d > 0x99) { a_d += 0x60; FlagCset(true); } - if (FlagHget() || (a_d & 0x0f) > 0x09) { a_d += 0x6; } - } - else - { // after a subtraction, only adjust if (half-)carry occurred - if (FlagCget()) { a_d -= 0x60; } - if (FlagHget()) { a_d -= 0x6; } - } - - a_d &= 0xFF; - - Regs[src] = (uint8_t)a_d; - - FlagZset(a_d == 0); - FlagHset(false); - } - - // used for signed operations - inline void ADDS_Func(uint32_t dest_l, uint32_t dest_h, uint32_t src_l, uint32_t src_h) - { - Reg16_d = Regs[dest_l]; - Reg16_s = Regs[src_l]; - - Reg16_d += Reg16_s; - - temp = 0; - - // since this is signed addition, calculate the high byte carry appropriately - if ((Reg16_s & 0x80) > 0) - { - if (((Reg16_d & 0xFF) >= Regs[dest_l])) - { - temp = 0xFF; - } - else - { - temp = 0; - } - } - else - { - temp = (uint32_t)(((Reg16_d & 0x100) > 0) ? 1 : 0); - } - - ans_l = (uint32_t)(Reg16_d & 0xFF); - - // JR operations do not effect flags - if (dest_l != PCl) - { - FlagCset((Reg16_d & 0x100) > 0); - - // redo for half carry flag - Reg16_d = Regs[dest_l] & 0xF; - Reg16_d += Regs[src_l] & 0xF; - - FlagHset((Reg16_d & 0x10) > 0); - FlagNset(false); - FlagZset(false); - } - - Regs[dest_l] = (uint8_t)ans_l; - Regs[dest_h] += (uint8_t)temp; - Regs[dest_h] &= (uint8_t)0xFF; - - } - - #pragma endregion - - #pragma region Disassemble - - // disassemblies will also return strings of the same length - const char* TraceHeader = "LR35902: PC, machine code, mnemonic, operands, registers (A, F, B, C, D, E, H, L, SP), Cy, flags(ZNHCIE)"; - const char* Un_halt_event = " ==Un-halted== "; - const char* IRQ_event = " ====IRQ==== "; - const char* Un_stop_event = " ==Un-stopped== "; - const char* No_Reg = " "; - const char* Reg_template = "A:AA F:FF B:BB C:CC D:DD E:EE H:HH L:LL SP:SPSP Cy:FEDCBA9876543210 LY:LLY ZNHCIE"; - const char* Disasm_template = "PCPC: AA BB CC DD Di Di, XXXXX "; - - char replacer[32] = {}; - char* val_char_1 = nullptr; - char* val_char_2 = nullptr; - int temp_reg; - - - void (*TraceCallback)(int); - - string CPURegisterState() - { - val_char_1 = replacer; - - string reg_state = "A:"; - sprintf_s(val_char_1, 5, "%02X", Regs[A]); - reg_state.append(val_char_1, 2); - - reg_state.append(" F:"); - sprintf_s(val_char_1, 5, "%02X", Regs[F]); - reg_state.append(val_char_1, 2); - - reg_state.append(" B:"); - sprintf_s(val_char_1, 5, "%02X", Regs[B]); - reg_state.append(val_char_1, 2); - - reg_state.append(" C:"); - sprintf_s(val_char_1, 5, "%02X", Regs[C]); - reg_state.append(val_char_1, 2); - - reg_state.append(" D:"); - sprintf_s(val_char_1, 5, "%02X", Regs[D]); - reg_state.append(val_char_1, 2); - - reg_state.append(" E:"); - sprintf_s(val_char_1, 5, "%02X", Regs[E]); - reg_state.append(val_char_1, 2); - - reg_state.append(" H:"); - sprintf_s(val_char_1, 5, "%02X", Regs[H]); - reg_state.append(val_char_1, 2); - - reg_state.append(" L:"); - sprintf_s(val_char_1, 5, "%02X", Regs[L]); - reg_state.append(val_char_1, 2); - - reg_state.append(" SP:"); - temp_reg = (Regs[SPh] << 8) + Regs[SPl]; - sprintf_s(val_char_1, 5, "%04X", temp_reg); - reg_state.append(val_char_1, 4); - - reg_state.append(" Cy:"); - reg_state.append(val_char_1, sprintf_s(val_char_1, 32, "%16u", (unsigned long)TotalExecutedCycles)); - reg_state.append(" "); - - reg_state.append(" LY:"); - reg_state.append(val_char_1, sprintf_s(val_char_1, 32, "%3u", LY)); - reg_state.append(" "); - - reg_state.append(FlagCget() ? "C" : "c"); - reg_state.append(FlagNget() ? "N" : "n"); - reg_state.append(FlagHget() ? "H" : "h"); - reg_state.append(FlagZget() ? "Z" : "z"); - reg_state.append(FlagI ? "I" : "i"); - reg_state.append(interrupts_enabled ? "E" : "e"); - - return reg_state; - } - - string CPUDisassembly() - { - uint32_t bytes_read = 0; - - uint32_t* bytes_read_ptr = &bytes_read; - - string disasm = Disassemble(RegPCget(), bytes_read_ptr); - string byte_code = ""; - - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%04X", RegPCget() & 0xFFFF); - byte_code.append(val_char_1, 4); - byte_code.append(": "); - - uint32_t i = 0; - - for (i = 0; i < bytes_read; i++) - { - char* val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%02X", PeekMemory((RegPCget() + i) & 0xFFFF)); - string val1(val_char_1, 2); - - byte_code.append(val1); - byte_code.append(" "); - } - - while (i < 4) - { - byte_code.append(" "); - i++; - } - - byte_code.append(" "); - - byte_code.append(disasm); - - while (byte_code.length() < 48) - { - byte_code.append(" "); - } - - return byte_code; - } - - string Result(string format, uint32_t* addr) - { - //d immediately succeeds the opcode - //n immediate succeeds the opcode and the displacement (if present) - //nn immediately succeeds the opcode and the displacement (if present) - - if (format.find("a16") != string::npos) - { - size_t str_loc = format.find("a16"); - - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%02X", PeekMemory(addr[0] & 0xFFFF)); - string val1(val_char_1, 2); - addr[0]++; - - val_char_2 = replacer; - sprintf_s(val_char_2, 5, "%02X", PeekMemory(addr[0] & 0xFFFF)); - string val2(val_char_2, 2); - addr[0]++; - - format.erase(str_loc, 3); - format.insert(str_loc, val1); - format.insert(str_loc, val2); - } - - if (format.find("d16") != string::npos) - { - size_t str_loc = format.find("d16"); - - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%02X", PeekMemory(addr[0] & 0xFFFF)); - string val1(val_char_1, 2); - addr[0]++; - - val_char_2 = replacer; - sprintf_s(val_char_2, 5, "%02X", PeekMemory(addr[0] & 0xFFFF)); - string val2(val_char_2, 2); - addr[0]++; - - format.erase(str_loc, 3); - format.insert(str_loc, val1); - format.insert(str_loc, val2); - } - - if (format.find("d8") != string::npos) - { - size_t str_loc = format.find("d8"); - - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%02X", PeekMemory(addr[0] & 0xFFFF)); - string val1(val_char_1, 2); - addr[0]++; - - format.erase(str_loc, 2); - format.insert(str_loc, val1); - } - - if (format.find("a8") != string::npos) - { - size_t str_loc = format.find("a8"); - - val_char_2 = replacer; - sprintf_s(val_char_1, 5, "%02X", PeekMemory(addr[0] & 0xFFFF)); - string val1(val_char_1, 2); - addr[0]++; - - string val2 = "FF"; - - format.erase(str_loc, 2); - format.insert(str_loc, val1); - format.insert(str_loc, val2); - } - - if (format.find("r8") != string::npos) - { - size_t str_loc = format.find("r8"); - - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%04X", ((addr[0] + 1) + (int8_t)PeekMemory(addr[0] & 0xFFFF)) & 0xFFFF); - string val1(val_char_1, 4); - addr[0]++; - - format.erase(str_loc, 2); - format.insert(str_loc, val1); - } - - return format; - } - - string Disassemble(uint32_t addr, uint32_t* size) - { - uint32_t start_addr = addr; - uint32_t extra_inc = 0; - - uint32_t A = PeekMemory(addr & 0xFFFF); - addr++; - string format; - switch (A) - { - case 0xCB: - A = PeekMemory(addr & 0xFFFF); - addr++; - format = mnemonics[A + 256]; - break; - - default: format = mnemonics[A]; break; - } - - uint32_t* addr_ptr = &addr; - string temp = Result(format, addr_ptr); - - addr += extra_inc; - - size[0] = addr - start_addr; - // handle case of addr wrapping around at 16 bit boundary - if (addr < start_addr) - { - size[0] = (0x10000 + addr) - start_addr; - } - - return temp; - } - - /* - string Disassemble(MemoryDomain m, uuint32_t addr, out uint32_t length) - { - string ret = Disassemble((uint32_t)addr, a = > m.PeekByte(a), out length); - return ret; - } - */ - - const string mnemonics[512] = - { - "NOP", "LD BC,d16", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,d8", "RLCA", // 00 - "LD (a16),SP", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,d8", "RRCA", // 08 - "STOP 0", "LD DE,d16", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,d8", "RLA", // 10 - "JR r8", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,d8", "RRA", // 18 - "JR NZ,r8", "LD HL,d16", "LD (HL+),A", "INC HL", "INC H", "DEC H", "LD H,d8", "DAA", // 20 - "JR Z,r8", "ADD HL,HL", "LD A,(HL+)", "DEC HL", "INC L", "DEC L", "LD L,d8", "CPL", // 28 - "JR NC,r8", "LD SP,d16", "LD (HL-),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),d8", "SCF", // 30 - "JR C,r8", "ADD HL,SP", "LD A,(HL-)", "DEC SP", "INC A", "DEC A", "LD A,d8", "CCF", // 38 - "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A", // 40 - "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A", // 48 - "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A", // 50 - "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A", // 58 - "LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A", // 60 - "LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A", // 68 - "LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A", // 70 - "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A", // 78 - "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,H", "ADD A,L", "ADD A,(HL)", "ADD A,A", // 80 - "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,H", "ADC A,L", "ADC A,(HL)", "ADC A,A", // 88 - "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", // 90 - "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,H", "SBC A,L", "SBC A,(HL)", "SBC A,A", // 98 - "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", // A0 - "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", // A8 - "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", // B0 - "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", // B8 - "RET NZ", "POP BC", "JP NZ,a16", "JP a16", "CALL NZ,a16", "PUSH BC", "ADD A,d8", "RST 00H", // C0 - "RET Z", "RET", "JP Z,a16", "PREFIX CB", "CALL Z,a16", "CALL a16", "ADC A,d8", "RST 08H", // C8 - "RET NC", "POP DE", "JP NC,a16", "???", "CALL NC,a16", "PUSH DE", "SUB d8", "RST 10H", // D0 - "RET C", "RETI", "JP C,a16", "???", "CALL C,a16", "???", "SBC A,d8", "RST 18H", // D8 - "LDH (a8),A", "POP HL", "LD (C),A", "???", "???", "PUSH HL", "AND d8", "RST 20H", // E0 - "ADD SP,r8", "JP (HL)", "LD (a16),A", "???", "???", "???", "XOR d8", "RST 28H", // E8 - "LDH A,(a8)", "POP AF", "LD A,(C)", "DI", "???", "PUSH AF", "OR d8", "RST 30H", // F0 - "LD HL,SP+r8", "LD SP,HL", "LD A,(a16)", "EI ", "???", "???", "CP d8", "RST 38H", // F8 - - "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", // 00 - "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", // 08 - "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", // 10 - "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", // 18 - "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", // 20 - "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", // 28 - "SWAP B", "SWAP C", "SWAP D", "SWAP E", "SWAP H", "SWAP L", "SWAP (HL)", "SWAP A", // 30 - "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", // 38 - "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", // 40 - "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", // 48 - "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", // 50 - "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", // 58 - "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", // 60 - "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", // 68 - "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", // 70 - "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", // 78 - "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", // 80 - "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", // 88 - "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", // 90 - "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", // 98 - "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", // A0 - "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", // A8 - "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", // B0 - "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", // B8 - "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", // C0 - "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", // C8 - "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", // D0 - "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", // d8 - "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", // e0 - "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", // E8 - "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", // F0 - "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A", // F8 - }; - - #pragma endregion - - #pragma region State Save / Load - - uint8_t* SaveState(uint8_t* saver) - { - - *saver = (uint8_t)(interrupts_enabled ? 1 : 0); saver++; - *saver = (uint8_t)(CB_prefix ? 1 : 0); saver++; - *saver = (uint8_t)(halted ? 1 : 0); saver++; - *saver = (uint8_t)(stopped ? 1 : 0); saver++; - *saver = (uint8_t)(jammed ? 1 : 0); saver++; - *saver = (uint8_t)(was_FlagI ? 1 : 0); saver++; - *saver = (uint8_t)(FlagI ? 1 : 0); saver++; - - *saver = opcode; saver++; - *saver = LY; saver++; - *saver = EI_pending; saver++; - - for (int i = 0; i < 14; i++) { *saver = Regs[i]; saver++; } - - *saver = (uint8_t)(instr_pntr & 0xFF); saver++; *saver = (uint8_t)((instr_pntr >> 8) & 0xFF); saver++; - *saver = (uint8_t)((instr_pntr >> 16) & 0xFF); saver++; *saver = (uint8_t)((instr_pntr >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(TotalExecutedCycles & 0xFF); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 8) & 0xFF); saver++; - *saver = (uint8_t)((TotalExecutedCycles >> 16) & 0xFF); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 24) & 0xFF); saver++; - *saver = (uint8_t)((TotalExecutedCycles >> 32) & 0xFF); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 40) & 0xFF); saver++; - *saver = (uint8_t)((TotalExecutedCycles >> 48) & 0xFF); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 56) & 0xFF); saver++; - - return saver; - } - - uint8_t* LoadState(uint8_t* loader) - { - interrupts_enabled = *loader == 1; loader++; - CB_prefix = *loader == 1; loader++; - halted = *loader == 1; loader++; - stopped = *loader == 1; loader++; - jammed = *loader == 1; loader++; - was_FlagI = *loader == 1; loader++; - FlagI = *loader == 1; loader++; - - opcode = *loader; loader++; - LY = *loader; loader++; - EI_pending = *loader; loader++; - - for (int i = 0; i < 14; i++) { Regs[i] = *loader; loader++; } - - instr_pntr = *loader; loader++; instr_pntr |= (*loader << 8); loader++; - instr_pntr |= (*loader << 16); loader++; instr_pntr |= (*loader << 24); loader++; - - TotalExecutedCycles = *loader; loader++; TotalExecutedCycles |= ((uint64_t)*loader << 8); loader++; - TotalExecutedCycles |= ((uint64_t)*loader << 16); loader++; TotalExecutedCycles |= ((uint64_t)*loader << 24); loader++; - TotalExecutedCycles |= ((uint64_t)*loader << 32); loader++; TotalExecutedCycles |= ((uint64_t)*loader << 40); loader++; - TotalExecutedCycles |= ((uint64_t)*loader << 48); loader++; TotalExecutedCycles |= ((uint64_t)*loader << 56); loader++; - - return loader; - } - - #pragma endregion - }; -} diff --git a/libHawk/GBHawk/GBHawk/Mappers.h b/libHawk/GBHawk/GBHawk/Mappers.h deleted file mode 100644 index 6aeadcb6ea..0000000000 --- a/libHawk/GBHawk/GBHawk/Mappers.h +++ /dev/null @@ -1,3190 +0,0 @@ -#include -#include -#include -#include - -using namespace std; - -namespace GBHawk -{ - class Mapper - { - public: - #pragma region mapper base - - Mapper() - { - - } - - uint8_t* ROM = nullptr; - uint8_t* Cart_RAM = nullptr; - uint32_t* ROM_Length = nullptr; - uint32_t* Cart_RAM_Length = nullptr; - uint32_t* addr_access = nullptr; - uint32_t* Acc_X_state = nullptr; - uint32_t* Acc_Y_state = nullptr; - - // Generic Mapper Variables - bool RAM_enable; - bool sel_mode; - bool IR_signal; - uint32_t ROM_bank; - uint32_t RAM_bank; - uint32_t ROM_mask; - uint32_t RAM_mask; - - // Common - bool halt; - uint32_t RTC_timer; - uint32_t RTC_low_clock; - - // HuC3 - bool timer_read; - uint8_t control; - uint8_t chip_read; - uint32_t time_val_shift; - uint32_t time; - uint32_t RTC_seconds; - - // MBC3 - uint8_t RTC_regs[5] = {}; - uint8_t RTC_regs_latch[5] = {}; - bool RTC_regs_latch_wr; - uint32_t RTC_offset; - - // camera - bool regs_enable; - uint8_t regs_cam[0x80] = {}; - - // sachen - bool locked, locked_GBC, finished, reg_access; - uint32_t ROM_bank_mask; - uint32_t BASE_ROM_Bank; - uint32_t addr_last; - uint32_t counter; - - // TAMA5 - uint8_t RTC_regs_TAMA[10] = {}; - uint32_t ctrl; - uint32_t RAM_addr_low; - uint32_t RAM_addr_high; - uint32_t RAM_val_low; - uint32_t RAM_val_high; - uint8_t Chip_return_low; - uint8_t Chip_return_high; - - // MBC7 - bool RAM_enable_1, RAM_enable_2, is_erased; - uint8_t acc_x_low; - uint8_t acc_x_high; - uint8_t acc_y_low; - uint8_t acc_y_high; - // EEPROM related - bool CS_prev; - bool CLK_prev; - bool DI_prev; - bool DO; - bool instr_read; - bool perf_instr; - bool WR_EN; - bool countdown_start; - uint32_t instr_bit_counter; - uint32_t instr; - uint32_t EE_addr; - uint32_t instr_case; - uint32_t instr_clocks; - uint32_t EE_value; - uint32_t countdown; - - - - virtual uint8_t ReadMemory(uint32_t addr) - { - return 0; - } - - virtual uint8_t PeekMemory(uint32_t addr) - { - return 0; - } - - virtual void WriteMemory(uint32_t addr, uint8_t value) - { - } - - virtual void PokeMemory(uint32_t addr, uint8_t value) - { - } - - - virtual void Dispose() - { - } - - virtual void Reset() - { - } - - virtual void Mapper_Tick() - { - } - - virtual void RTC_Get(int value, int index) - { - } - /* - virtual void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - } - - protected void SetCDLROM(LR35902.eCDLogMemFlags flags, int cdladdr) - { - Core.SetCDL(flags, "ROM", cdladdr); - } - - protected void SetCDLRAM(LR35902.eCDLogMemFlags flags, int cdladdr) - { - Core.SetCDL(flags, "CartRAM", cdladdr); - } - */ - #pragma endregion - - #pragma region State Save / Load - - uint8_t* SaveState(uint8_t* saver) - { - saver = bool_saver(RAM_enable, saver); - saver = bool_saver(sel_mode, saver); - saver = bool_saver(IR_signal, saver); - saver = int_saver(ROM_bank, saver); - saver = int_saver(RAM_bank, saver); - saver = int_saver(ROM_mask, saver); - saver = int_saver(RAM_mask, saver); - - saver = bool_saver(halt, saver); - saver = int_saver(RTC_timer, saver); - saver = int_saver(RTC_low_clock, saver); - - saver = bool_saver(timer_read, saver); - saver = byte_saver(control, saver); - saver = byte_saver(chip_read, saver); - saver = int_saver(time_val_shift, saver); - saver = int_saver(time, saver); - saver = int_saver(RTC_seconds, saver); - - for (int i = 0; i < 5; i++) { saver = byte_saver(RTC_regs[i], saver); } - for (int i = 0; i < 5; i++) { saver = byte_saver(RTC_regs_latch[i], saver); } - saver = bool_saver(RTC_regs_latch_wr, saver); - saver = int_saver(RTC_offset, saver); - - saver = bool_saver(regs_enable, saver); - for (int i = 0; i < 5; i++) { saver = byte_saver(regs_cam[i], saver); } - - saver = bool_saver(locked, saver); - saver = bool_saver(locked_GBC, saver); - saver = bool_saver(finished, saver); - saver = bool_saver(reg_access, saver); - saver = int_saver(ROM_bank_mask, saver); - saver = int_saver(BASE_ROM_Bank, saver); - saver = int_saver(addr_last, saver); - saver = int_saver(counter, saver); - - for (int i = 0; i < 10; i++) { saver = byte_saver(RTC_regs_TAMA[i], saver); } - saver = byte_saver(Chip_return_low, saver); - saver = byte_saver(Chip_return_high, saver); - saver = int_saver(ctrl, saver); - saver = int_saver(RAM_addr_low, saver); - saver = int_saver(RAM_addr_high, saver); - saver = int_saver(RAM_val_low, saver); - saver = int_saver(RAM_val_high, saver); - - saver = bool_saver(RAM_enable_1, saver); - saver = bool_saver(RAM_enable_2, saver); - saver = bool_saver(is_erased, saver); - saver = byte_saver(acc_x_low, saver); - saver = byte_saver(acc_x_high, saver); - saver = byte_saver(acc_y_low, saver); - saver = byte_saver(acc_y_high, saver); - // EEPROM related - saver = bool_saver(CS_prev, saver); - saver = bool_saver(CLK_prev, saver); - saver = bool_saver(DI_prev, saver); - saver = bool_saver(DO, saver); - saver = bool_saver(instr_read, saver); - saver = bool_saver(perf_instr, saver); - saver = bool_saver(WR_EN, saver); - saver = bool_saver(countdown_start, saver); - saver = int_saver(instr_bit_counter, saver); - saver = int_saver(instr, saver); - saver = int_saver(EE_addr, saver); - saver = int_saver(instr_case, saver); - saver = int_saver(instr_clocks, saver); - saver = int_saver(EE_value, saver); - saver = int_saver(countdown, saver); - - return saver; - } - - uint8_t* LoadState(uint8_t* loader) - { - loader = bool_loader(&RAM_enable, loader); - loader = bool_loader(&sel_mode, loader); - loader = bool_loader(&IR_signal, loader); - loader = int_loader(&ROM_bank, loader); - loader = int_loader(&RAM_bank, loader); - loader = int_loader(&ROM_mask, loader); - loader = int_loader(&RAM_mask, loader); - - loader = bool_loader(&halt, loader); - loader = int_loader(&RTC_timer, loader); - loader = int_loader(&RTC_low_clock, loader); - - loader = bool_loader(&timer_read, loader); - loader = byte_loader(&control, loader); - loader = byte_loader(&chip_read, loader); - loader = int_loader(&time_val_shift, loader); - loader = int_loader(&time, loader); - loader = int_loader(&RTC_seconds, loader); - - for (int i = 0; i < 5; i++) { loader = byte_loader(&RTC_regs[i], loader); } - for (int i = 0; i < 5; i++) { loader = byte_loader(&RTC_regs_latch[i], loader); } - loader = bool_loader(&RTC_regs_latch_wr, loader); - loader = int_loader(&RTC_offset, loader); - - loader = bool_loader(®s_enable, loader); - for (int i = 0; i < 5; i++) { loader = byte_loader(®s_cam[i], loader); } - - loader = bool_loader(&locked, loader); - loader = bool_loader(&locked_GBC, loader); - loader = bool_loader(&finished, loader); - loader = bool_loader(®_access, loader); - loader = int_loader(&ROM_bank_mask, loader); - loader = int_loader(&BASE_ROM_Bank, loader); - loader = int_loader(&addr_last, loader); - loader = int_loader(&counter, loader); - - for (int i = 0; i < 10; i++) { loader = byte_loader(&RTC_regs_TAMA[i], loader); } - loader = byte_loader(&Chip_return_low, loader); - loader = byte_loader(&Chip_return_high, loader); - loader = int_loader(&ctrl, loader); - loader = int_loader(&RAM_addr_low, loader); - loader = int_loader(&RAM_addr_high, loader); - loader = int_loader(&RAM_val_low, loader); - loader = int_loader(&RAM_val_high, loader); - - loader = bool_loader(&RAM_enable_1, loader); - loader = bool_loader(&RAM_enable_2, loader); - loader = bool_loader(&is_erased, loader); - loader = byte_loader(&acc_x_low, loader); - loader = byte_loader(&acc_x_high, loader); - loader = byte_loader(&acc_y_low, loader); - loader = byte_loader(&acc_y_high, loader); - // EEPROM related - loader = bool_loader(&CS_prev, loader); - loader = bool_loader(&CLK_prev, loader); - loader = bool_loader(&DI_prev, loader); - loader = bool_loader(&DO, loader); - loader = bool_loader(&instr_read, loader); - loader = bool_loader(&perf_instr, loader); - loader = bool_loader(&WR_EN, loader); - loader = bool_loader(&countdown_start, loader); - loader = int_loader(&instr_bit_counter, loader); - loader = int_loader(&instr, loader); - loader = int_loader(&EE_addr, loader); - loader = int_loader(&instr_case, loader); - loader = int_loader(&instr_clocks, loader); - loader = int_loader(&EE_value, loader); - loader = int_loader(&countdown, loader); - - return loader; - } - - uint8_t* bool_saver(bool to_save, uint8_t* saver) - { - *saver = (uint8_t)(to_save ? 1 : 0); saver++; - - return saver; - } - - uint8_t* byte_saver(uint8_t to_save, uint8_t* saver) - { - *saver = to_save; saver++; - - return saver; - } - - uint8_t* int_saver(uint32_t to_save, uint8_t* saver) - { - *saver = (uint8_t)(to_save & 0xFF); saver++; *saver = (uint8_t)((to_save >> 8) & 0xFF); saver++; - *saver = (uint8_t)((to_save >> 16) & 0xFF); saver++; *saver = (uint8_t)((to_save >> 24) & 0xFF); saver++; - - return saver; - } - - uint8_t* bool_loader(bool* to_load, uint8_t* loader) - { - to_load[0] = *to_load == 1; loader++; - - return loader; - } - - uint8_t* byte_loader(uint8_t* to_load, uint8_t* loader) - { - to_load[0] = *loader; loader++; - - return loader; - } - - uint8_t* int_loader(uint32_t* to_load, uint8_t* loader) - { - to_load[0] = *loader; loader++; to_load[0] |= (*loader << 8); loader++; - to_load[0] |= (*loader << 16); loader++; to_load[0] |= (*loader << 24); loader++; - - return loader; - } - - #pragma endregion - - }; - - #pragma region Camera - - class Mapper_Camera : public Mapper - { - public: - - void Reset() - { - ROM_bank = 1; - RAM_bank = 0; - RAM_enable = false; - ROM_mask = ROM_Length[0] / 0x4000 - 1; - - RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1; - - regs_enable = false; - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - return ROM[addr]; - } - else if (addr < 0x8000) - { - return ROM[(addr - 0x4000) + ROM_bank * 0x4000]; - } - else - { - if (regs_enable) - { - if ((addr & 0x7F) == 0) - { - return 0;// regs[0]; - } - else - { - return 0; - } - } - else - { - if (/*RAM_enable && */(((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])) - { - return Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; - } - else - { - return 0xFF; - } - } - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - // lowest bank is fixed, but is still effected by mode - SetCDLROM(flags, addr); - } - else if (addr < 0x8000) - { - SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); - } - else - { - if (!regs_enable) - { - if ((((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])) - { - SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); - } - else - { - return; - } - } - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x8000) - { - if (addr < 0x2000) - { - RAM_enable = (value & 0xF) == 0xA; - } - else if (addr < 0x4000) - { - ROM_bank = value; - ROM_bank &= ROM_mask; - //Console.WriteLine(addr + " " + value + " " + ROM_mask + " " + ROM_bank); - } - else if (addr < 0x6000) - { - if ((value & 0x10) == 0x10) - { - regs_enable = true; - } - else - { - regs_enable = false; - RAM_bank = value & RAM_mask; - } - } - } - else - { - if (regs_enable) - { - regs_cam[(addr & 0x7F)] = (uint8_t)(value & 0x7); - } - else - { - if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])) - { - Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; - } - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - }; - - #pragma endregion - - #pragma region Default - - class Mapper_Default : public Mapper - { - public: - - void Reset() - { - // nothing to initialize - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x8000) - { - return ROM[addr]; - } - else - { - if (Cart_RAM_Length > 0) - { - return Cart_RAM[addr - 0xA000]; - } - else - { - return 0; - } - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x8000) - { - SetCDLROM(flags, addr); - } - else - { - if (Cart_RAM != null) - { - SetCDLRAM(flags, addr - 0xA000); - } - else - { - return; - } - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x8000) - { - // no mapping hardware available - } - else - { - if (Cart_RAM_Length > 0) - { - Cart_RAM[addr - 0xA000] = value; - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - }; - - #pragma endregion - - #pragma region HuC1 - - class Mapper_HuC1 : public Mapper - { - public: - - void Reset() - { - ROM_bank = 0; - RAM_bank = 0; - RAM_enable = false; - ROM_mask = ROM_Length[0] / 0x4000 - 1; - - // some games have sizes that result in a degenerate ROM, account for it here - if (ROM_mask > 4) { ROM_mask |= 3; } - - RAM_mask = 0; - if (Cart_RAM_Length[0] > 0) - { - RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1; - if (Cart_RAM_Length[0] == 0x800) { RAM_mask = 0; } - } - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - return ROM[addr]; - } - else if (addr < 0x8000) - { - return ROM[(addr - 0x4000) + ROM_bank * 0x4000]; - } - else if ((addr >= 0xA000) && (addr < 0xC000)) - { - if (RAM_enable) - { - if (Cart_RAM_Length[0] > 0) - { - if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]) - { - return Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; - } - else - { - return 0xFF; - } - } - else - { - return 0xFF; - } - } - else - { - // when RAM isn't enabled, reading from this area will return IR sensor reading - // for now we'll assume it never sees light (0xC0) - return 0xC0; - } - } - else - { - return 0xFF; - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - SetCDLROM(flags, addr); - } - else if (addr < 0x8000) - { - SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); - } - else if ((addr >= 0xA000) && (addr < 0xC000)) - { - if (RAM_enable) - { - if (Cart_RAM != null) - { - if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]) - { - SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); - } - else - { - return; - } - } - else - { - return; - } - } - else - { - return; - } - } - else - { - return; - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x8000) - { - if (addr < 0x2000) - { - RAM_enable = (value & 0xF) != 0xE; - } - else if (addr < 0x4000) - { - value &= 0x3F; - - ROM_bank &= 0xC0; - ROM_bank |= value; - ROM_bank &= ROM_mask; - } - else if (addr < 0x6000) - { - RAM_bank = value & 3; - RAM_bank &= RAM_mask; - } - } - else - { - if (RAM_enable) - { - if (Cart_RAM_Length[0] > 0) - { - if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]) - { - Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; - } - } - } - else - { - // I don't know if other bits here have an effect - if (value == 1) - { - IR_signal = true; - } - else if (value == 0) - { - IR_signal = false; - } - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - }; - #pragma endregion - - #pragma region huC3 - - class Mapper_HuC3 : public Mapper - { - public: - - void Reset() - { - ROM_bank = 0; - RAM_bank = 0; - RAM_enable = false; - ROM_mask = ROM_Length[0] / 0x4000 - 1; - control = 0; - chip_read = 1; - timer_read = false; - time_val_shift = 0; - - // some games have sizes that result in a degenerate ROM, account for it here - if (ROM_mask > 4) { ROM_mask |= 3; } - - RAM_mask = 0; - if (Cart_RAM_Length[0] > 0) - { - RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1; - if (Cart_RAM_Length[0] == 0x800) { RAM_mask = 0; } - } - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - return ROM[addr]; - } - else if (addr < 0x8000) - { - return ROM[(addr - 0x4000) + ROM_bank * 0x4000]; - } - else if ((addr >= 0xA000) && (addr < 0xC000)) - { - if ((control >= 0xB) && (control < 0xE)) - { - if (control == 0xD) - { - return 1; - } - return chip_read; - } - - if (RAM_enable) - { - if (Cart_RAM_Length[0] > 0) - { - if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]) - { - return Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; - } - else - { - return 0xFF; - } - } - else - { - return 0xFF; - } - } - else - { - // what to return if RAM not enabled and controller not selected? - return 0xFF; - } - } - else - { - return 0xFF; - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - SetCDLROM(flags, addr); - } - else if (addr < 0x8000) - { - SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); - } - else if ((addr >= 0xA000) && (addr < 0xC000)) - { - if (RAM_enable) - { - if (Cart_RAM != null) - { - if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]) - { - SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); - } - else - { - return; - } - } - else - { - return; - } - } - else - { - return; - } - } - else - { - return; - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x8000) - { - if (addr < 0x2000) - { - RAM_enable = (value & 0xA) == 0xA; - control = value; - } - else if (addr < 0x4000) - { - if (value == 0) { value = 1; } - - ROM_bank = value; - ROM_bank &= ROM_mask; - } - else if (addr < 0x6000) - { - RAM_bank = value; - RAM_bank &= 0xF; - RAM_bank &= RAM_mask; - } - } - else - { - if (RAM_enable && ((control < 0xB) || (control > 0xE))) - { - if (Cart_RAM_Length[0] > 0) - { - if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]) - { - Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; - } - } - } - - if (control == 0xB) - { - switch (value & 0xF0) - { - case 0x10: - if (timer_read) - { - // return timer value - chip_read = (uint8_t)((time >> time_val_shift) & 0xF); - time_val_shift += 4; - if (time_val_shift == 28) { time_val_shift = 0; } - } - break; - case 0x20: - break; - case 0x30: - if (!timer_read) - { - // write to timer - if (time_val_shift == 0) { time = 0; } - if (time_val_shift < 28) - { - time |= (uint32_t)((value & 0x0F) << time_val_shift); - time_val_shift += 4; - if (time_val_shift == 28) { timer_read = true; } - } - } - break; - case 0x40: - // other commands - switch (value & 0xF) - { - case 0x0: - time_val_shift = 0; - break; - case 0x3: - timer_read = false; - time_val_shift = 0; - break; - case 0x7: - timer_read = true; - time_val_shift = 0; - break; - case 0xF: - break; - } - break; - case 0x50: - break; - case 0x60: - timer_read = true; - break; - } - } - else if (control == 0xC) - { - // maybe IR - } - else if (control == 0xD) - { - // maybe IR - } - } - } - - void RTC_Get(uint32_t value, uint32_t index) - { - time |= (uint32_t)((value & 0xFF) << index); - } - - void Mapper_Tick() - { - RTC_timer++; - - if (RTC_timer == 128) - { - RTC_timer = 0; - - RTC_low_clock++; - - if (RTC_low_clock == 32768) - { - RTC_low_clock = 0; - - RTC_seconds++; - if (RTC_seconds > 59) - { - RTC_seconds = 0; - time++; - if ((time & 0xFFF) > 1439) - { - time -= 1440; - time += (1 << 12); - if ((time >> 12) > 365) - { - time -= (365 << 12); - time += (1 << 24); - } - } - } - } - } - } - }; - - #pragma endregion - - #pragma region MBC1 - - class Mapper_MBC1 : public Mapper - { - public: - - void Reset() - { - ROM_bank = 1; - RAM_bank = 0; - RAM_enable = false; - sel_mode = false; - ROM_mask = ROM_Length[0] / 0x4000 - 1; - - // some games have sizes that result in a degenerate ROM, account for it here - if (ROM_mask > 4) { ROM_mask |= 3; } - - RAM_mask = 0; - if (Cart_RAM_Length[0] > 0) - { - RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1; - if (Cart_RAM_Length[0] == 0x800) { RAM_mask = 0; } - } - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - // lowest bank is fixed, but is still effected by mode - if (sel_mode) - { - return ROM[(ROM_bank & 0x60) * 0x4000 + addr]; - } - else - { - return ROM[addr]; - } - } - else if (addr < 0x8000) - { - return ROM[(addr - 0x4000) + ROM_bank * 0x4000]; - } - else - { - if (Cart_RAM_Length[0] > 0) - { - if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])) - { - return Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; - } - else - { - return 0xFF; - } - - } - else - { - return 0xFF; - } - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - // lowest bank is fixed, but is still effected by mode - if (sel_mode) - { - SetCDLROM(flags, (ROM_bank & 0x60) * 0x4000 + addr); - } - else - { - SetCDLROM(flags, addr); - } - } - else if (addr < 0x8000) - { - SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); - } - else - { - if (Cart_RAM != null) - { - if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])) - { - SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); - } - else - { - return; - } - - } - else - { - return; - } - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x8000) - { - if (addr < 0x2000) - { - RAM_enable = (value & 0xF) == 0xA; - } - else if (addr < 0x4000) - { - value &= 0x1F; - - // writing zero gets translated to 1 - if (value == 0) { value = 1; } - - ROM_bank &= 0xE0; - ROM_bank |= value; - ROM_bank &= ROM_mask; - } - else if (addr < 0x6000) - { - if (sel_mode && (Cart_RAM_Length[0] > 0)) - { - RAM_bank = value & 3; - RAM_bank &= RAM_mask; - } - else - { - ROM_bank &= 0x1F; - ROM_bank |= ((value & 3) << 5); - ROM_bank &= ROM_mask; - } - } - else - { - sel_mode = (value & 1) > 0; - - if (sel_mode && (Cart_RAM_Length[0] > 0)) - { - ROM_bank &= 0x1F; - ROM_bank &= ROM_mask; - } - else - { - RAM_bank = 0; - } - } - } - else - { - if (Cart_RAM_Length[0] > 0) - { - if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])) - { - Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; - } - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - }; - - #pragma endregion - - #pragma region MBC1_Multi - - class Mapper_MBC1_Multi : public Mapper - { - public: - - void Reset() - { - ROM_bank = 1; - RAM_bank = 0; - RAM_enable = false; - sel_mode = false; - ROM_mask = (ROM_Length[0] / 0x4000 * 2) - 1; // due to how mapping works, we want a 1 bit higher mask - RAM_mask = 0; - if (Cart_RAM_Length[0] > 0) - { - RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1; - if (Cart_RAM_Length[0] == 0x800) { RAM_mask = 0; } - } - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - // lowest bank is fixed, but is still effected by mode - if (sel_mode) - { - return ROM[((ROM_bank & 0x60) >> 1) * 0x4000 + addr]; - } - else - { - return ROM[addr]; - } - } - else if (addr < 0x8000) - { - return ROM[(addr - 0x4000) + (((ROM_bank & 0x60) >> 1) | (ROM_bank & 0xF)) * 0x4000]; - } - else - { - if (Cart_RAM_Length[0] > 0) - { - if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])) - { - return Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; - } - else - { - return 0xFF; - } - - } - else - { - return 0; - } - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - // lowest bank is fixed, but is still effected by mode - if (sel_mode) - { - SetCDLROM(flags, ((ROM_bank & 0x60) >> 1) * 0x4000 + addr); - } - else - { - SetCDLROM(flags, addr); - } - } - else if (addr < 0x8000) - { - SetCDLROM(flags, (addr - 0x4000) + (((ROM_bank & 0x60) >> 1) | (ROM_bank & 0xF)) * 0x4000); - } - else - { - if (Cart_RAM != null) - { - if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])) - { - SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); - } - else - { - return; - } - - } - else - { - return; - } - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x8000) - { - if (addr < 0x2000) - { - RAM_enable = ((value & 0xA) == 0xA); - } - else if (addr < 0x4000) - { - value &= 0x1F; - - // writing zero gets translated to 1 - if (value == 0) { value = 1; } - - ROM_bank &= 0xE0; - ROM_bank |= value; - ROM_bank &= ROM_mask; - } - else if (addr < 0x6000) - { - if (sel_mode && (Cart_RAM_Length[0] > 0)) - { - RAM_bank = value & 3; - RAM_bank &= RAM_mask; - } - else - { - ROM_bank &= 0x1F; - ROM_bank |= ((value & 3) << 5); - ROM_bank &= ROM_mask; - } - } - else - { - sel_mode = (value & 1) > 0; - - if (sel_mode && (Cart_RAM_Length[0] > 0)) - { - ROM_bank &= 0x1F; - ROM_bank &= ROM_mask; - } - else - { - RAM_bank = 0; - } - } - } - else - { - if (Cart_RAM_Length[0] > 0) - { - if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])) - { - Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; - } - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - }; - - #pragma endregion - - #pragma region MBC2 - - class Mapper_MBC2 : public Mapper - { - public: - - void Reset() - { - ROM_bank = 1; - RAM_bank = 0; - RAM_enable = false; - ROM_mask = ROM_Length[0] / 0x4000 - 1; - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - return ROM[addr]; - } - else if (addr < 0x8000) - { - return ROM[(addr - 0x4000) + ROM_bank * 0x4000]; - } - else if ((addr >= 0xA000) && (addr < 0xA200)) - { - if (RAM_enable) - { - return Cart_RAM[addr - 0xA000]; - } - return 0xFF; - } - else - { - return 0xFF; - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - SetCDLROM(flags, addr); - } - else if (addr < 0x8000) - { - SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); - } - else if ((addr >= 0xA000) && (addr < 0xA200)) - { - if (RAM_enable) - { - SetCDLRAM(flags, addr - 0xA000); - } - return; - } - else - { - return; - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x2000) - { - if ((addr & 0x100) == 0) - { - RAM_enable = ((value & 0xA) == 0xA); - } - } - else if (addr < 0x4000) - { - if ((addr & 0x100) > 0) - { - ROM_bank = value & 0xF & ROM_mask; - if (ROM_bank == 0) { ROM_bank = 1; } - } - } - else if ((addr >= 0xA000) && (addr < 0xA200)) - { - if (RAM_enable) - { - Cart_RAM[addr - 0xA000] = (uint8_t)(value & 0xF); - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - }; - - #pragma endregion - - #pragma region MBC3 - - class Mapper_MBC3 : public Mapper - { - public: - - void Reset() - { - ROM_bank = 1; - RAM_bank = 0; - RAM_enable = false; - ROM_mask = ROM_Length[0] / 0x4000 - 1; - - // some games have sizes that result in a degenerate ROM, account for it here - if (ROM_mask > 4) { ROM_mask |= 3; } - - RAM_mask = 0; - if (Cart_RAM_Length[0] > 0) - { - RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1; - if (Cart_RAM_Length[0] == 0x800) { RAM_mask = 0; } - } - - RTC_regs_latch[0] = 0; - RTC_regs_latch[1] = 0; - RTC_regs_latch[2] = 0; - RTC_regs_latch[3] = 0; - RTC_regs_latch[4] = 0; - - RTC_regs_latch_wr = true; - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - return ROM[addr]; - } - else if (addr < 0x8000) - { - return ROM[(addr - 0x4000) + ROM_bank * 0x4000]; - } - else - { - if (RAM_enable) - { - if ((Cart_RAM_Length[0] > 0) && (RAM_bank <= RAM_mask)) - { - if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]) - { - return Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; - } - else - { - return 0xFF; - } - } - - if ((RAM_bank >= 8) && (RAM_bank <= 0xC)) - { - //Console.WriteLine("reg: " + (RAM_bank - 8) + " value: " + RTC_regs_latch[RAM_bank - 8] + " cpu: " + Core.cpu.TotalExecutedCycles); - return RTC_regs_latch[RAM_bank - 8]; - } - else - { - return 0x0; - } - } - else - { - return 0x0; - } - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - SetCDLROM(flags, addr); - } - else if (addr < 0x8000) - { - SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); - } - else - { - if (RAM_enable) - { - if ((Cart_RAM != null) && (RAM_bank <= RAM_mask)) - { - if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]) - { - SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); - } - else - { - return; - } - } - - if ((RAM_bank >= 8) && (RAM_bank <= 0xC)) - { - return; - } - else - { - return; - } - } - else - { - return; - } - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x8000) - { - if (addr < 0x2000) - { - RAM_enable = ((value & 0xA) == 0xA); - } - else if (addr < 0x4000) - { - value &= 0x7F; - - // writing zero gets translated to 1 - if (value == 0) { value = 1; } - - ROM_bank = value; - ROM_bank &= ROM_mask; - } - else if (addr < 0x6000) - { - RAM_bank = value; - } - else - { - if (!RTC_regs_latch_wr && ((value & 1) == 1)) - { - for (uint32_t i = 0; i < 5; i++) - { - RTC_regs_latch[i] = RTC_regs[i]; - } - } - - RTC_regs_latch_wr = (value & 1) > 0; - } - } - else - { - if (RAM_enable) - { - if ((Cart_RAM_Length[0] > 0) && (RAM_bank <= RAM_mask)) - { - if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]) - { - Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; - } - } - else if ((RAM_bank >= 8) && (RAM_bank <= 0xC)) - { - RTC_regs[RAM_bank - 8] = value; - - if ((RAM_bank - 8) == 0) { RTC_low_clock = RTC_timer = 0; } - - halt = (RTC_regs[4] & 0x40) > 0; - } - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - - void RTC_Get(uint32_t value, uint32_t index) - { - if (index < 5) - { - RTC_regs[index] = (uint8_t)value; - } - else - { - RTC_offset = value; - } - } - - void Mapper_Tick() - { - if (!halt) - { - RTC_timer++; - - if (RTC_timer == 128) - { - RTC_timer = 0; - - RTC_low_clock++; - - if (RTC_low_clock == 32768) - { - RTC_low_clock = 0; - RTC_timer = RTC_offset; - - RTC_regs[0]++; - - if (RTC_regs[0] > 59) - { - RTC_regs[0] = 0; - RTC_regs[1]++; - if (RTC_regs[1] > 59) - { - RTC_regs[1] = 0; - RTC_regs[2]++; - if (RTC_regs[2] > 23) - { - RTC_regs[2] = 0; - if (RTC_regs[3] < 0xFF) - { - RTC_regs[3]++; - } - else - { - RTC_regs[3] = 0; - - if ((RTC_regs[4] & 1) == 0) - { - RTC_regs[4] |= 1; - } - else - { - RTC_regs[4] &= 0xFE; - RTC_regs[4] |= 0x80; - } - } - } - } - } - } - } - } - } - }; - - #pragma endregion - - #pragma region MBC5 - - class Mapper_MBC5 : public Mapper - { - public: - - void Reset() - { - ROM_bank = 1; - RAM_bank = 0; - RAM_enable = false; - ROM_mask = ROM_Length[0] / 0x4000 - 1; - - // some games have sizes that result in a degenerate ROM, account for it here - if (ROM_mask > 4) { ROM_mask |= 3; } - if (ROM_mask > 0x100) { ROM_mask |= 0xFF; } - - RAM_mask = 0; - if (Cart_RAM_Length[0] > 0) - { - RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1; - if (Cart_RAM_Length[0] == 0x800) { RAM_mask = 0; } - } - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - return ROM[addr]; - } - else if (addr < 0x8000) - { - return ROM[(addr - 0x4000) + ROM_bank * 0x4000]; - } - else - { - if (Cart_RAM_Length[0] > 0) - { - if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])) - { - return Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; - } - else - { - return 0xFF; - } - - } - else - { - return 0xFF; - } - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - SetCDLROM(flags, addr); - } - else if (addr < 0x8000) - { - SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); - } - else - { - if (Cart_RAM != null) - { - if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])) - { - SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); - } - else - { - return; - } - - } - else - { - return; - } - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x8000) - { - if (addr < 0x2000) - { - RAM_enable = (value & 0xF) == 0xA; - } - else if (addr < 0x3000) - { - value &= 0xFF; - - ROM_bank &= 0x100; - ROM_bank |= value; - ROM_bank &= ROM_mask; - } - else if (addr < 0x4000) - { - value &= 1; - - ROM_bank &= 0xFF; - ROM_bank |= (value << 8); - ROM_bank &= ROM_mask; - } - else if (addr < 0x6000) - { - RAM_bank = value & 0xF; - RAM_bank &= RAM_mask; - } - } - else - { - if (Cart_RAM_Length[0] > 0) - { - if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])) - { - Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; - } - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - }; - - #pragma endregion - - #pragma region MBC6 - - class Mapper_MBC6 : public Mapper - { - public: - - void Reset() - { - // nothing to initialize - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x8000) - { - return ROM[addr]; - } - else - { - if (Cart_RAM_Length[0] > 0) - { - return Cart_RAM[addr - 0xA000]; - } - else - { - return 0; - } - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x8000) - { - SetCDLROM(flags, addr); - } - else - { - if (Cart_RAM != null) - { - SetCDLRAM(flags, addr - 0xA000); - } - else - { - return; - } - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x8000) - { - // no mapping hardware available - } - else - { - if (Cart_RAM_Length[0] > 0) - { - Cart_RAM[addr - 0xA000] = value; - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - }; - - #pragma endregion - - #pragma region MBC7 - - class Mapper_MBC7 : public Mapper - { - public: - - void Reset() - { - ROM_bank = 1; - RAM_enable_1 = RAM_enable_2 = false; - ROM_mask = ROM_Length[0] / 0x4000 - 1; - - // some games have sizes that result in a degenerate ROM, account for it here - if (ROM_mask > 4) { ROM_mask |= 3; } - - acc_x_low = 0; - acc_x_high = 0x80; - acc_y_low = 0; - acc_y_high = 0x80; - - // reset acceerometer - is_erased = false; - - // EEPROM related - CS_prev = CLK_prev = DI_prev = DO = instr_read = perf_instr = WR_EN = countdown_start = false; - instr_bit_counter = instr = EE_addr = instr_case = instr_clocks = EE_value = countdown = 0; - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - return ROM[addr]; - } - else if (addr < 0x8000) - { - return ROM[(addr - 0x4000) + ROM_bank * 0x4000]; - } - else if (addr < 0xA000) - { - return 0xFF; - } - else if (addr < 0xB000) - { - if (RAM_enable_1 && RAM_enable_2) - { - return Register_Access_Read(addr); - } - else - { - return 0xFF; - } - } - else - { - return 0xFF; - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - SetCDLROM(flags, addr); - } - else if (addr < 0x8000) - { - SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); - } - else if (addr < 0xA000) - { - return; - } - else if (addr < 0xB000) - { - if (RAM_enable_1 && RAM_enable_2) - { - return; - } - else - { - return; - } - } - else - { - return; - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0xA000) - { - if (addr < 0x2000) - { - RAM_enable_1 = (value & 0xF) == 0xA; - } - else if (addr < 0x4000) - { - value &= 0xFF; - - //Console.WriteLine(Core.cpu.TotalExecutedCycles); - //Console.WriteLine(value); - - ROM_bank &= 0x100; - ROM_bank |= value; - ROM_bank &= ROM_mask; - } - else if (addr < 0x6000) - { - RAM_enable_2 = (value & 0xF0) == 0x40; - } - } - else - { - if (RAM_enable_1 && RAM_enable_2) - { - Register_Access_Write(addr, value); - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - - uint8_t Register_Access_Read(uint32_t addr) - { - if ((addr & 0xA0F0) == 0xA000) - { - return 0xFF; - } - else if ((addr & 0xA0F0) == 0xA010) - { - return 0xFF; - } - else if ((addr & 0xA0F0) == 0xA020) - { - return acc_x_low; - } - else if ((addr & 0xA0F0) == 0xA030) - { - return acc_x_high; - } - else if ((addr & 0xA0F0) == 0xA040) - { - return acc_y_low; - } - else if ((addr & 0xA0F0) == 0xA050) - { - return acc_y_high; - } - else if ((addr & 0xA0F0) == 0xA060) - { - return 0xFF; - } - else if ((addr & 0xA0F0) == 0xA070) - { - return 0xFF; - } - else if ((addr & 0xA0F0) == 0xA080) - { - return (uint8_t)((CS_prev ? 0x80 : 0) | - (CLK_prev ? 0x40 : 0) | - (DI_prev ? 2 : 0) | - (DO ? 1 : 0)); - } - else - { - return 0xFF; - } - } - - void Register_Access_Write(uint32_t addr, uint8_t value) - { - if ((addr & 0xA0F0) == 0xA000) - { - if (value == 0x55) - { - //Console.WriteLine("Erasing ACC"); - - is_erased = true; - acc_x_low = 0x00; - acc_x_high = 0x80; - acc_y_low = 0x00; - acc_y_high = 0x80; - } - } - else if ((addr & 0xA0F0) == 0xA010) - { - if ((value == 0xAA) && is_erased) - { - // latch new accelerometer values - //Console.WriteLine("Latching ACC"); - acc_x_low = (uint8_t)(Acc_X_state[0] & 0xFF); - acc_x_high = (uint8_t)((Acc_X_state[0] & 0xFF00) >> 8); - acc_y_low = (uint8_t)(Acc_Y_state[0] & 0xFF); - acc_y_high = (uint8_t)((Acc_Y_state[0] & 0xFF00) >> 8); - } - } - else if ((addr & 0xA0F0) == 0xA080) - { - // EEPROM writes - EEPROM_write(value); - } - } - - void EEPROM_write(uint8_t value) - { - bool CS = (value & 0x80) > 0; - bool CLK = (value & 0x40) > 0; - bool DI = (value & 0x2) > 0; - - // if we deselect the chip, complete instructions or countdown and stop - if (!CS) - { - CS_prev = CS; - CLK_prev = CLK; - DI_prev = DI; - - DO = true; - countdown_start = false; - perf_instr = false; - instr_read = false; - - //Console.Write("Chip De-selected: "); - //Console.WriteLine(Core.cpu.TotalExecutedCycles); - } - - if (!instr_read && !perf_instr) - { - // if we aren't performing an operation or reading an incoming instruction, we are waiting for one - // this is signalled by CS and DI both being 1 while CLK goes from 0 to 1 - if (CLK && !CLK_prev && DI && CS) - { - instr_read = true; - instr_bit_counter = 0; - instr = 0; - DO = false; - //Console.Write("Initiating command: "); - //Console.WriteLine(Core.cpu.TotalExecutedCycles); - } - } - else if (instr_read && CLK && !CLK_prev) - { - // all instructions are 10 bits long - instr = (instr << 1) | ((value & 2) >> 1); - - instr_bit_counter++; - if (instr_bit_counter == 10) - { - instr_read = false; - instr_clocks = 0; - EE_addr = instr & 0x7F; - EE_value = 0; - - switch (instr & 0x300) - { - case 0x0: - switch (instr & 0xC0) - { - case 0x0: // disable writes - instr_case = 0; - WR_EN = false; - DO = true; - break; - case 0x40: // fill mem with value - instr_case = 1; - perf_instr = true; - break; - case 0x80: // fill mem with FF - instr_case = 2; - if (WR_EN) - { - for (uint32_t i = 0; i < 256; i++) - { - Cart_RAM[i] = 0xFF; - } - } - DO = true; - break; - case 0xC0: // enable writes - instr_case = 3; - WR_EN = true; - DO = true; - break; - } - break; - case 0x100: // write to address - instr_case = 4; - perf_instr = true; - break; - case 0x200: // read from address - instr_case = 5; - perf_instr = true; - break; - case 0x300: // set address to FF - instr_case = 6; - if (WR_EN) - { - Cart_RAM[EE_addr * 2] = 0xFF; - Cart_RAM[EE_addr * 2 + 1] = 0xFF; - } - DO = true; - break; - } - - //Console.Write("Selected Command: "); - //Console.Write(instr_case); - //Console.Write(" "); - //Console.WriteLine(Core.cpu.TotalExecutedCycles); - } - } - else if (perf_instr && CLK && !CLK_prev) - { - //Console.Write("Command In progress, Cycle: "); - //Console.Write(instr_clocks); - //Console.Write(" "); - //Console.WriteLine(Core.cpu.TotalExecutedCycles); - - // for commands that require additional clocking - switch (instr_case) - { - case 1: - EE_value = (EE_value << 1) | ((value & 2) >> 1); - - if (instr_clocks == 15) - { - if (WR_EN) - { - for (uint32_t i = 0; i < 128; i++) - { - Cart_RAM[i * 2] = (uint8_t)(EE_value & 0xFF); - Cart_RAM[i * 2 + 1] = (uint8_t)((EE_value & 0xFF00) >> 8); - } - } - instr_case = 7; - countdown = 8; - } - break; - - case 4: - EE_value = (EE_value << 1) | ((value & 2) >> 1); - - if (instr_clocks == 15) - { - if (WR_EN) - { - Cart_RAM[EE_addr * 2] = (uint8_t)(EE_value & 0xFF); - Cart_RAM[EE_addr * 2 + 1] = (uint8_t)((EE_value & 0xFF00) >> 8); - } - instr_case = 7; - countdown = 8; - } - break; - - case 5: - if ((instr_clocks >= 0) && (instr_clocks <= 7)) - { - DO = ((Cart_RAM[EE_addr * 2 + 1] >> (7 - instr_clocks)) & 1) == 1; - } - else if ((instr_clocks >= 8) && (instr_clocks <= 15)) - { - DO = ((Cart_RAM[EE_addr * 2] >> (15 - instr_clocks)) & 1) == 1; - } - - if (instr_clocks == 15) - { - instr_case = 7; - countdown = 8; - } - break; - - case 6: - - instr_case = 7; - countdown = 8; - break; - - case 7: - // completed operations take time, so countdown a bit here. - // not cycle accurate for operations like writing to all of the EEPROM, but good enough - - break; - } - - if (instr_case == 7) - { - perf_instr = false; - countdown_start = true; - } - - instr_clocks++; - } - else if (countdown_start) - { - countdown--; - if (countdown == 0) - { - countdown_start = false; - DO = true; - - //Console.Write("Command Complete: "); - //Console.WriteLine(Core.cpu.TotalExecutedCycles); - } - } - - CS_prev = CS; - CLK_prev = CLK; - DI_prev = DI; - } - }; - - #pragma endregion - - #pragma region MMM01 - - class Mapper_MMM01 : public Mapper - { - public: - - void Reset() - { - // nothing to initialize - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x8000) - { - return ROM[addr]; - } - else - { - if (Cart_RAM_Length[0] > 0) - { - return Cart_RAM[addr - 0xA000]; - } - else - { - return 0; - } - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x8000) - { - SetCDLROM(flags, addr); - } - else - { - if (Cart_RAM != null) - { - SetCDLRAM(flags, addr - 0xA000); - } - else - { - return; - } - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x8000) - { - // no mapping hardware available - } - else - { - if (Cart_RAM_Length[0] > 0) - { - Cart_RAM[addr - 0xA000] = value; - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - }; - - #pragma endregion - - #pragma region RockMan8 - - class Mapper_RM8 : public Mapper - { - public: - - void Reset() - { - ROM_bank = 1; - ROM_mask = ROM_Length[0] / 0x4000 - 1; - - // some games have sizes that result in a degenerate ROM, account for it here - if (ROM_mask > 4) { ROM_mask |= 3; } - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - // lowest bank is fixed - return ROM[addr]; - - } - else if (addr < 0x8000) - { - return ROM[(addr - 0x4000) + ROM_bank * 0x4000]; - } - else - { - return 0xFF; - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - // lowest bank is fixed - SetCDLROM(flags, addr); - - } - else if (addr < 0x8000) - { - SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); - } - else - { - return; - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if ((addr >= 0x2000) && (addr < 0x4000)) - { - value &= 0x1F; - - if (value == 0) { value = 1; } - - // in hhugboy they just subtract 8, but to me looks like bits 4 and 5 are just swapped (and bit 4 is unused?) - ROM_bank = ((value & 0xF) | ((value & 0x10) >> 1))& ROM_mask; - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - }; - - #pragma endregion - - #pragma region Sachen_MMC1 - - class Mapper_Sachen1 : public Mapper - { - public: - - void Reset() - { - ROM_bank = 1; - ROM_mask = ROM_Length[0] / 0x4000 - 1; - BASE_ROM_Bank = 0; - ROM_bank_mask = 0xFF; - locked = true; - reg_access = false; - addr_last = 0; - counter = 0; - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - if (locked) - { - // header is scrambled - if ((addr >= 0x100) && (addr < 0x200)) - { - uint32_t temp0 = (addr & 1); - uint32_t temp1 = (addr & 2); - uint32_t temp4 = (addr & 0x10); - uint32_t temp6 = (addr & 0x40); - - temp0 = temp0 << 6; - temp1 = temp1 << 3; - temp4 = temp4 >> 3; - temp6 = temp6 >> 6; - - addr &= 0x1AC; - addr |= (uint32_t)(temp0 | temp1 | temp4 | temp6); - } - addr |= 0x80; - } - - return ROM[addr + BASE_ROM_Bank * 0x4000]; - } - else if (addr < 0x8000) - { - return ROM[(addr - 0x4000) + ROM_bank * 0x4000]; - } - else - { - return 0xFF; - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - if (locked) - { - // header is scrambled - if ((addr >= 0x100) && (addr < 0x200)) - { - uint32_t temp0 = (addr & 1); - uint32_t temp1 = (addr & 2); - uint32_t temp4 = (addr & 0x10); - uint32_t temp6 = (addr & 0x40); - - temp0 = temp0 << 6; - temp1 = temp1 << 3; - temp4 = temp4 >> 3; - temp6 = temp6 >> 6; - - addr &= 0x1AC; - addr |= (uint32_t)(temp0 | temp1 | temp4 | temp6); - } - addr |= 0x80; - } - - SetCDLROM(flags, addr + BASE_ROM_Bank * 0x4000); - } - else if (addr < 0x8000) - { - SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); - } - else - { - return; - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x2000) - { - if (reg_access) - { - BASE_ROM_Bank = value; - } - } - else if (addr < 0x4000) - { - ROM_bank = (value > 0) ? value : 1; - - if ((value & 0x30) == 0x30) - { - reg_access = true; - } - else - { - reg_access = false; - } - } - else if (addr < 0x6000) - { - if (reg_access) - { - ROM_bank_mask = value; - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - - void Mapper_Tick() - { - if (locked) - { - if (((addr_access[0] & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (addr_access[0] >= 0x100)) - { - counter++; - } - - if (addr_access[0] >= 0x100) - { - addr_last = addr_access[0]; - } - - if (counter == 0x30) - { - locked = false; - } - } - } - }; - - #pragma endregion - - #pragma region Sachen_MMC2 - - class Mapper_Sachen2 : public Mapper - { - public: - - void Reset() - { - ROM_bank = 1; - ROM_mask = ROM_Length[0] / 0x4000 - 1; - BASE_ROM_Bank = 0; - ROM_bank_mask = 0; - locked = true; - locked_GBC = false; - finished = false; - reg_access = false; - addr_last = 0; - counter = 0; - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - // header is scrambled - if ((addr >= 0x100) && (addr < 0x200)) - { - uint32_t temp0 = (addr & 1); - uint32_t temp1 = (addr & 2); - uint32_t temp4 = (addr & 0x10); - uint32_t temp6 = (addr & 0x40); - - temp0 = temp0 << 6; - temp1 = temp1 << 3; - temp4 = temp4 >> 3; - temp6 = temp6 >> 6; - - addr &= 0x1AC; - addr |= (uint32_t)(temp0 | temp1 | temp4 | temp6); - } - - if (locked_GBC) { addr |= 0x80; } - - return ROM[addr + BASE_ROM_Bank * 0x4000]; - } - else if (addr < 0x8000) - { - uint32_t temp_bank = (ROM_bank & ~ROM_bank_mask) | (ROM_bank_mask & BASE_ROM_Bank); - temp_bank &= ROM_mask; - - return ROM[(addr - 0x4000) + temp_bank * 0x4000]; - } - else - { - return 0xFF; - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - // header is scrambled - if ((addr >= 0x100) && (addr < 0x200)) - { - uint32_t temp0 = (addr & 1); - uint32_t temp1 = (addr & 2); - uint32_t temp4 = (addr & 0x10); - uint32_t temp6 = (addr & 0x40); - - temp0 = temp0 << 6; - temp1 = temp1 << 3; - temp4 = temp4 >> 3; - temp6 = temp6 >> 6; - - addr &= 0x1AC; - addr |= (uint32_t)(temp0 | temp1 | temp4 | temp6); - } - - if (locked_GBC) { addr |= 0x80; } - - SetCDLROM(flags, addr + BASE_ROM_Bank * 0x4000); - } - else if (addr < 0x8000) - { - uint32_t temp_bank = (ROM_bank & ~ROM_bank_mask) | (ROM_bank_mask & BASE_ROM_Bank); - temp_bank &= ROM_mask; - - SetCDLROM(flags, (addr - 0x4000) + temp_bank * 0x4000); - } - else - { - return; - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x2000) - { - if (reg_access) - { - BASE_ROM_Bank = value; - } - } - else if (addr < 0x4000) - { - ROM_bank = (value > 0) ? (value) : 1; - - if ((value & 0x30) == 0x30) - { - reg_access = true; - } - else - { - reg_access = false; - } - } - else if (addr < 0x6000) - { - if (reg_access) - { - ROM_bank_mask = value; - } - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - - void Mapper_Tick() - { - if (locked) - { - if (((addr_access[0] & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (addr_access[0] >= 0x100)) - { - counter++; - } - - if (addr_access[0] >= 0x100) - { - addr_last = addr_access[0]; - } - - if (counter == 0x30) - { - locked = false; - locked_GBC = true; - counter = 0; - } - } - else if (locked_GBC) - { - if (((addr_access[0] & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (addr_access[0] >= 0x100)) - { - counter++; - } - - if (addr_access[0] >= 0x100) - { - addr_last = addr_access[0]; - } - - if (counter == 0x30) - { - locked_GBC = false; - finished = true; - } - - // The above condition seems to never be reached as described in the mapper notes - // so for now add this one - - if ((addr_access[0] == 0x133) && (counter == 1)) - { - locked_GBC = false; - finished = true; - } - } - } - }; - - #pragma endregion - - #pragma region TAMA5 - - class Mapper_TAMA5 : public Mapper - { - public: - - void Reset() - { - ROM_bank = 0; - RAM_bank = 0; - ROM_mask = ROM_Length[0] / 0x4000 - 1; - - // some games have sizes that result in a degenerate ROM, account for it here - if (ROM_mask > 4) { ROM_mask |= 3; } - - RAM_mask = 0; - if (Cart_RAM_Length[0] > 0) - { - RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1; - if (Cart_RAM_Length[0] == 0x800) { RAM_mask = 0; } - } - - RAM_addr_low = RAM_addr_high = RAM_val_low = RAM_val_high = 0; - Chip_return_low = Chip_return_high = 0; - halt = false; - - ctrl = 0; - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x4000) - { - return ROM[addr]; - } - else if (addr < 0x8000) - { - return ROM[(addr - 0x4000) + ROM_bank * 0x4000]; - } - else - { - - switch (ctrl) - { - case 0xA: - // The game won't proceed unless this value (anded with 3) is 1 - // see bank 0: 0x1A7D to 0x1A89 - return 1; - case 0xC: - //Console.WriteLine("read low: " + Chip_return_low); - return Chip_return_low; - case 0xD: - //Console.WriteLine("read high: " + Chip_return_high); - return Chip_return_high; - } - - return 0x0; - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x4000) - { - SetCDLROM(flags, addr); - } - else if (addr < 0x8000) - { - SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); - } - else - { - - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr == 0xA000) - { - switch (ctrl) - { - case 0: - ROM_bank &= 0xF0; - ROM_bank |= (value & 0xF); - break; - case 1: - ROM_bank &= 0x0F; - ROM_bank |= ((value & 0x1) << 4); - break; - case 4: - RAM_val_low = (value & 0xF); - break; - case 5: - RAM_val_high = (value & 0xF); - //Cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] = (uint8_t)((RAM_val_high << 4) | RAM_val_low); - break; - case 6: - RAM_addr_high = (value & 1); - - switch ((value & 0xE) >> 1) - { - case 0: - // write to RAM - Cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] = (uint8_t)((RAM_val_high << 4) | RAM_val_low); - break; - case 1: - // read from RAM - Chip_return_high = (uint8_t)(Cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] >> 4); - Chip_return_low = (uint8_t)(Cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] & 0xF); - break; - case 2: - // read from RTC registers - if (RAM_addr_low == 3) - { - Chip_return_high = RTC_regs_TAMA[2]; - Chip_return_low = RTC_regs_TAMA[1]; - } - else if (RAM_addr_low == 6) - { - Chip_return_high = RTC_regs_TAMA[4]; - Chip_return_low = RTC_regs_TAMA[3]; - } - else - { - Chip_return_high = 1; - Chip_return_low = 1; - } - break; - case 3: - // write to RTC registers (probably wrong, not well tested) - if (RAM_addr_low == 3) - { - RTC_regs_TAMA[2] = (uint8_t)(RAM_val_high & 0xF); - RTC_regs_TAMA[1] = (uint8_t)(RAM_val_low & 0xF); - } - else if (RAM_addr_low == 6) - { - RTC_regs_TAMA[4] = (uint8_t)(RAM_val_high & 0xF); - RTC_regs_TAMA[3] = (uint8_t)(RAM_val_low & 0xF); - } - else - { - - } - break; - case 4: - // read from seconds register (time changes are checked when it rolls over) - Chip_return_low = (uint8_t)(RTC_regs_TAMA[0] & 0xF); - break; - } - - //Console.WriteLine("CTRL: " + (value >> 1) + " RAM_high:" + RAM_addr_high + " RAM_low: " + RAM_addr_low + " val: " + (uint8_t)((RAM_val_high << 4) | RAM_val_low) + " Cpu: " + Core.cpu.TotalExecutedCycles); - break; - case 7: - RAM_addr_low = (value & 0xF); - - //Console.WriteLine(" RAM_low:" + RAM_addr_low + " Cpu: " + Core.cpu.TotalExecutedCycles); - break; - } - } - else if (addr == 0xA001) - { - ctrl = value; - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - - void RTC_Get(uint32_t value, uint32_t index) - { - if (index < 10) - { - RTC_regs_TAMA[index] = (uint8_t)value; - } - else - { - RTC_offset = value; - } - } - - void Mapper_Tick() - { - if (!halt) - { - RTC_timer++; - - if (RTC_timer == 128) - { - RTC_timer = 0; - - RTC_low_clock++; - - if (RTC_low_clock == 32768) - { - RTC_low_clock = 0; - RTC_timer = RTC_offset; - - RTC_regs_TAMA[0]++; - - if (RTC_regs_TAMA[0] > 59) - { - RTC_regs_TAMA[0] = 0; - RTC_regs_TAMA[1]++; - // 1's digit of minutes - if (RTC_regs_TAMA[1] > 9) - { - RTC_regs_TAMA[1] = 0; - RTC_regs_TAMA[2]++; - // 10's digit of minutes - if (RTC_regs_TAMA[2] > 5) - { - RTC_regs_TAMA[2] = 0; - RTC_regs_TAMA[3]++; - // 1's digit of hours - if (RTC_regs_TAMA[3] > 9) - { - RTC_regs_TAMA[3] = 0; - RTC_regs_TAMA[4]++; - // 10's digit of hours - if (RTC_regs_TAMA[4] > 2) - { - RTC_regs_TAMA[4] = 0; - RTC_regs_TAMA[5]++; - } - } - } - } - } - } - } - } - } - }; - - #pragma endregion - - #pragma region Wisdom Tree - - class Mapper_WT : public Mapper - { - public: - - void Reset() - { - ROM_bank = 0; - ROM_mask = ROM_Length[0] / 0x8000 - 1; - - // some games have sizes that result in a degenerate ROM, account for it here - if (ROM_mask > 4) { ROM_mask |= 3; } - if (ROM_mask > 0x100) { ROM_mask |= 0xFF; } - } - - uint8_t ReadMemory(uint32_t addr) - { - if (addr < 0x8000) - { - return ROM[ROM_bank * 0x8000 + addr]; - } - else - { - return 0xFF; - } - } - - /* - void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) - { - if (addr < 0x8000) - { - SetCDLROM(flags, ROM_bank * 0x8000 + addr); - } - else - { - return; - } - } - */ - - uint8_t PeekMemory(uint32_t addr) - { - return ReadMemory(addr); - } - - void WriteMemory(uint32_t addr, uint8_t value) - { - if (addr < 0x4000) - { - ROM_bank = ((addr << 1) & 0x1ff) >> 1; - ROM_bank &= ROM_mask; - } - } - - void PokeMemory(uint32_t addr, uint8_t value) - { - WriteMemory(addr, value); - } - }; - - #pragma endregion -} diff --git a/libHawk/GBHawk/GBHawk/Memory.cpp b/libHawk/GBHawk/GBHawk/Memory.cpp deleted file mode 100644 index 597609604e..0000000000 --- a/libHawk/GBHawk/GBHawk/Memory.cpp +++ /dev/null @@ -1,999 +0,0 @@ -#include -#include -#include -#include - -#include "Memory.h" -#include "LR35902.h" -#include "PPU.h" -#include "GBAudio.h" -#include "Mappers.h" -#include "SerialPort.h" -#include "Timer.h" - -using namespace std; - -namespace GBHawk -{ - /* - $FFFF Interrupt Enable Flag - $FF80-$FFFE Zero Page - 127 bytes - $FF00-$FF7F Hardware I/O Registers - $FEA0-$FEFF Unusable Memory - $FE00-$FE9F OAM - Object Attribute Memory - $E000-$FDFF Echo RAM - Reserved, Do Not Use - $D000-$DFFF Internal RAM - Bank 1-7 (switchable - CGB only) - $C000-$CFFF Internal RAM - Bank 0 (fixed) - $A000-$BFFF Cartridge RAM (If Available) - $9C00-$9FFF BG Map Data 2 - $9800-$9BFF BG Map Data 1 - $8000-$97FF Character RAM - $4000-$7FFF Cartridge ROM - Switchable Banks 1-xx - $0150-$3FFF Cartridge ROM - Bank 0 (fixed) - $0100-$014F Cartridge Header Area - $0000-$00FF Restart and Interrupt Vectors - */ - - /* - * VRAM is arranged as: - * 0x1800 Tiles - * 0x400 BG Map 1 - * 0x400 BG Map 2 - * 0x1800 Tiles - * 0x400 CA Map 1 - * 0x400 CA Map 2 - * Only the top set is available in GB (i.e. VRAM_Bank = 0) - */ - - uint8_t MemoryManager::ReadMemory(uint32_t addr) - { - //uint flags = (uint)(MemoryCallbackFlags.AccessRead); - //MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "System Bus"); - addr_access = addr; - - if (ppu_pntr->DMA_start) - { - // some of gekkio's tests require these to be accessible during DMA - if (addr < 0x8000) - { - if (ppu_pntr->DMA_addr < 0x80) - { - return 0xFF; - } - else - { - return mapper_pntr->ReadMemory(addr); - } - } - else if ((addr >= 0xE000) && (addr < 0xF000)) - { - return RAM[addr - 0xE000]; - } - else if ((addr >= 0xF000) && (addr < 0xFE00)) - { - return RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)]; - } - else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu_pntr->DMA_OAM_access) - { - return OAM[addr - 0xFE00]; - } - else if ((addr >= 0xFF00) && (addr < 0xFF80)) // The game GOAL! Requires Hardware Regs to be accessible - { - return Read_Registers(addr); - } - else if ((addr >= 0xFF80)) - { - return ZP_RAM[addr - 0xFF80]; - } - - return 0xFF; - } - - if (addr < 0x900) - { - if (addr < 0x100) - { - // return Either BIOS ROM or Game ROM - if ((GB_bios_register & 0x1) == 0) - { - return bios_rom[addr]; // Return BIOS - } - else - { - return mapper_pntr->ReadMemory(addr); - } - } - else if (addr >= 0x200) - { - // return Either BIOS ROM or Game ROM - if (((GB_bios_register & 0x1) == 0) && is_GBC) - { - return bios_rom[addr]; // Return BIOS - } - else - { - return mapper_pntr->ReadMemory(addr); - } - } - else - { - return mapper_pntr->ReadMemory(addr); - } - } - else if (addr < 0x8000) - { - return mapper_pntr->ReadMemory(addr); - } - else if (addr < 0xA000) - { - if (ppu_pntr->VRAM_access_read) { return VRAM[(VRAM_Bank * 0x2000) + (addr - 0x8000)]; } - else { return 0xFF; } - } - else if (addr < 0xC000) - { - return mapper_pntr->ReadMemory(addr); - } - else if (addr < 0xD000) - { - return RAM[addr - 0xC000]; - } - else if (addr < 0xE000) - { - return RAM[(RAM_Bank * 0x1000) + (addr - 0xD000)]; - } - else if (addr < 0xF000) - { - return RAM[addr - 0xE000]; - } - else if (addr < 0xFE00) - { - return RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)]; - } - else if (addr < 0xFEA0) - { - if (ppu_pntr->OAM_access_read) { return OAM[addr - 0xFE00]; } - else { return 0xFF; } - } - else if (addr < 0xFF00) - { - // unmapped memory, returns 0xFF - return 0xFF; - } - else if (addr < 0xFF80) - { - return Read_Registers(addr); - } - else if (addr < 0xFFFF) - { - return ZP_RAM[addr - 0xFF80]; - } - else - { - return Read_Registers(addr); - } - - } - - void MemoryManager::WriteMemory(uint32_t addr, uint8_t value) - { - //uint flags = (uint)(MemoryCallbackFlags.AccessWrite); - //MemoryCallbacks.CallMemoryCallbacks(addr, value, flags, "System Bus"); - addr_access = addr; - - if (ppu_pntr->DMA_start) - { - // some of gekkio's tests require this to be accessible during DMA - if ((addr >= 0xE000) && (addr < 0xF000)) - { - RAM[addr - 0xE000] = value; - } - else if ((addr >= 0xF000) && (addr < 0xFE00)) - { - RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)] = value; - } - else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu_pntr->DMA_OAM_access) - { - OAM[addr - 0xFE00] = value; - } - else if ((addr >= 0xFF00) && (addr < 0xFF80)) // The game GOAL! Requires Hardware Regs to be accessible - { - Write_Registers(addr, value); - } - else if ((addr >= 0xFF80)) - { - ZP_RAM[addr - 0xFF80] = value; - } - return; - } - - if (addr < 0x900) - { - if (addr < 0x100) - { - if ((GB_bios_register & 0x1) == 0) - { - // No Writing to BIOS - } - else - { - mapper_pntr->WriteMemory(addr, value); - } - } - else if (addr >= 0x200) - { - if (((GB_bios_register & 0x1) == 0) && is_GBC) - { - // No Writing to BIOS - } - else - { - mapper_pntr->WriteMemory(addr, value); - } - } - else - { - mapper_pntr->WriteMemory(addr, value); - } - } - else if (addr < 0x8000) - { - mapper_pntr->WriteMemory(addr, value); - } - else if (addr < 0xA000) - { - if (ppu_pntr->VRAM_access_write) { VRAM[(VRAM_Bank * 0x2000) + (addr - 0x8000)] = value; } - } - else if (addr < 0xC000) - { - mapper_pntr->WriteMemory(addr, value); - } - else if (addr < 0xD000) - { - RAM[addr - 0xC000] = value; - } - else if (addr < 0xE000) - { - RAM[(RAM_Bank * 0x1000) + (addr - 0xD000)] = value; - } - else if (addr < 0xF000) - { - RAM[addr - 0xE000] = value; - } - else if (addr < 0xFE00) - { - RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)] = value; - } - else if (addr < 0xFEA0) - { - if (ppu_pntr->OAM_access_write) { OAM[addr - 0xFE00] = value; } - } - else if (addr < 0xFF00) - { - // unmapped, writing has no effect - } - else if (addr < 0xFF80) - { - Write_Registers(addr, value); - } - else if (addr < 0xFFFF) - { - ZP_RAM[addr - 0xFF80] = value; - } - else - { - Write_Registers(addr, value); - } - } - - uint8_t MemoryManager::PeekMemory(uint32_t addr) - { - if (ppu_pntr->DMA_start) - { - // some of gekkio's tests require these to be accessible during DMA - if (addr < 0x8000) - { - if (ppu_pntr->DMA_addr < 0x80) - { - return 0xFF; - } - else - { - return mapper_pntr->ReadMemory(addr); - } - } - else if ((addr >= 0xE000) && (addr < 0xF000)) - { - return RAM[addr - 0xE000]; - } - else if ((addr >= 0xF000) && (addr < 0xFE00)) - { - return RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)]; - } - else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu_pntr->DMA_OAM_access) - { - return OAM[addr - 0xFE00]; - } - else if ((addr >= 0xFF00) && (addr < 0xFF80)) // The game GOAL! Requires Hardware Regs to be accessible - { - return Read_Registers(addr); - } - else if ((addr >= 0xFF80)) - { - return ZP_RAM[addr - 0xFF80]; - } - - return 0xFF; - } - - if (addr < 0x900) - { - if (addr < 0x100) - { - // return Either BIOS ROM or Game ROM - if ((GB_bios_register & 0x1) == 0) - { - return bios_rom[addr]; // Return BIOS - } - else - { - return mapper_pntr->ReadMemory(addr); - } - } - else if (addr >= 0x200) - { - // return Either BIOS ROM or Game ROM - if (((GB_bios_register & 0x1) == 0) && is_GBC) - { - return bios_rom[addr]; // Return BIOS - } - else - { - return mapper_pntr->ReadMemory(addr); - } - } - else - { - return mapper_pntr->ReadMemory(addr); - } - } - else if (addr < 0x8000) - { - return mapper_pntr->PeekMemory(addr); - } - else if (addr < 0xA000) - { - if (ppu_pntr->VRAM_access_read) { return VRAM[(VRAM_Bank * 0x2000) + (addr - 0x8000)]; } - else { return 0xFF; } - } - else if (addr < 0xC000) - { - return mapper_pntr->PeekMemory(addr); - } - else if (addr < 0xD000) - { - return RAM[addr - 0xC000]; - } - else if (addr < 0xE000) - { - return RAM[(RAM_Bank * 0x1000) + (addr - 0xD000)]; - } - else if (addr < 0xF000) - { - return RAM[addr - 0xE000]; - } - else if (addr < 0xFE00) - { - return RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)]; - } - else if (addr < 0xFEA0) - { - if (ppu_pntr->OAM_access_read) { return OAM[addr - 0xFE00]; } - else { return 0xFF; } - } - else if (addr < 0xFF00) - { - // unmapped memory, returns 0xFF - return 0xFF; - } - else if (addr < 0xFF80) - { - return Read_Registers(addr); - } - else if (addr < 0xFFFF) - { - return ZP_RAM[addr - 0xFF80]; - } - else - { - return Read_Registers(addr); - } - } - - uint8_t MemoryManager::Read_Registers(uint32_t addr) - { - uint8_t ret = 0; - - switch (addr) - { - // Read Input - case 0xFF00: - lagged = false; - ret = input_register; - break; - - // Serial data port - case 0xFF01: - ret = serialport_pntr->ReadReg(addr); - break; - - // Serial port control - case 0xFF02: - ret = serialport_pntr->ReadReg(addr); - break; - - // Timer Registers - case 0xFF04: - case 0xFF05: - case 0xFF06: - case 0xFF07: - ret = timer_pntr->ReadReg(addr); - break; - - // Interrupt flags - case 0xFF0F: - ret = REG_FF0F_OLD; - break; - - // audio regs - case 0xFF10: - case 0xFF11: - case 0xFF12: - case 0xFF13: - case 0xFF14: - case 0xFF16: - case 0xFF17: - case 0xFF18: - case 0xFF19: - case 0xFF1A: - case 0xFF1B: - case 0xFF1C: - case 0xFF1D: - case 0xFF1E: - case 0xFF20: - case 0xFF21: - case 0xFF22: - case 0xFF23: - case 0xFF24: - case 0xFF25: - case 0xFF26: - case 0xFF30: - case 0xFF31: - case 0xFF32: - case 0xFF33: - case 0xFF34: - case 0xFF35: - case 0xFF36: - case 0xFF37: - case 0xFF38: - case 0xFF39: - case 0xFF3A: - case 0xFF3B: - case 0xFF3C: - case 0xFF3D: - case 0xFF3E: - case 0xFF3F: - ret = psg_pntr->ReadReg(addr); - break; - - // PPU Regs - case 0xFF40: - case 0xFF41: - case 0xFF42: - case 0xFF43: - case 0xFF44: - case 0xFF45: - case 0xFF46: - case 0xFF47: - case 0xFF48: - case 0xFF49: - case 0xFF4A: - case 0xFF4B: - ret = ppu_pntr->ReadReg(addr); - break; - - // Speed Control for GBC - case 0xFF4D: - if (GBC_compat) - { - ret = (uint8_t)(((double_speed ? 1 : 0) << 7) + ((speed_switch ? 1 : 0))); - } - else - { - ret = 0xFF; - } - break; - - case 0xFF4F: // VBK - if (GBC_compat) - { - ret = (uint8_t)(0xFE | VRAM_Bank); - } - else - { - ret = 0xFF; - } - break; - - // Bios control register. Not sure if it is readable - case 0xFF50: - ret = 0xFF; - break; - - // PPU Regs for GBC - case 0xFF51: - case 0xFF52: - case 0xFF53: - case 0xFF54: - case 0xFF55: - if (GBC_compat) - { - ret = ppu_pntr->ReadReg(addr); - } - else - { - ret = 0xFF; - } - break; - - case 0xFF56: - if (GBC_compat) - { - // can receive data - if ((IR_reg & 0xC0) == 0xC0) - { - ret = IR_reg; - } - else - { - ret = (uint8_t)(IR_reg | 2); - } - } - else - { - ret = 0xFF; - } - break; - - case 0xFF68: - case 0xFF69: - case 0xFF6A: - case 0xFF6B: - if (GBC_compat) - { - ret = ppu_pntr->ReadReg(addr); - } - else - { - ret = 0xFF; - } - break; - - // Speed Control for GBC - case 0xFF70: - if (GBC_compat) - { - ret = (uint8_t)RAM_Bank; - } - else - { - ret = 0xFF; - } - break; - - case 0xFF6C: - if (GBC_compat) { ret = undoc_6C; } - else { ret = 0xFF; } - break; - - case 0xFF72: - if (is_GBC) { ret = undoc_72; } - else { ret = 0xFF; } - break; - - case 0xFF73: - if (is_GBC) { ret = undoc_73; } - else { ret = 0xFF; } - break; - - case 0xFF74: - if (GBC_compat) { ret = undoc_74; } - else { ret = 0xFF; } - break; - - case 0xFF75: - if (is_GBC) { ret = undoc_75; } - else { ret = 0xFF; } - break; - - case 0xFF76: - if (is_GBC) { ret = undoc_76; } - else { ret = 0xFF; } - break; - - case 0xFF77: - if (is_GBC) { ret = undoc_77; } - else { ret = 0xFF; } - break; - - // interrupt control register - case 0xFFFF: - ret = REG_FFFF; - break; - - default: - ret = 0xFF; - break; - - } - return ret; - } - - void MemoryManager::Write_Registers(uint32_t addr, uint8_t value) - { - // check for high to low transitions that trigger IRQs - uint8_t contr_prev = input_register; - - switch (addr) - { - // select input - case 0xFF00: - input_register &= 0xCF; - input_register |= (uint8_t)(value & 0x30); // top 2 bits always 1 - - input_register &= 0xF0; - if ((input_register & 0x30) == 0x20) - { - input_register |= (uint8_t)(controller_state & 0xF); - } - else if ((input_register & 0x30) == 0x10) - { - input_register |= (uint8_t)((controller_state & 0xF0) >> 4); - } - else if ((input_register & 0x30) == 0x00) - { - // if both polls are set, then a bit is zero if either or both pins are zero - uint8_t temp = (uint8_t)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4)); - input_register |= temp; - } - else - { - input_register |= 0xF; - } - - // check for interrupts - if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) || - ((contr_prev & 4) > 0) && ((input_register & 4) == 0) || - ((contr_prev & 2) > 0) && ((input_register & 2) == 0) || - ((contr_prev & 1) > 0) && ((input_register & 1) == 0)) - { - if (((REG_FFFF & 0x10) > 0)) { cpu_pntr->FlagI = true; } - REG_FF0F |= 0x10; - } - - break; - - // Serial data port - case 0xFF01: - serialport_pntr->WriteReg(addr, value); - break; - - // Serial port control - case 0xFF02: - serialport_pntr->WriteReg(addr, value); - break; - - // Timer Registers - case 0xFF04: - case 0xFF05: - case 0xFF06: - case 0xFF07: - timer_pntr->WriteReg(addr, value); - break; - - // Interrupt flags - case 0xFF0F: - REG_FF0F = (uint8_t)(0xE0 | value); - - // check if enabling any of the bits triggered an IRQ - for (int i = 0; i < 5; i++) - { - if (((REG_FFFF & (1 << i)) > 0) && ((REG_FF0F & (1 << i)) > 0)) - { - cpu_pntr->FlagI = true; - } - } - - // if no bits are in common between flags and enables, de-assert the IRQ - if (((REG_FF0F & 0x1F) & REG_FFFF) == 0) { cpu_pntr->FlagI = false; } - break; - - // audio regs - case 0xFF10: - case 0xFF11: - case 0xFF12: - case 0xFF13: - case 0xFF14: - case 0xFF16: - case 0xFF17: - case 0xFF18: - case 0xFF19: - case 0xFF1A: - case 0xFF1B: - case 0xFF1C: - case 0xFF1D: - case 0xFF1E: - case 0xFF20: - case 0xFF21: - case 0xFF22: - case 0xFF23: - case 0xFF24: - case 0xFF25: - case 0xFF26: - case 0xFF30: - case 0xFF31: - case 0xFF32: - case 0xFF33: - case 0xFF34: - case 0xFF35: - case 0xFF36: - case 0xFF37: - case 0xFF38: - case 0xFF39: - case 0xFF3A: - case 0xFF3B: - case 0xFF3C: - case 0xFF3D: - case 0xFF3E: - case 0xFF3F: - psg_pntr->WriteReg(addr, value); - break; - - // PPU Regs - case 0xFF40: - case 0xFF41: - case 0xFF42: - case 0xFF43: - case 0xFF44: - case 0xFF45: - case 0xFF46: - ppu_pntr->WriteReg(addr, value); - break; - case 0xFF47: - case 0xFF48: - case 0xFF49: - ppu_pntr->WriteReg(addr, value); - compute_palettes(); - break; - case 0xFF4A: - case 0xFF4B: - ppu_pntr->WriteReg(addr, value); - break; - - // GBC compatibility register (I think) - case 0xFF4C: - if ((value != 0xC0) && (value != 0x80))// && (value != 0xFF) && (value != 0x04)) - { - GBC_compat = false; - - // cpu operation is a function of hardware only - //cpu.is_GBC = GBC_compat; - } - break; - - // Speed Control for GBC - case 0xFF4D: - if (GBC_compat) - { - speed_switch = (value & 1) > 0; - } - break; - - // VBK - case 0xFF4F: - if (GBC_compat && !ppu_pntr->HDMA_active) - { - VRAM_Bank = (uint8_t)(value & 1); - } - break; - - // Bios control register. Writing 1 permanently disables BIOS until a power cycle occurs - case 0xFF50: - // Console.WriteLine(value); - if (GB_bios_register == 0) - { - GB_bios_register = value; - } - break; - - // PPU Regs for GBC - case 0xFF51: - case 0xFF52: - case 0xFF53: - case 0xFF54: - case 0xFF55: - if (GBC_compat) - { - ppu_pntr->WriteReg(addr, value); - } - break; - - case 0xFF56: - if (is_GBC) - { - IR_reg = (uint8_t)((value & 0xC1) | (IR_reg & 0x3E)); - - // send IR signal out - if ((IR_reg & 0x1) == 0x1) { IR_signal = (uint8_t)(0 | IR_mask); } - else { IR_signal = 2; } - - // receive own signal if IR on and receive on - if ((IR_reg & 0xC1) == 0xC1) { IR_self = (uint8_t)(0 | IR_mask); } - else { IR_self = 2; } - - IR_write = 8; - } - break; - - case 0xFF68: - case 0xFF69: - case 0xFF6A: - case 0xFF6B: - //if (GBC_compat) - //{ - ppu_pntr->WriteReg(addr, value); - //} - break; - - // RAM Bank in GBC mode - case 0xFF70: - //Console.WriteLine(value); - if (GBC_compat) - { - RAM_Bank = value & 7; - if (RAM_Bank == 0) { RAM_Bank = 1; } - } - break; - - case 0xFF6C: - if (GBC_compat) { undoc_6C |= (uint8_t)(value & 1); } - break; - - case 0xFF72: - if (is_GBC) { undoc_72 = value; } - break; - - case 0xFF73: - if (is_GBC) { undoc_73 = value; } - break; - - case 0xFF74: - if (GBC_compat) { undoc_74 = value; } - break; - - case 0xFF75: - if (is_GBC) { undoc_75 |= (uint8_t)(value & 0x70); } - break; - - case 0xFF76: - // read only - break; - - case 0xFF77: - // read only - break; - - // interrupt control register - case 0xFFFF: - REG_FFFF = value; - - // check if enabling any of the bits triggered an IRQ - for (int i = 0; i < 5; i++) - { - if (((REG_FFFF & (1 << i)) > 0) && ((REG_FF0F & (1 << i)) > 0)) - { - cpu_pntr->FlagI = true; - } - } - - // if no bits are in common between flags and enables, de-assert the IRQ - if (((REG_FF0F & 0x1F) & REG_FFFF) == 0) { cpu_pntr->FlagI = false; } - break; - - default: - //Console.Write(addr); - //Console.Write(" "); - //Console.WriteLine(value); - break; - } - } - - void MemoryManager::compute_palettes() - { - for (int i = 0; i < 4; i++) - { - color_palette_OBJ[i] = color_palette[(ppu_pntr->obj_pal_0 >> (i * 2)) & 3]; - color_palette_OBJ[i + 4] = color_palette[(ppu_pntr->obj_pal_1 >> (i * 2)) & 3]; - color_palette_BG[i] = color_palette[(ppu_pntr->BGP >> (i * 2)) & 3]; - } - } - - void MemoryManager::do_controller_check() - { - lagged = false; - - // update the controller state on VBlank - controller_state = new_controller_1; - Acc_X_state = new_accx; - Acc_Y_state = new_accy; - - // check if new input changed the input register and triggered IRQ - uint8_t contr_prev = input_register; - - input_register &= 0xF0; - if ((input_register & 0x30) == 0x20) - { - input_register |= (uint8_t)(controller_state & 0xF); - } - else if ((input_register & 0x30) == 0x10) - { - input_register |= (uint8_t)((controller_state & 0xF0) >> 4); - } - else if ((input_register & 0x30) == 0x00) - { - // if both polls are set, then a bit is zero if either or both pins are zero - uint8_t temp = (uint8_t)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4)); - input_register |= temp; - } - else - { - input_register |= 0xF; - } - - // check for interrupts - if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) || - ((contr_prev & 4) > 0) && ((input_register & 4) == 0) || - ((contr_prev & 2) > 0) && ((input_register & 2) == 0) || - ((contr_prev & 1) > 0) && ((input_register & 1) == 0)) - { - if ((REG_FFFF & 0x10) > 0) { cpu_pntr->FlagI = true; } - REG_FF0F |= 0x10; - } - } - - void MemoryManager::SendVideoBuffer() - { - if (GBC_compat) - { - if (!ppu_pntr->blank_frame) - { - for (int j = 0; j < (160 * 144); j++) { frame_buffer[j] = vidbuffer[j]; } - } - - ppu_pntr->blank_frame = false; - } - else - { - if (ppu_pntr->blank_frame) - { - for (int i = 0; i < (160 * 144); i++) - { - vidbuffer[i] = color_palette[0]; - } - } - - for (int j = 0; j < (160 * 144); j++) { frame_buffer[j] = vidbuffer[j]; } - - ppu_pntr->blank_frame = false; - } - } -} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/Memory.h b/libHawk/GBHawk/GBHawk/Memory.h deleted file mode 100644 index 6d051eace1..0000000000 --- a/libHawk/GBHawk/GBHawk/Memory.h +++ /dev/null @@ -1,400 +0,0 @@ -#include -#include -#include -#include - -using namespace std; - -namespace GBHawk -{ - class LR35902; - class Timer; - class PPU; - class GBAudio; - class SerialPort; - class Mapper; - - class MemoryManager - { - public: - - MemoryManager() - { - - }; - - uint8_t ReadMemory(uint32_t addr); - uint8_t PeekMemory(uint32_t addr); - void WriteMemory(uint32_t addr, uint8_t value); - uint8_t Read_Registers(uint32_t addr); - void Write_Registers(uint32_t addr, uint8_t value); - void compute_palettes(); - void do_controller_check(); - void SendVideoBuffer(); - - #pragma region Declarations - - PPU* ppu_pntr = nullptr; - GBAudio* psg_pntr = nullptr; - LR35902* cpu_pntr = nullptr; - Timer* timer_pntr = nullptr; - SerialPort* serialport_pntr = nullptr; - Mapper* mapper_pntr = nullptr; - uint8_t* ROM = nullptr; - uint8_t* Cart_RAM = nullptr; - uint8_t* bios_rom = nullptr; - - // initialized by core loading, not savestated - uint32_t ROM_Length; - uint32_t ROM_Mapper; - uint32_t Cart_RAM_Length; - - // passed in on frame advace, not stated - uint8_t new_controller_1; - uint32_t new_accx; - uint32_t new_accy; - - // State - bool lagged; - bool is_GBC; - bool GBC_compat; - bool speed_switch, double_speed; - bool in_vblank; - bool in_vblank_old; - bool vblank_rise; - bool HDMA_transfer; - bool Use_MT; - bool has_bat; - - uint8_t GB_bios_register; - uint8_t IR_reg, IR_mask, IR_signal, IR_receive, IR_self; - - // several undocumented GBC Registers - uint8_t undoc_6C, undoc_72, undoc_73, undoc_74, undoc_75, undoc_76, undoc_77; - uint8_t controller_state; - - uint8_t REG_FFFF, REG_FF0F, REG_FF0F_OLD; - - int32_t _scanlineCallbackLine; - uint8_t input_register; - uint32_t RAM_Bank = 0; - uint32_t VRAM_Bank = 0; - uint32_t IR_write; - uint32_t addr_access; - uint32_t Acc_X_state; - uint32_t Acc_Y_state; - - uint8_t ZP_RAM[0x80] = {}; - uint8_t RAM[0x8000] = {}; - uint8_t VRAM[0x4000] = {}; - uint8_t OAM[0xA0] = {}; - uint8_t header[0x50] = {}; - uint32_t vidbuffer[160 * 144] = {}; - uint32_t frame_buffer[160 * 144] = {}; - uint32_t color_palette[4] = { 0xFFFFFFFF , 0xFFAAAAAA, 0xFF555555, 0xFF000000 }; - - const uint8_t GBA_override[13] = { 0xFF, 0x00, 0xCD, 0x03, 0x35, 0xAA, 0x31, 0x90, 0x94, 0x00, 0x00, 0x00, 0x00 }; - - // these two arrays are computed on calls from the GPU Viewer to get the GB palettes - uint32_t color_palette_BG[4] = {}; - uint32_t color_palette_OBJ[8] = {}; - - #pragma endregion - - #pragma region Functions - - // NOTE: only called when checks pass that the files are correct - void Load_BIOS(uint8_t* bios, bool GBC_console, bool GBC_as_GBA) - { - if (GBC_console) - { - bios_rom = new uint8_t[2304]; - memcpy(bios_rom, bios, 2304); - is_GBC = true; - - // set up IR variables if it's GBC - IR_mask = 0; IR_reg = 0x3E; IR_receive = 2; IR_self = 2; IR_signal = 2; - - if (GBC_as_GBA) - { - for (int i = 0; i < 13; i++) - { - bios_rom[i + 0xF3] = (uint8_t)((GBA_override[i] + bios_rom[i + 0xF3]) & 0xFF); - } - IR_mask = 2; - } - } - else - { - bios_rom = new uint8_t[256]; - memcpy(bios_rom, bios, 256); - } - } - - void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1) - { - ROM = new uint8_t[ext_rom_size_1]; - - memcpy(ROM, ext_rom_1, ext_rom_size_1); - - ROM_Length = ext_rom_size_1; - - std::memcpy(header, ext_rom_1 + 0x100, 0x50); - } - - // Switch Speed (GBC only) - uint32_t SpeedFunc(uint32_t temp) - { - if (is_GBC) - { - if (speed_switch) - { - speed_switch = false; - uint32_t ret = double_speed ? 70224 * 2 : 70224 * 2; // actual time needs checking - double_speed = !double_speed; - return ret; - } - - // if we are not switching speed, return 0 - return 0; - } - - // if we are in GB mode, return 0 indicating not switching speed - return 0; - } - - void Register_Reset() - { - input_register = 0xCF; // not reading any input - - REG_FFFF = 0; - REG_FF0F = 0xE0; - REG_FF0F_OLD = 0xE0; - - //undocumented registers - undoc_6C = 0xFE; - undoc_72 = 0; - undoc_73 = 0; - undoc_74 = 0; - undoc_75 = 0x8F; - undoc_76 = 0; - undoc_77 = 0; - } - - #pragma endregion - - #pragma region State Save / Load - - uint8_t* SaveState(uint8_t* saver) - { - saver = bool_saver(lagged, saver); - saver = bool_saver(is_GBC, saver); - saver = bool_saver(GBC_compat, saver); - saver = bool_saver(speed_switch, saver); - saver = bool_saver(double_speed, saver); - saver = bool_saver(in_vblank, saver); - saver = bool_saver(in_vblank_old, saver); - saver = bool_saver(vblank_rise, saver); - saver = bool_saver(HDMA_transfer, saver); - saver = bool_saver(Use_MT, saver); - saver = bool_saver(has_bat, saver); - - saver = byte_saver(GB_bios_register, saver); - saver = byte_saver(IR_reg, saver); - saver = byte_saver(IR_mask, saver); - saver = byte_saver(IR_signal, saver); - saver = byte_saver(IR_receive, saver); - saver = byte_saver(IR_self, saver); - saver = byte_saver(undoc_6C, saver); - saver = byte_saver(undoc_72, saver); - saver = byte_saver(undoc_73, saver); - saver = byte_saver(undoc_74, saver); - saver = byte_saver(undoc_75, saver); - saver = byte_saver(undoc_76, saver); - saver = byte_saver(undoc_77, saver); - - saver = byte_saver(controller_state, saver); - - saver = byte_saver(REG_FFFF, saver); - saver = byte_saver(REG_FF0F, saver); - saver = byte_saver(REG_FF0F_OLD, saver); - saver = byte_saver(input_register, saver); - - saver = int_saver(_scanlineCallbackLine, saver); - - saver = int_saver(RAM_Bank, saver); - saver = int_saver(VRAM_Bank, saver); - saver = int_saver(IR_write, saver); - saver = int_saver(addr_access, saver); - saver = int_saver(Acc_X_state, saver); - saver = int_saver(Acc_Y_state, saver); - - saver = byte_array_saver(ZP_RAM, saver, 0x80); - saver = byte_array_saver(RAM, saver, 0x8000); - saver = byte_array_saver(VRAM, saver, 0x4000); - saver = byte_array_saver(OAM, saver, 0xA0); - saver = byte_array_saver(header, saver, 0x50); - - saver = int_array_saver(vidbuffer, saver, 160 * 144); - saver = int_array_saver(frame_buffer, saver, 160 * 144); - - if (Cart_RAM_Length != 0) - { - saver = byte_array_saver(Cart_RAM, saver, Cart_RAM_Length); - } - - return saver; - } - - uint8_t* LoadState(uint8_t* loader) - { - loader = bool_loader(&lagged, loader); - loader = bool_loader(&is_GBC, loader); - loader = bool_loader(&GBC_compat, loader); - loader = bool_loader(&speed_switch, loader); - loader = bool_loader(&double_speed, loader); - loader = bool_loader(&in_vblank, loader); - loader = bool_loader(&in_vblank_old, loader); - loader = bool_loader(&vblank_rise, loader); - loader = bool_loader(&HDMA_transfer, loader); - loader = bool_loader(&Use_MT, loader); - loader = bool_loader(&has_bat, loader); - - loader = byte_loader(&GB_bios_register, loader); - loader = byte_loader(&IR_reg, loader); - loader = byte_loader(&IR_mask, loader); - loader = byte_loader(&IR_signal, loader); - loader = byte_loader(&IR_receive, loader); - loader = byte_loader(&IR_self, loader); - loader = byte_loader(&undoc_6C, loader); - loader = byte_loader(&undoc_72, loader); - loader = byte_loader(&undoc_73, loader); - loader = byte_loader(&undoc_74, loader); - loader = byte_loader(&undoc_75, loader); - loader = byte_loader(&undoc_76, loader); - loader = byte_loader(&undoc_77, loader); - - loader = byte_loader(&controller_state, loader); - - loader = byte_loader(®_FFFF, loader); - loader = byte_loader(®_FF0F, loader); - loader = byte_loader(®_FF0F_OLD, loader); - loader = byte_loader(&input_register, loader); - - loader = sint_loader(&_scanlineCallbackLine, loader); - - loader = int_loader(&RAM_Bank, loader); - loader = int_loader(&VRAM_Bank, loader); - loader = int_loader(&IR_write, loader); - loader = int_loader(&addr_access, loader); - loader = int_loader(&Acc_X_state, loader); - loader = int_loader(&Acc_Y_state, loader); - - loader = byte_array_loader(ZP_RAM, loader, 0x80); - loader = byte_array_loader(RAM, loader, 0x8000); - loader = byte_array_loader(VRAM, loader, 0x4000); - loader = byte_array_loader(OAM, loader, 0xA0); - loader = byte_array_loader(header, loader, 0x50); - - loader = int_array_loader(vidbuffer, loader, 160 * 144); - loader = int_array_loader(frame_buffer, loader, 160 * 144); - - if (Cart_RAM_Length != 0) - { - loader = byte_array_loader(Cart_RAM, loader, Cart_RAM_Length); - } - - return loader; - } - - uint8_t* bool_saver(bool to_save, uint8_t* saver) - { - *saver = (uint8_t)(to_save ? 1 : 0); saver++; - - return saver; - } - - uint8_t* byte_saver(uint8_t to_save, uint8_t* saver) - { - *saver = to_save; saver++; - - return saver; - } - - uint8_t* int_saver(uint32_t to_save, uint8_t* saver) - { - *saver = (uint8_t)(to_save & 0xFF); saver++; *saver = (uint8_t)((to_save >> 8) & 0xFF); saver++; - *saver = (uint8_t)((to_save >> 16) & 0xFF); saver++; *saver = (uint8_t)((to_save >> 24) & 0xFF); saver++; - - return saver; - } - - uint8_t* byte_array_saver(uint8_t* to_save, uint8_t* saver, int length) - { - for (int i = 0; i < length; i++) { *saver = to_save[i]; saver++; } - - return saver; - } - - uint8_t* int_array_saver(uint32_t* to_save, uint8_t* saver, int length) - { - for (int i = 0; i < length; i++) - { - *saver = (uint8_t)(to_save[i] & 0xFF); saver++; *saver = (uint8_t)((to_save[i] >> 8) & 0xFF); saver++; - *saver = (uint8_t)((to_save[i] >> 16) & 0xFF); saver++; *saver = (uint8_t)((to_save[i] >> 24) & 0xFF); saver++; - } - - return saver; - } - - uint8_t* bool_loader(bool* to_load, uint8_t* loader) - { - to_load[0] = *to_load == 1; loader++; - - return loader; - } - - uint8_t* byte_loader(uint8_t* to_load, uint8_t* loader) - { - to_load[0] = *loader; loader++; - - return loader; - } - - uint8_t* int_loader(uint32_t* to_load, uint8_t* loader) - { - to_load[0] = *loader; loader++; to_load[0] |= (*loader << 8); loader++; - to_load[0] |= (*loader << 16); loader++; to_load[0] |= (*loader << 24); loader++; - - return loader; - } - - uint8_t* sint_loader(int32_t* to_load, uint8_t* loader) - { - to_load[0] = *loader; loader++; to_load[0] |= (*loader << 8); loader++; - to_load[0] |= (*loader << 16); loader++; to_load[0] |= (*loader << 24); loader++; - - return loader; - } - - uint8_t* byte_array_loader(uint8_t* to_load, uint8_t* loader, int length) - { - for (int i = 0; i < length; i++) { to_load[i] = *loader; loader++; } - - return loader; - } - - uint8_t* int_array_loader(uint32_t* to_load, uint8_t* loader, int length) - { - for (int i = 0; i < length; i++) - { - to_load[i] = *loader; loader++; to_load[i] |= (*loader << 8); loader++; - to_load[i] |= (*loader << 16); loader++; to_load[i] |= (*loader << 24); loader++; - } - - return loader; - } - - #pragma endregion - }; -} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/PPU.cpp b/libHawk/GBHawk/GBHawk/PPU.cpp deleted file mode 100644 index 236fb0b859..0000000000 --- a/libHawk/GBHawk/GBHawk/PPU.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include -#include - -#include "Memory.h" -#include "PPU.h" - -using namespace std; - -namespace GBHawk -{ - uint8_t PPU::ReadMemory(uint32_t addr) - { - return mem_ctrl->ReadMemory(addr); - } - - void PPU::vblank_process() - { - in_vblank[0] = true; - vblank_rise[0] = true; - - if (scanlineCallback && (_scanlineCallbackLine[0] == -1)) - { - scanlineCallback(); - } - - mem_ctrl->do_controller_check(); - - // send the image on VBlank - mem_ctrl->SendVideoBuffer(); - } -} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/PPU.h b/libHawk/GBHawk/GBHawk/PPU.h deleted file mode 100644 index b40147c1aa..0000000000 --- a/libHawk/GBHawk/GBHawk/PPU.h +++ /dev/null @@ -1,4853 +0,0 @@ -using namespace std; - -namespace GBHawk -{ - class MemoryManager; - - class PPU - { - public: - #pragma region PPU Base - - PPU() - { - - } - - void (*scanlineCallback)(void); - - uint8_t ReadMemory(uint32_t); - - MemoryManager* mem_ctrl; - - // pointers not stated - bool* FlagI = nullptr; - bool* in_vblank = nullptr; - bool* vblank_rise = nullptr; - bool* cpu_halted = nullptr; - bool* HDMA_transfer = nullptr; - bool* GBC_compat = nullptr; - - uint8_t* cpu_LY = nullptr; - uint8_t* REG_FFFF = nullptr; - uint8_t* REG_FF0F = nullptr; - int32_t* _scanlineCallbackLine = nullptr; - uint8_t* OAM = nullptr; - uint8_t* VRAM = nullptr; - uint32_t* VRAM_Bank = nullptr; - uint32_t* _vidbuffer = nullptr; - uint32_t* color_palette = nullptr; - - uint32_t BG_palette[32] = {}; - uint32_t OBJ_palette[32] = {}; - - bool HDMA_active; - bool clear_screen; - - // register variables - uint8_t LCDC; - uint8_t STAT; - uint8_t scroll_y; - uint8_t scroll_x; - uint8_t LY; - uint8_t LY_actual; - uint8_t LY_inc; - uint8_t LYC; - uint8_t DMA_addr; - uint8_t BGP; - uint8_t obj_pal_0; - uint8_t obj_pal_1; - uint8_t window_y; - uint8_t window_x; - bool DMA_start; - uint32_t DMA_clock; - uint32_t DMA_inc; - uint8_t DMA_byte; - - // state variables - uint32_t cycle; - bool LYC_INT; - bool HBL_INT; - bool VBL_INT; - bool OAM_INT; - bool LCD_was_off; - bool stat_line; - bool stat_line_old; - // OAM scan - bool DMA_OAM_access; - bool OAM_access_read; - bool OAM_access_write; - uint32_t OAM_scan_index; - uint32_t SL_sprites_index; - uint32_t SL_sprites[40] = {}; - uint32_t write_sprite; - bool no_scan; - // render - bool VRAM_access_read; - bool VRAM_access_write; - uint32_t read_case; - uint32_t internal_cycle; - uint32_t y_tile; - uint32_t y_scroll_offset; - uint32_t x_tile; - uint32_t x_scroll_offset; - int32_t tile_byte; - uint32_t sprite_fetch_cycles; - bool fetch_sprite; - bool going_to_fetch; - bool first_fetch; - uint32_t sprite_fetch_counter; - uint8_t sprite_attr_list[160] = {}; - uint8_t sprite_pixel_list[160] = {}; - uint8_t sprite_present_list[160] = {}; - uint32_t temp_fetch; - uint32_t tile_inc; - bool pre_render; - bool pre_render_2; - uint8_t tile_data[3] = {}; - uint8_t tile_data_latch[3] = {}; - uint32_t latch_counter; - bool latch_new_data; - uint32_t render_counter; - uint32_t render_offset; - int32_t pixel_counter; - uint32_t pixel; - uint8_t sprite_data[2] = {}; - uint8_t sprite_sel[2] = {}; - uint32_t sl_use_index; - bool no_sprites; - uint32_t SL_sprites_ordered[40] = {}; // (x_end, data_low, data_high, attr) - uint32_t evaled_sprites; - uint32_t sprite_ordered_index; - bool blank_frame; - bool window_latch; - int32_t consecutive_sprite; - uint32_t last_eval; - - uint32_t total_counter; - // windowing state - uint32_t window_counter; - bool window_pre_render; - bool window_started; - bool window_is_reset; - uint32_t window_tile_inc; - uint32_t window_y_tile; - uint32_t window_x_tile; - uint32_t window_y_tile_inc; - uint32_t window_x_latch; - uint32_t window_y_latch; - - uint32_t hbl_countdown; - - // The following are GBC specific variables - // individual uint8_t used in palette colors - uint8_t BG_bytes[64] = {}; - uint8_t OBJ_bytes[64] = {}; - bool BG_bytes_inc; - bool OBJ_bytes_inc; - uint8_t BG_bytes_index; - uint8_t OBJ_bytes_index; - uint8_t BG_transfer_byte; - uint8_t OBJ_transfer_byte; - - // HDMA is unique to GBC, do it as part of the PPU tick - uint8_t HDMA_src_hi; - uint8_t HDMA_src_lo; - uint8_t HDMA_dest_hi; - uint8_t HDMA_dest_lo; - uint32_t HDMA_tick; - uint8_t HDMA_byte; - - // controls for tile attributes - uint32_t VRAM_sel; - bool BG_V_flip; - bool HDMA_mode; - bool HDMA_run_once; - uint32_t cur_DMA_src; - uint32_t cur_DMA_dest; - uint32_t HDMA_length; - uint32_t HDMA_countdown; - uint32_t HBL_HDMA_count; - uint32_t last_HBL; - bool HBL_HDMA_go; - bool HBL_test; - uint8_t LYC_t; - uint32_t LYC_cd; - - // accessors for derived values (GBC only) - uint8_t BG_pal_ret() { return (uint8_t)(((BG_bytes_inc ? 1 : 0) << 7) | (BG_bytes_index & 0x3F)); } - - uint8_t OBJ_pal_ret() { return (uint8_t)(((OBJ_bytes_inc ? 1 : 0) << 7) | (OBJ_bytes_index & 0x3F)); } - - uint8_t HDMA_ctrl() { return (uint8_t)(((HDMA_active ? 0 : 1) << 7) | ((HDMA_length >> 4) - 1)); } - - virtual uint8_t ReadReg(uint32_t addr) { return 0; } - - virtual void WriteReg(uint32_t addr, uint8_t value) { } - - virtual void tick() { } - - virtual void latch_delay() { } - - virtual void render(uint32_t render_cycle) { } - - virtual void process_sprite() { } - - virtual void OAM_scan(uint32_t OAM_cycle) { } - - virtual void Reset() { } - - virtual void reorder_and_assemble_sprites() { } - - void vblank_process(); - - uint8_t BG_PAL_read() - { - if (VRAM_access_read) - { - return BG_bytes[BG_bytes_index]; - } - else - { - return 0xFF; - } - } - - void color_compute_BG() - { - uint32_t R; - uint32_t G; - uint32_t B; - - if ((BG_bytes_index % 2) == 0) - { - R = (uint32_t)(BG_bytes[BG_bytes_index] & 0x1F); - G = (uint32_t)(((BG_bytes[BG_bytes_index] & 0xE0) | ((BG_bytes[BG_bytes_index + 1] & 0x03) << 8)) >> 5); - B = (uint32_t)((BG_bytes[BG_bytes_index + 1] & 0x7C) >> 2); - } - else - { - R = (uint32_t)(BG_bytes[BG_bytes_index - 1] & 0x1F); - G = (uint32_t)(((BG_bytes[BG_bytes_index - 1] & 0xE0) | ((BG_bytes[BG_bytes_index] & 0x03) << 8)) >> 5); - B = (uint32_t)((BG_bytes[BG_bytes_index] & 0x7C) >> 2); - } - - uint32_t retR = ((R * 13 + G * 2 + B) >> 1) & 0xFF; - uint32_t retG = ((G * 3 + B) << 1) & 0xFF; - uint32_t retB = ((R * 3 + G * 2 + B * 11) >> 1) & 0xFF; - - BG_palette[BG_bytes_index >> 1] = (uint32_t)(0xFF000000 | (retR << 16) | (retG << 8) | retB); - } - - void color_compute_OBJ() - { - uint32_t R; - uint32_t G; - uint32_t B; - - if ((OBJ_bytes_index % 2) == 0) - { - R = (uint32_t)(OBJ_bytes[OBJ_bytes_index] & 0x1F); - G = (uint32_t)(((OBJ_bytes[OBJ_bytes_index] & 0xE0) | ((OBJ_bytes[OBJ_bytes_index + 1] & 0x03) << 8)) >> 5); - B = (uint32_t)((OBJ_bytes[OBJ_bytes_index + 1] & 0x7C) >> 2); - } - else - { - R = (uint32_t)(OBJ_bytes[OBJ_bytes_index - 1] & 0x1F); - G = (uint32_t)(((OBJ_bytes[OBJ_bytes_index - 1] & 0xE0) | ((OBJ_bytes[OBJ_bytes_index] & 0x03) << 8)) >> 5); - B = (uint32_t)((OBJ_bytes[OBJ_bytes_index] & 0x7C) >> 2); - } - - uint32_t retR = ((R * 13 + G * 2 + B) >> 1) & 0xFF; - uint32_t retG = ((G * 3 + B) << 1) & 0xFF; - uint32_t retB = ((R * 3 + G * 2 + B * 11) >> 1) & 0xFF; - - OBJ_palette[OBJ_bytes_index >> 1] = (uint32_t)(0xFF000000 | (retR << 16) | (retG << 8) | retB); - } - - // normal DMA moves twice as fast in double speed mode on GBC - // So give it it's own function so we can seperate it from PPU tick - void DMA_tick() - { - // Note that DMA is halted when the CPU is halted - if (DMA_start && !cpu_halted[0]) - { - if (DMA_clock >= 4) - { - DMA_OAM_access = false; - if ((DMA_clock % 4) == 1) - { - // the cpu can't access memory during this time, but we still need the ppu to be able to. - DMA_start = false; - // Gekkio reports that A14 being high on DMA transfers always represent WRAM accesses - // So transfers nominally from higher memory areas are actually still from there (i.e. FF -> DF) - uint8_t DMA_actual = DMA_addr; - if (DMA_addr > 0xDF) { DMA_actual &= 0xDF; } - DMA_byte = ReadMemory(((uint32_t)(DMA_actual << 8) + DMA_inc)); - DMA_start = true; - } - else if ((DMA_clock % 4) == 3) - { - OAM[DMA_inc] = DMA_byte; - - if (DMA_inc < (0xA0 - 1)) { DMA_inc++; } - } - } - - DMA_clock++; - - if (DMA_clock == 648) - { - DMA_start = false; - DMA_OAM_access = true; - } - } - } - - #pragma endregion - - #pragma region State Save / Load - - uint8_t* SaveState(uint8_t* saver) - { - saver = int_array_saver(BG_palette, saver, 32); - saver = int_array_saver(OBJ_palette, saver, 32); - saver = int_array_saver(SL_sprites, saver, 40); - - saver = byte_array_saver(sprite_attr_list, saver, 160); - saver = byte_array_saver(sprite_pixel_list, saver, 160); - saver = byte_array_saver(sprite_present_list, saver, 160); - saver = byte_array_saver(tile_data, saver, 3); - saver = byte_array_saver(tile_data_latch, saver, 3); - saver = byte_array_saver(sprite_data, saver, 2); - saver = byte_array_saver(sprite_sel, saver, 2); - saver = int_array_saver(SL_sprites_ordered, saver, 40); - - saver = bool_saver(HDMA_active, saver); - saver = bool_saver(clear_screen, saver); - - saver = byte_saver(LCDC, saver); - saver = byte_saver(STAT, saver); - saver = byte_saver(scroll_y, saver); - saver = byte_saver(scroll_x, saver); - saver = byte_saver(LY, saver); - saver = byte_saver(LY_actual, saver); - saver = byte_saver(LY_inc, saver); - saver = byte_saver(LYC, saver); - saver = byte_saver(DMA_addr, saver); - saver = byte_saver(BGP, saver); - saver = byte_saver(obj_pal_0, saver); - saver = byte_saver(obj_pal_1, saver); - saver = byte_saver(window_y, saver); - saver = byte_saver(window_x, saver); - saver = bool_saver(DMA_start, saver); - saver = int_saver(DMA_clock, saver); - saver = int_saver(DMA_inc, saver); - saver = byte_saver(DMA_byte, saver); - - saver = int_saver(cycle, saver); - saver = bool_saver(LYC_INT, saver); - saver = bool_saver(HBL_INT, saver); - saver = bool_saver(VBL_INT, saver); - saver = bool_saver(OAM_INT, saver); - saver = bool_saver(stat_line, saver); - saver = bool_saver(stat_line_old, saver); - saver = bool_saver(LCD_was_off, saver); - saver = int_saver(OAM_scan_index, saver); - saver = int_saver(SL_sprites_index, saver); - saver = int_saver(write_sprite, saver); - saver = bool_saver(no_scan, saver); - - saver = bool_saver(DMA_OAM_access, saver); - saver = bool_saver(OAM_access_read, saver); - saver = bool_saver(OAM_access_write, saver); - saver = bool_saver(VRAM_access_read, saver); - saver = bool_saver(VRAM_access_write, saver); - - saver = int_saver(read_case, saver); - saver = int_saver(internal_cycle, saver); - saver = int_saver(y_tile, saver); - saver = int_saver(y_scroll_offset, saver); - saver = int_saver(x_tile, saver); - saver = int_saver(x_scroll_offset, saver); - saver = int_saver(tile_byte, saver); - saver = int_saver(sprite_fetch_cycles, saver); - saver = bool_saver(fetch_sprite, saver); - saver = bool_saver(going_to_fetch, saver); - saver = bool_saver(first_fetch, saver); - saver = int_saver(sprite_fetch_counter, saver); - - saver = int_saver(temp_fetch, saver); - saver = int_saver(tile_inc, saver); - saver = bool_saver(pre_render, saver); - saver = bool_saver(pre_render_2, saver); - saver = int_saver(latch_counter, saver); - saver = bool_saver(latch_new_data, saver); - saver = int_saver(render_counter, saver); - saver = int_saver(render_offset, saver); - saver = int_saver(pixel_counter, saver); - saver = int_saver(pixel, saver); - saver = int_saver(sl_use_index, saver); - saver = bool_saver(no_sprites, saver); - saver = int_saver(evaled_sprites, saver); - saver = int_saver(sprite_ordered_index, saver); - saver = bool_saver(blank_frame, saver); - saver = bool_saver(window_latch, saver); - saver = int_saver(consecutive_sprite, saver); - saver = int_saver(last_eval, saver); - - saver = int_saver(window_counter, saver); - saver = bool_saver(window_pre_render, saver); - saver = bool_saver(window_started, saver); - saver = bool_saver(window_is_reset, saver); - saver = int_saver(window_tile_inc, saver); - saver = int_saver(window_y_tile, saver); - saver = int_saver(window_x_tile, saver); - saver = int_saver(window_y_tile_inc, saver); - saver = int_saver(window_x_latch, saver); - saver = int_saver(window_y_latch, saver); - - saver = int_saver(hbl_countdown, saver); - - // The following are GBC specific variables - saver = byte_array_saver(BG_bytes, saver, 64); - saver = byte_array_saver(OBJ_bytes, saver, 64); - - saver = byte_saver(BG_transfer_byte, saver); - saver = byte_saver(OBJ_transfer_byte, saver); - saver = byte_saver(HDMA_src_hi, saver); - saver = byte_saver(HDMA_src_lo, saver); - saver = byte_saver(HDMA_dest_hi, saver); - saver = byte_saver(HDMA_dest_lo, saver); - saver = int_saver(HDMA_tick, saver); - saver = byte_saver(HDMA_byte, saver); - - saver = int_saver(VRAM_sel, saver); - saver = bool_saver(BG_V_flip, saver); - saver = bool_saver(HDMA_mode, saver); - saver = bool_saver(HDMA_run_once, saver); - saver = int_saver(cur_DMA_src, saver); - saver = int_saver(cur_DMA_dest, saver); - saver = int_saver(HDMA_length, saver); - saver = int_saver(HDMA_countdown, saver); - saver = int_saver(HBL_HDMA_count, saver); - saver = int_saver(last_HBL, saver); - saver = bool_saver(HBL_HDMA_go, saver); - saver = bool_saver(HBL_test, saver); - - saver = bool_saver(BG_bytes_inc, saver); - saver = bool_saver(OBJ_bytes_inc, saver); - saver = byte_saver(BG_bytes_index, saver); - saver = byte_saver(OBJ_bytes_index, saver); - - saver = byte_saver(LYC_t, saver); - saver = int_saver(LYC_cd, saver); - - return saver; - } - - uint8_t* LoadState(uint8_t* loader) - { - loader = int_array_loader(BG_palette, loader, 32); - loader = int_array_loader(OBJ_palette, loader, 32); - loader = int_array_loader(SL_sprites, loader, 40); - - loader = byte_array_loader(sprite_attr_list, loader, 160); - loader = byte_array_loader(sprite_pixel_list, loader, 160); - loader = byte_array_loader(sprite_present_list, loader, 160); - loader = byte_array_loader(tile_data, loader, 3); - loader = byte_array_loader(tile_data_latch, loader, 3); - loader = byte_array_loader(sprite_data, loader, 2); - loader = byte_array_loader(sprite_sel, loader, 2); - loader = int_array_loader(SL_sprites_ordered, loader, 40); - - loader = bool_loader(&HDMA_active, loader); - loader = bool_loader(&clear_screen, loader); - - loader = byte_loader(&LCDC, loader); - loader = byte_loader(&STAT, loader); - loader = byte_loader(&scroll_y, loader); - loader = byte_loader(&scroll_x, loader); - loader = byte_loader(&LY, loader); - loader = byte_loader(&LY_actual, loader); - loader = byte_loader(&LY_inc, loader); - loader = byte_loader(&LYC, loader); - loader = byte_loader(&DMA_addr, loader); - loader = byte_loader(&BGP, loader); - loader = byte_loader(&obj_pal_0, loader); - loader = byte_loader(&obj_pal_1, loader); - loader = byte_loader(&window_y, loader); - loader = byte_loader(&window_x, loader); - loader = bool_loader(&DMA_start, loader); - loader = int_loader(&DMA_clock, loader); - loader = int_loader(&DMA_inc, loader); - loader = byte_loader(&DMA_byte, loader); - - loader = int_loader(&cycle, loader); - loader = bool_loader(&LYC_INT, loader); - loader = bool_loader(&HBL_INT, loader); - loader = bool_loader(&VBL_INT, loader); - loader = bool_loader(&OAM_INT, loader); - loader = bool_loader(&stat_line, loader); - loader = bool_loader(&stat_line_old, loader); - loader = bool_loader(&LCD_was_off, loader); - loader = int_loader(&OAM_scan_index, loader); - loader = int_loader(&SL_sprites_index, loader); - loader = int_loader(&write_sprite, loader); - loader = bool_loader(&no_scan, loader); - - loader = bool_loader(&DMA_OAM_access, loader); - loader = bool_loader(&OAM_access_read, loader); - loader = bool_loader(&OAM_access_write, loader); - loader = bool_loader(&VRAM_access_read, loader); - loader = bool_loader(&VRAM_access_write, loader); - - loader = int_loader(&read_case, loader); - loader = int_loader(&internal_cycle, loader); - loader = int_loader(&y_tile, loader); - loader = int_loader(&y_scroll_offset, loader); - loader = int_loader(&x_tile, loader); - loader = int_loader(&x_scroll_offset, loader); - loader = sint_loader(&tile_byte, loader); - loader = int_loader(&sprite_fetch_cycles, loader); - loader = bool_loader(&fetch_sprite, loader); - loader = bool_loader(&going_to_fetch, loader); - loader = bool_loader(&first_fetch, loader); - loader = int_loader(&sprite_fetch_counter, loader); - - loader = int_loader(&temp_fetch, loader); - loader = int_loader(&tile_inc, loader); - loader = bool_loader(&pre_render, loader); - loader = bool_loader(&pre_render_2, loader); - loader = int_loader(&latch_counter, loader); - loader = bool_loader(&latch_new_data, loader); - loader = int_loader(&render_counter, loader); - loader = int_loader(&render_offset, loader); - loader = sint_loader(&pixel_counter, loader); - loader = int_loader(&pixel, loader); - loader = int_loader(&sl_use_index, loader); - loader = bool_loader(&no_sprites, loader); - loader = int_loader(&evaled_sprites, loader); - loader = int_loader(&sprite_ordered_index, loader); - loader = bool_loader(&blank_frame, loader); - loader = bool_loader(&window_latch, loader); - loader = sint_loader(&consecutive_sprite, loader); - loader = int_loader(&last_eval, loader); - - loader = int_loader(&window_counter, loader); - loader = bool_loader(&window_pre_render, loader); - loader = bool_loader(&window_started, loader); - loader = bool_loader(&window_is_reset, loader); - loader = int_loader(&window_tile_inc, loader); - loader = int_loader(&window_y_tile, loader); - loader = int_loader(&window_x_tile, loader); - loader = int_loader(&window_y_tile_inc, loader); - loader = int_loader(&window_x_latch, loader); - loader = int_loader(&window_y_latch, loader); - - loader = int_loader(&hbl_countdown, loader); - - // The following are GBC specific variables - loader = byte_array_loader(BG_bytes, loader, 64); - loader = byte_array_loader(OBJ_bytes, loader, 64); - - loader = byte_loader(&BG_transfer_byte, loader); - loader = byte_loader(&OBJ_transfer_byte, loader); - loader = byte_loader(&HDMA_src_hi, loader); - loader = byte_loader(&HDMA_src_lo, loader); - loader = byte_loader(&HDMA_dest_hi, loader); - loader = byte_loader(&HDMA_dest_lo, loader); - loader = int_loader(&HDMA_tick, loader); - loader = byte_loader(&HDMA_byte, loader); - - loader = int_loader(&VRAM_sel, loader); - loader = bool_loader(&BG_V_flip, loader); - loader = bool_loader(&HDMA_mode, loader); - loader = bool_loader(&HDMA_run_once, loader); - loader = int_loader(&cur_DMA_src, loader); - loader = int_loader(&cur_DMA_dest, loader); - loader = int_loader(&HDMA_length, loader); - loader = int_loader(&HDMA_countdown, loader); - loader = int_loader(&HBL_HDMA_count, loader); - loader = int_loader(&last_HBL, loader); - loader = bool_loader(&HBL_HDMA_go, loader); - loader = bool_loader(&HBL_test, loader); - - loader = bool_loader(&BG_bytes_inc, loader); - loader = bool_loader(&OBJ_bytes_inc, loader); - loader = byte_loader(&BG_bytes_index, loader); - loader = byte_loader(&OBJ_bytes_index, loader); - - loader = byte_loader(&LYC_t, loader); - loader = int_loader(&LYC_cd, loader); - - return loader; - } - - uint8_t* bool_saver(bool to_save, uint8_t* saver) - { - *saver = (uint8_t)(to_save ? 1 : 0); saver++; - - return saver; - } - - uint8_t* byte_saver(uint8_t to_save, uint8_t* saver) - { - *saver = to_save; saver++; - - return saver; - } - - uint8_t* int_saver(uint32_t to_save, uint8_t* saver) - { - *saver = (uint8_t)(to_save & 0xFF); saver++; *saver = (uint8_t)((to_save >> 8) & 0xFF); saver++; - *saver = (uint8_t)((to_save >> 16) & 0xFF); saver++; *saver = (uint8_t)((to_save >> 24) & 0xFF); saver++; - - return saver; - } - - uint8_t* byte_array_saver(uint8_t* to_save, uint8_t* saver, int length) - { - for (int i = 0; i < length; i++) { *saver = to_save[i]; saver++; } - - return saver; - } - - uint8_t* int_array_saver(uint32_t* to_save, uint8_t* saver, int length) - { - for (int i = 0; i < length; i++) - { - *saver = (uint8_t)(to_save[i] & 0xFF); saver++; *saver = (uint8_t)((to_save[i] >> 8) & 0xFF); saver++; - *saver = (uint8_t)((to_save[i] >> 16) & 0xFF); saver++; *saver = (uint8_t)((to_save[i] >> 24) & 0xFF); saver++; - } - - return saver; - } - - uint8_t* bool_loader(bool* to_load, uint8_t* loader) - { - to_load[0] = *to_load == 1; loader++; - - return loader; - } - - uint8_t* byte_loader(uint8_t* to_load, uint8_t* loader) - { - to_load[0] = *loader; loader++; - - return loader; - } - - uint8_t* int_loader(uint32_t* to_load, uint8_t* loader) - { - to_load[0] = *loader; loader++; to_load[0] |= (*loader << 8); loader++; - to_load[0] |= (*loader << 16); loader++; to_load[0] |= (*loader << 24); loader++; - - return loader; - } - - uint8_t* sint_loader(int32_t* to_load, uint8_t* loader) - { - to_load[0] = *loader; loader++; to_load[0] |= (*loader << 8); loader++; - to_load[0] |= (*loader << 16); loader++; to_load[0] |= (*loader << 24); loader++; - - return loader; - } - - uint8_t* byte_array_loader(uint8_t* to_load, uint8_t* loader, int length) - { - for (int i = 0; i < length; i++) { to_load[i] = *loader; loader++; } - - return loader; - } - - uint8_t* int_array_loader(uint32_t* to_load, uint8_t* loader, int length) - { - for (int i = 0; i < length; i++) - { - to_load[i] = *loader; loader++; to_load[i] |= (*loader << 8); loader++; - to_load[i] |= (*loader << 16); loader++; to_load[i] |= (*loader << 24); loader++; - } - - return loader; - } - - #pragma endregion - }; - - #pragma region GB_PPU - - class GB_PPU : public PPU - { - public: - - GB_PPU() {} - - uint8_t ReadReg(uint32_t addr) - { - uint8_t ret = 0; - - switch (addr) - { - case 0xFF40: ret = LCDC; break; // LCDC - case 0xFF41: ret = STAT; break; // STAT - case 0xFF42: ret = scroll_y; break; // SCY - case 0xFF43: ret = scroll_x; break; // SCX - case 0xFF44: ret = LY; break; // LY - case 0xFF45: ret = LYC; break; // LYC - case 0xFF46: ret = DMA_addr; break; // DMA - case 0xFF47: ret = BGP; break; // BGP - case 0xFF48: ret = obj_pal_0; break; // OBP0 - case 0xFF49: ret = obj_pal_1; break; // OBP1 - case 0xFF4A: ret = window_y; break; // WY - case 0xFF4B: ret = window_x; break; // WX - } - - return ret; - } - - void WriteReg(uint32_t addr, uint8_t value) - { - //Console.WriteLine((addr - 0xFF40) + " " + value + " " + LY + " " + cycle + " " + LCDC.Bit(7)); - switch (addr) - { - case 0xFF40: // LCDC - if (((LCDC & 0x80) > 0) && !((value & 0x80) > 0)) - { - VRAM_access_read = true; - VRAM_access_write = true; - OAM_access_read = true; - OAM_access_write = true; - - clear_screen = true; - } - - if (!((LCDC & 0x80) > 0) && ((value & 0x80) > 0)) - { - // don't draw for one frame after turning on - blank_frame = true; - } - - LCDC = value; - break; - case 0xFF41: // STAT - // writing to STAT during mode 0 or 1 causes a STAT IRQ - // this appears to be a glitchy LYC compare - if (((LCDC & 0x80) > 0)) - { - if (((STAT & 3) == 0) || ((STAT & 3) == 1)) - { - LYC_INT = true; - //if (Core.REG_FFFF.Bit(1)) { Core.cpu.FlagI = true; } - //Core.REG_FF0F |= 0x02; - } - else - { - if (((value & 0x40) > 0)) - { - if (LY == LYC) { LYC_INT = true; } - else { LYC_INT = false; } - } - } - } - STAT = (uint8_t)((value & 0xF8) | (STAT & 7) | 0x80); - - //if (!STAT.Bit(6)) { LYC_INT = false; } - if (!((STAT & 0x10) > 0)) { VBL_INT = false; } - break; - case 0xFF42: // SCY - scroll_y = value; - break; - case 0xFF43: // SCX - scroll_x = value; - break; - case 0xFF44: // LY - LY = 0; /*reset*/ - break; - case 0xFF45: // LYC - LYC = value; - if (((LCDC & 0x80) > 0)) - { - if (LY != LYC) { STAT &= 0xFB; LYC_INT = false; } - else { STAT |= 0x4; LYC_INT = true; } - - // special case: the transition from 153 -> 0 acts strange - // the comparison to 153 expects to be true for longer then the value of LY expects to be 153 - // this appears to be fixed in CGB - if ((LY_inc == 0) && cycle == 8) - { - if (153 != LYC) { STAT &= 0xFB; LYC_INT = false; } - else { STAT |= 0x4; LYC_INT = true; } - } - } - break; - case 0xFF46: // DMA - DMA_addr = value; - DMA_start = true; - DMA_OAM_access = true; - DMA_clock = 0; - DMA_inc = 0; - break; - case 0xFF47: // BGP - BGP = value; - break; - case 0xFF48: // OBP0 - obj_pal_0 = value; - break; - case 0xFF49: // OBP1 - obj_pal_1 = value; - break; - case 0xFF4A: // WY - window_y = value; - break; - case 0xFF4B: // WX - window_x = value; - break; - } - } - - void tick() - { - // the ppu only does anything if it is turned on via bit 7 of LCDC - if (((LCDC & 0x80) > 0)) - { - // start the next scanline - if (cycle == 456) - { - // scanline callback - if ((LY + LY_inc) == _scanlineCallbackLine[0]) - { - if (scanlineCallback) - { - scanlineCallback(); - } - } - - cycle = 0; - LY += LY_inc; - cpu_LY[0] = LY; - - no_scan = false; - - if (LY == 0 && LY_inc == 0) - { - LY_inc = 1; - in_vblank[0] = false; - - STAT &= 0xFC; - - // special note here, the y coordiate of the window is kept if the window is deactivated - // meaning it will pick up where it left off if re-enabled later - // so we don't reset it in the scanline loop - window_y_tile = 0; - window_y_latch = window_y; - window_y_tile_inc = 0; - window_started = false; - if (!((LCDC & 0x20) > 0)) { window_is_reset = true; } - } - - // Automatically restore access to VRAM at this time (force end drawing) - // Who Framed Roger Rabbit seems to run into this. - VRAM_access_write = true; - VRAM_access_read = true; - - if (LY == 144) - { - vblank_process(); - } - } - - // exit vblank if LCD went from off to on - if (LCD_was_off) - { - //VBL_INT = false; - in_vblank[0] = false; - LCD_was_off = false; - - // we exit vblank into mode 0 for 4 cycles - // but no hblank interrupt, presumably this only happens transitioning from mode 3 to 0 - STAT &= 0xFC; - - // also the LCD doesn't turn on right away - // also, the LCD does not enter mode 2 on scanline 0 when first turned on - no_scan = true; - cycle = 8; - } - - // the VBL stat is continuously asserted - if (LY >= 144) - { - if (((STAT & 0x10) > 0)) - { - if ((cycle >= 4) && (LY == 144)) - { - VBL_INT = true; - } - else if (LY > 144) - { - VBL_INT = true; - } - } - - if ((cycle == 2) && (LY == 144)) - { - // there is an edge case where a VBL INT is triggered if STAT bit 5 is set - if (((STAT & 0x20) > 0)) { VBL_INT = true; } - } - - if ((cycle == 4) && (LY == 144)) - { - HBL_INT = false; - - // set STAT mode to 1 (VBlank) and interrupt flag if it is enabled - STAT &= 0xFC; - STAT |= 0x01; - - if (((REG_FFFF[0] & 0x1) > 0)) { FlagI[0] = true; } - REG_FF0F[0] |= 0x01; - } - - if ((cycle == 4) && (LY == 144)) - { - if (((STAT & 0x20) > 0)) { VBL_INT = false; } - } - - if ((cycle == 6) && (LY == 153)) - { - LY = 0; - LY_inc = 0; - cpu_LY[0] = LY; - } - } - - if (!in_vblank[0]) - { - if (no_scan) - { - // timings are slightly different if we just turned on the LCD - // there is no mode 2 (presumably it missed the trigger) - if (cycle < 85) - { - if (cycle == 8) - { - // clear the sprite table - for (uint32_t k = 0; k < 10; k++) - { - SL_sprites[k * 4] = 0; - SL_sprites[k * 4 + 1] = 0; - SL_sprites[k * 4 + 2] = 0; - SL_sprites[k * 4 + 3] = 0; - } - - if (LY != LYC) - { - LYC_INT = false; - STAT &= 0xFB; - } - - if ((LY == LYC) && !((STAT & 0x4) > 0)) - { - // set STAT coincidence FLAG and interrupt flag if it is enabled - STAT |= 0x04; - if (((STAT & 0x40) > 0)) { LYC_INT = true; } - } - } - - if (cycle == 84) - { - STAT &= 0xFC; - STAT |= 0x03; - OAM_INT = false; - - OAM_access_read = false; - OAM_access_write = false; - VRAM_access_read = false; - VRAM_access_write = false; - } - } - else - { - if (cycle >= 85) - { - if (cycle == 85) - { - // x-scroll is expected to be latched one cycle later - // this is fine since nothing has started in the rendering until the second cycle - // calculate the column number of the tile to start with - x_tile = (uint32_t)(scroll_x >> 3); - render_offset = scroll_x % 8; - } - - // render the screen and handle hblank - render(cycle - 85); - } - } - } - else - { - if (cycle <= 80) - { - if (cycle == 2) - { - if (LY != 0) - { - HBL_INT = false; - if (((STAT & 0x20) > 0)) { OAM_INT = true; } - } - } - else if (cycle == 4) - { - // apparently, writes can make it to OAM one cycle longer then reads - OAM_access_write = false; - - // here mode 2 will be set to true and interrupts fired if enabled - STAT &= 0xFC; - STAT |= 0x2; - - if (LY == 0) - { - VBL_INT = false; - if (((STAT & 0x20) > 0)) { OAM_INT = true; } - } - } - - if (cycle == 80) - { - OAM_access_read = false; - OAM_access_write = true; - VRAM_access_read = false; - } - else - { - // here OAM scanning is performed - OAM_scan(cycle); - } - } - else if (cycle >= 83) - { - if (cycle == 84) - { - STAT &= 0xFC; - STAT |= 0x03; - OAM_INT = false; - OAM_access_write = false; - VRAM_access_write = false; - - // x-scroll is expected to be latched one cycle later - // this is fine since nothing has started in the rendering until the second cycle - // calculate the column number of the tile to start with - x_tile = (uint32_t)(scroll_x >> 3); - render_offset = scroll_x % 8; - } - - // render the screen and handle hblank - render(cycle - 83); - } - } - } - - if (LY_inc == 0) - { - if (cycle == 10) - { - LYC_INT = false; - STAT &= 0xFB; - } - else if (cycle == 12) - { - // Special case of LY = LYC - if ((LY == LYC) && !((STAT & 0x4) > 0)) - { - // set STAT coincidence FLAG and interrupt flag if it is enabled - STAT |= 0x04; - if (((STAT & 0x40) > 0)) { LYC_INT = true; } - } - } - } - - // here LY=LYC will be asserted or cleared (but only if LY isnt 0 as that's a special case) - if ((cycle == 2) && (LY != 0)) - { - if (LY_inc == 1) - { - LYC_INT = false; - STAT &= 0xFB; - } - } - else if ((cycle == 4) && (LY != 0)) - { - if ((LY == LYC) && !((STAT & 0x4) > 0)) - { - // set STAT coincidence FLAG and interrupt flag if it is enabled - STAT |= 0x04; - if (((STAT & 0x40) > 0)) { LYC_INT = true; } - } - } - - cycle++; - } - else - { - STAT &= 0xFC; - - VBL_INT = LYC_INT = HBL_INT = OAM_INT = false; - - in_vblank[0] = true; - - LCD_was_off = true; - - LY = 0; - cpu_LY[0] = LY; - - cycle = 0; - } - - // assert the STAT IRQ line if the line went from zero to 1 - stat_line = VBL_INT | LYC_INT | HBL_INT | OAM_INT; - - if (stat_line && !stat_line_old) - { - if (((REG_FFFF[0] & 0x2) > 0)) { FlagI[0] = true; } - REG_FF0F[0] |= 0x02; - } - - stat_line_old = stat_line; - - // process latch delays - //latch_delay(); - } - - // might be needed, not sure yet - void latch_delay() - { - - } - - void render(uint32_t render_cycle) - { - // we are now in STAT mode 3 - // NOTE: presumably the first necessary sprite is fetched at sprite evaulation - // i.e. just keeping track of the lowest x-value sprite - if (render_cycle == 0) - { - /* - OAM_access_read = false; - OAM_access_write = true; - VRAM_access_read = false; - */ - // window X is latched for the scanline, mid-line changes have no effect - window_x_latch = window_x; - - OAM_scan_index = 0; - read_case = 0; - internal_cycle = 0; - pre_render = true; - pre_render_2 = true; - tile_inc = 0; - pixel_counter = -8; - sl_use_index = 0; - fetch_sprite = false; - going_to_fetch = false; - first_fetch = true; - consecutive_sprite = (int32_t)(render_offset * (-1)) + 8; - no_sprites = false; - evaled_sprites = 0; - window_pre_render = false; - window_latch = ((LCDC & 0x20) > 0); - - total_counter = 0; - - // TODO: If Window is turned on midscanline what happens? When is this check done exactly? - if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY >= window_y_latch))) - { - window_y_tile_inc++; - if (window_y_tile_inc == 8) - { - window_y_tile_inc = 0; - window_y_tile++; - window_y_tile %= 32; - } - } - window_started = false; - - if (SL_sprites_index == 0) { no_sprites = true; } - // it is much easier to process sprites if we order them according to the rules of sprite priority first - if (!no_sprites) { reorder_and_assemble_sprites(); } - } - - // before anything else, we have to check if windowing is in effect - if (window_latch && !window_started && (LY >= window_y_latch) && (pixel_counter >= (int32_t)(window_x_latch - 7)) && (window_x_latch < 167)) - { - /* - Console.Write(LY); - Console.Write(" "); - Console.Write(cycle); - Console.Write(" "); - Console.Write(window_y_tile_inc); - Console.Write(" "); - Console.Write(window_x_latch); - Console.Write(" "); - Console.WriteLine(pixel_counter); - */ - if (window_x_latch == 0) - { - // if the window starts at zero, we still do the first access to the BG - // but then restart all over again at the window - if ((render_offset % 7) <= 6) - { - read_case = 9; - } - else - { - read_case = 10; - } - } - else - { - read_case = 4; - } - - window_pre_render = true; - - window_counter = 0; - render_counter = 0; - - // NOTE: pixel counter is >= window_x_latch - 7 here, so subtraction will result in a positive number - window_x_tile = (uint32_t)((pixel_counter - ((int32_t)window_x_latch - 7)) >> 3); - - window_tile_inc = 0; - window_started = true; - window_is_reset = false; - } - - if (!pre_render && !fetch_sprite) - { - // start shifting data into the LCD - if (render_counter >= (render_offset + 8)) - { - pixel = (tile_data_latch[0] & (1 << (7 - (render_counter % 8)))) > 0 ? 1 : 0; - pixel |= (tile_data_latch[1] & (1 << (7 - (render_counter % 8)))) > 0 ? 2 : 0; - - uint32_t ref_pixel = pixel; - if (((LCDC & 0x1) > 0)) - { - pixel = (BGP >> (pixel * 2)) & 3; - } - else - { - pixel = 0; - } - - // now we have the BG pixel, we next need the sprite pixel - if (!no_sprites) - { - bool have_sprite = false; - uint32_t s_pixel = 0; - uint32_t sprite_attr = 0; - - if (sprite_present_list[pixel_counter] == 1) - { - have_sprite = true; - s_pixel = sprite_pixel_list[pixel_counter]; - sprite_attr = sprite_attr_list[pixel_counter]; - } - - if (have_sprite) - { - bool use_sprite = false; - if (((LCDC & 0x2) > 0)) - { - if (!((sprite_attr & 0x80) > 0)) - { - use_sprite = true; - } - else if (ref_pixel == 0) - { - use_sprite = true; - } - - if (!((LCDC & 0x1) > 0)) - { - use_sprite = true; - } - } - - if (use_sprite) - { - if (((sprite_attr & 0x10) > 0)) - { - pixel = (obj_pal_1 >> (s_pixel * 2)) & 3; - } - else - { - pixel = (obj_pal_0 >> (s_pixel * 2)) & 3; - } - } - } - } - - // based on sprite priority and pixel values, pick a final pixel color - _vidbuffer[LY * 160 + pixel_counter] = color_palette[pixel]; - - pixel_counter++; - - if (pixel_counter == 160) - { - read_case = 8; - } - } - else if (pixel_counter < 0) - { - pixel_counter++; - } - render_counter++; - } - - if (!fetch_sprite) - { - if (!pre_render_2) - { - // before we go on to read case 3, we need to know if we stall there or not - // Gekkio's tests show that if sprites are at position 0 or 1 (mod 8) - // then it takes an extra cycle (1 or 2 more t-states) to process them - // Also, on DMG only, this process only runs if sprites are on in the LCDC (on GBC it always runs) - if (!no_sprites && (pixel_counter < 160) && ((LCDC & 0x2) > 0)) - { - for (uint32_t i = 0; i < SL_sprites_index; i++) - { - if ((pixel_counter >= (int32_t)(SL_sprites[i * 4 + 1] - 8)) && - (pixel_counter < (int32_t)(SL_sprites[i * 4 + 1])) && - !((evaled_sprites & (1 << i)) > 0)) - { - going_to_fetch = true; - fetch_sprite = true; - } - } - } - } - - switch (read_case) - { - case 0: // read a background tile - if ((internal_cycle % 2) == 1) - { - // calculate the row number of the tiles to be fetched - y_tile = ((uint32_t)((uint32_t)scroll_y + (uint32_t)LY) >> 3) % 32; - - temp_fetch = y_tile * 32 + (x_tile + tile_inc) % 32; - tile_byte = VRAM[0x1800 + (((LCDC & 0x8) > 0) ? 1 : 0) * 0x400 + temp_fetch]; - - read_case = 1; - if (!pre_render) - { - tile_inc++; - } - } - break; - - case 1: // read from tile graphics (0) - if ((internal_cycle % 2) == 1) - { - y_scroll_offset = (scroll_y + LY) % 8; - - if (((LCDC & 0x10) > 0)) - { - tile_data[0] = VRAM[tile_byte * 16 + y_scroll_offset * 2]; - } - else - { - // same as before except now tile uint8_t represents a signed uint8_t - if (((tile_byte & 0x80) > 0)) - { - tile_byte -= 256; - } - tile_data[0] = VRAM[0x1000 + tile_byte * 16 + y_scroll_offset * 2]; - } - - read_case = 2; - } - break; - - case 2: // read from tile graphics (1) - if ((internal_cycle % 2) == 0) - { - pre_render_2 = false; - } - else - { - y_scroll_offset = (scroll_y + LY) % 8; - - if (((LCDC & 0x10) > 0)) - { - // if LCDC somehow changed between the two reads, make sure we have a positive number - if (tile_byte < 0) - { - tile_byte += 256; - } - - tile_data[1] = VRAM[tile_byte * 16 + y_scroll_offset * 2 + 1]; - } - else - { - // same as before except now tile uint8_t represents a signed uint8_t - if (((tile_byte & 0x80) > 0) && tile_byte > 0) - { - tile_byte -= 256; - } - - tile_data[1] = VRAM[0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1]; - } - - if (pre_render) - { - // here we set up rendering - pre_render = false; - - render_counter = 0; - latch_counter = 0; - read_case = 0; - } - else - { - read_case = 3; - } - } - break; - - case 3: // read from sprite data - if ((internal_cycle % 2) == 1) - { - read_case = 0; - latch_new_data = true; - } - break; - - case 4: // read from window data - if ((window_counter % 2) == 1) - { - temp_fetch = window_y_tile * 32 + (window_x_tile + window_tile_inc) % 32; - tile_byte = VRAM[0x1800 + (((LCDC & 0x40) > 0) ? 1 : 0) * 0x400 + temp_fetch]; - - window_tile_inc++; - read_case = 5; - } - window_counter++; - break; - - case 5: // read from tile graphics (for the window) - if ((window_counter % 2) == 1) - { - y_scroll_offset = (window_y_tile_inc) % 8; - - if (((LCDC & 0x10) > 0)) - { - - tile_data[0] = VRAM[tile_byte * 16 + y_scroll_offset * 2]; - - } - else - { - // same as before except now tile uint8_t represents a signed uint8_t - if (((tile_byte & 0x80) > 0)) - { - tile_byte -= 256; - } - - tile_data[0] = VRAM[0x1000 + tile_byte * 16 + y_scroll_offset * 2]; - } - - read_case = 6; - } - window_counter++; - break; - - case 6: // read from tile graphics (for the window) - if ((window_counter % 2) == 1) - { - y_scroll_offset = (window_y_tile_inc) % 8; - if (((LCDC & 0x10) > 0)) - { - // if LCDC somehow changed between the two reads, make sure we have a positive number - if (tile_byte < 0) - { - tile_byte += 256; - } - - tile_data[1] = VRAM[tile_byte * 16 + y_scroll_offset * 2 + 1]; - } - else - { - // same as before except now tile uint8_t represents a signed uint8_t - if (((tile_byte & 0x80) > 0) && tile_byte > 0) - { - tile_byte -= 256; - } - - tile_data[1] = VRAM[0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1]; - } - - if (window_pre_render) - { - // here we set up rendering - // unlike for the normal background case, there is no pre-render period for the window - // so start shifting in data to the screen right away - if (window_x_latch <= 7) - { - if (render_offset == 0) - { - read_case = 4; - } - else - { - read_case = 9 + render_offset - 1; - } - render_counter = 8 - render_offset; - - render_offset = 7 - window_x_latch; - } - else - { - render_offset = 0; - read_case = 4; - render_counter = 8; - } - - latch_counter = 0; - latch_new_data = true; - window_pre_render = false; - } - else - { - read_case = 7; - } - } - window_counter++; - break; - - case 7: // read from sprite data - if ((window_counter % 2) == 1) - { - read_case = 4; - latch_new_data = true; - } - window_counter++; - break; - - case 8: // done reading, we are now in phase 0 - pre_render = true; - - STAT &= 0xFC; - STAT |= 0x00; - - if (((STAT & 0x8) > 0)) { HBL_INT = true; } - - OAM_access_read = true; - OAM_access_write = true; - VRAM_access_read = true; - VRAM_access_write = true; - break; - - case 9: - // this is a degenerate case for starting the window at 0 - // kevtris' timing doc indicates an additional normal BG access - // but this information is thrown away, so it's faster to do this then constantly check - // for it in read case 0 - read_case = 4; - break; - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - read_case--; - break; - } - internal_cycle++; - - if (latch_new_data) - { - latch_new_data = false; - tile_data_latch[0] = tile_data[0]; - tile_data_latch[1] = tile_data[1]; - } - } - - // every in range sprite takes 6 cycles to process - // sprites located at x=0 still take 6 cycles to process even though they don't appear on screen - // sprites above x=168 do not take any cycles to process however - - if (fetch_sprite) - { - if (going_to_fetch) - { - going_to_fetch = false; - - last_eval = 0; - - // at this time it is unknown what each cycle does, but we only need to accurately keep track of cycles - for (uint32_t i = 0; i < SL_sprites_index; i++) - { - if ((pixel_counter >= (int32_t)(SL_sprites[i * 4 + 1] - 8)) && - (pixel_counter < (int32_t)(SL_sprites[i * 4 + 1])) && - !((evaled_sprites & (1 << i)) > 0)) - { - sprite_fetch_counter += 6; - evaled_sprites |= (1 << i); - last_eval = SL_sprites[i * 4 + 1]; - } - } - - // x scroll offsets the penalty table - // there is no penalty if the next sprites to be fetched are within the currentfetch block (8 pixels) - if (first_fetch || ((int32_t)last_eval >= consecutive_sprite)) - { - if (((last_eval + render_offset) % 8) == 0) { sprite_fetch_counter += 5; } - else if (((last_eval + render_offset) % 8) == 1) { sprite_fetch_counter += 4; } - else if (((last_eval + render_offset) % 8) == 2) { sprite_fetch_counter += 3; } - else if (((last_eval + render_offset) % 8) == 3) { sprite_fetch_counter += 2; } - else if (((last_eval + render_offset) % 8) == 4) { sprite_fetch_counter += 1; } - else if (((last_eval + render_offset) % 8) == 5) { sprite_fetch_counter += 0; } - else if (((last_eval + render_offset) % 8) == 6) { sprite_fetch_counter += 0; } - else if (((last_eval + render_offset) % 8) == 7) { sprite_fetch_counter += 0; } - - consecutive_sprite = (uint32_t)(((last_eval + render_offset) >> 3) << 3) + 8 - render_offset; - - // special case exists here for sprites at zero with non-zero x-scroll. Not sure exactly the reason for it. - if (last_eval == 0 && render_offset != 0) - { - sprite_fetch_counter += render_offset; - } - } - - total_counter += sprite_fetch_counter; - - first_fetch = false; - } - else - { - sprite_fetch_counter--; - if (sprite_fetch_counter == 0) - { - fetch_sprite = false; - } - } - } - } - - void process_sprite() - { - uint32_t y; - - if ((SL_sprites[sl_use_index * 4 + 3] & 0x40) > 0) - { - if (((LCDC & 0x4) > 0)) - { - y = LY - (SL_sprites[sl_use_index * 4] - 16); - y = 15 - y; - sprite_sel[0] = VRAM[(SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2]; - sprite_sel[1] = VRAM[(SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2 + 1]; - } - else - { - y = LY - (SL_sprites[sl_use_index * 4] - 16); - y = 7 - y; - sprite_sel[0] = VRAM[SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2]; - sprite_sel[1] = VRAM[SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2 + 1]; - } - } - else - { - if (((LCDC & 0x4) > 0)) - { - y = LY - (SL_sprites[sl_use_index * 4] - 16); - sprite_sel[0] = VRAM[(SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2]; - sprite_sel[1] = VRAM[(SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2 + 1]; - } - else - { - y = LY - (SL_sprites[sl_use_index * 4] - 16); - sprite_sel[0] = VRAM[SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2]; - sprite_sel[1] = VRAM[SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2 + 1]; - } - } - - if ((SL_sprites[sl_use_index * 4 + 3] & 0x20) > 0) - { - uint32_t b0, b1, b2, b3, b4, b5, b6, b7 = 0; - for (uint32_t i = 0; i < 2; i++) - { - b0 = (sprite_sel[i] & 0x01) << 7; - b1 = (sprite_sel[i] & 0x02) << 5; - b2 = (sprite_sel[i] & 0x04) << 3; - b3 = (sprite_sel[i] & 0x08) << 1; - b4 = (sprite_sel[i] & 0x10) >> 1; - b5 = (sprite_sel[i] & 0x20) >> 3; - b6 = (sprite_sel[i] & 0x40) >> 5; - b7 = (sprite_sel[i] & 0x80) >> 7; - - sprite_sel[i] = (uint8_t)(b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7); - } - } - } - - // order sprites according to x coordinate - // note that for sprites of equal x coordinate, priority goes to first on the list - void reorder_and_assemble_sprites() - { - sprite_ordered_index = 0; - - for (uint32_t i = 0; i < 256; i++) - { - for (uint32_t j = 0; j < SL_sprites_index; j++) - { - if (SL_sprites[j * 4 + 1] == i) - { - sl_use_index = j; - process_sprite(); - SL_sprites_ordered[sprite_ordered_index * 4] = SL_sprites[j * 4 + 1]; - SL_sprites_ordered[sprite_ordered_index * 4 + 1] = sprite_sel[0]; - SL_sprites_ordered[sprite_ordered_index * 4 + 2] = sprite_sel[1]; - SL_sprites_ordered[sprite_ordered_index * 4 + 3] = SL_sprites[j * 4 + 3]; - sprite_ordered_index++; - } - } - } - - bool have_pixel = false; - uint8_t s_pixel = 0; - uint8_t sprite_attr = 0; - - for (uint32_t i = 0; i < 160; i++) - { - have_pixel = false; - for (uint32_t j = 0; j < SL_sprites_index; j++) - { - if ((i >= (SL_sprites_ordered[j * 4] - 8)) && - (i < SL_sprites_ordered[j * 4]) && - !have_pixel) - { - // we can use the current sprite, so pick out a pixel for it - uint32_t t_index = i - (SL_sprites_ordered[j * 4] - 8); - - t_index = 7 - t_index; - - sprite_data[0] = (uint8_t)((SL_sprites_ordered[j * 4 + 1] >> t_index) & 1); - sprite_data[1] = (uint8_t)(((SL_sprites_ordered[j * 4 + 2] >> t_index) & 1) << 1); - - s_pixel = (uint8_t)(sprite_data[0] + sprite_data[1]); - sprite_attr = (uint8_t)SL_sprites_ordered[j * 4 + 3]; - - // pixel color of 0 is transparent, so if this is the case we don't have a pixel - if (s_pixel != 0) - { - have_pixel = true; - } - } - } - - if (have_pixel) - { - sprite_present_list[i] = 1; - sprite_pixel_list[i] = s_pixel; - sprite_attr_list[i] = sprite_attr; - } - else - { - sprite_present_list[i] = 0; - } - } - } - - void OAM_scan(uint32_t OAM_cycle) - { - // we are now in STAT mode 2 - // TODO: maybe stat mode 2 flags are set at cycle 0 on visible scanlines? - if (OAM_cycle == 0) - { - OAM_access_read = false; - - OAM_scan_index = 0; - SL_sprites_index = 0; - write_sprite = 0; - } - - // the gameboy has 80 cycles to scan through 40 sprites, picking out the first 10 it finds to draw - // the following is a guessed at implmenentation based on how NES does it, it's probably pretty close - if (OAM_cycle < 10) - { - // start by clearing the sprite table (probably just clears X on hardware, but let's be safe here.) - SL_sprites[OAM_cycle * 4] = 0; - SL_sprites[OAM_cycle * 4 + 1] = 0; - SL_sprites[OAM_cycle * 4 + 2] = 0; - SL_sprites[OAM_cycle * 4 + 3] = 0; - } - else - { - if (write_sprite == 0) - { - if (OAM_scan_index < 40) - { - int32_t temp = DMA_OAM_access ? OAM[OAM_scan_index * 4] : (int32_t)0xFF; - // (sprite Y - 16) equals LY, we have a sprite - if ((temp - 16) <= LY && - ((temp - 16) + 8 + (((LCDC & 0x4) > 0) ? 8 : 0)) > LY) - { - // always pick the first 10 in range sprites - if (SL_sprites_index < 10) - { - SL_sprites[SL_sprites_index * 4] = temp; - - write_sprite = 1; - } - else - { - // if we already have 10 sprites, there's nothing to do, increment the index - OAM_scan_index++; - } - } - else - { - OAM_scan_index++; - } - } - } - else - { - uint32_t temp2 = DMA_OAM_access ? OAM[OAM_scan_index * 4 + write_sprite] : (uint32_t)0xFF; - SL_sprites[SL_sprites_index * 4 + write_sprite] = temp2; - write_sprite++; - - if (write_sprite == 4) - { - write_sprite = 0; - SL_sprites_index++; - OAM_scan_index++; - } - } - } - } - - void Reset() - { - LCDC = 0; - STAT = 0x80; - scroll_y = 0; - scroll_x = 0; - LY = 0; - LYC = 0; - DMA_addr = 0xFF; - BGP = 0xFF; - obj_pal_0 = 0xFF; - obj_pal_1 = 0xFF; - window_y = 0x0; - window_x = 0x0; - window_x_latch = 0xFF; - window_y_latch = 0xFF; - LY_inc = 1; - no_scan = false; - OAM_access_read = true; - VRAM_access_read = true; - OAM_access_write = true; - VRAM_access_write = true; - DMA_OAM_access = true; - - cycle = 0; - LYC_INT = false; - HBL_INT = false; - VBL_INT = false; - OAM_INT = false; - - stat_line = false; - stat_line_old = false; - - window_counter = 0; - window_pre_render = false; - window_started = false; - window_is_reset = true; - window_tile_inc = 0; - window_y_tile = 0; - window_x_tile = 0; - window_y_tile_inc = 0; - } - }; - - #pragma endregion - - #pragma region GBC_PPU - - class GBC_PPU : public PPU - { - public: - - uint8_t ReadReg(uint32_t addr) - { - uint8_t ret = 0; - //Console.WriteLine(Core.cpu.TotalExecutedCycles); - switch (addr) - { - case 0xFF40: ret = LCDC; break; // LCDC - case 0xFF41: ret = STAT; break; // STAT - case 0xFF42: ret = scroll_y; break; // SCY - case 0xFF43: ret = scroll_x; break; // SCX - case 0xFF44: ret = LY; break; // LY - case 0xFF45: ret = LYC; break; // LYC - case 0xFF46: ret = DMA_addr; break; // DMA - case 0xFF47: ret = BGP; break; // BGP - case 0xFF48: ret = obj_pal_0; break; // OBP0 - case 0xFF49: ret = obj_pal_1; break; // OBP1 - case 0xFF4A: ret = window_y; break; // WY - case 0xFF4B: ret = window_x; break; // WX - - // These are GBC specific Regs - case 0xFF51: ret = HDMA_src_hi; break; // HDMA1 - case 0xFF52: ret = HDMA_src_lo; break; // HDMA2 - case 0xFF53: ret = HDMA_dest_hi; break; // HDMA3 - case 0xFF54: ret = HDMA_dest_lo; break; // HDMA4 - case 0xFF55: ret = HDMA_ctrl(); break; // HDMA5 - case 0xFF68: ret = BG_pal_ret(); break; // BGPI - case 0xFF69: ret = BG_PAL_read(); break; // BGPD - case 0xFF6A: ret = OBJ_pal_ret(); break; // OBPI - case 0xFF6B: ret = OBJ_bytes[OBJ_bytes_index]; break; // OBPD - } - - return ret; - } - - void WriteReg(uint32_t addr, uint8_t value) - { - switch (addr) - { - case 0xFF40: // LCDC - if (((LCDC & 0x80) > 0) && !((value & 0x80) > 0)) - { - VRAM_access_read = true; - VRAM_access_write = true; - OAM_access_read = true; - OAM_access_write = true; - } - - if (!((LCDC & 0x80) > 0) && ((value & 0x80) > 0)) - { - // don't draw for one frame after turning on - blank_frame = true; - } - - LCDC = value; - break; - case 0xFF41: // STAT - // note that their is no stat interrupt bug in GBC - STAT = (uint8_t)((value & 0xF8) | (STAT & 7) | 0x80); - - if (((STAT & 3) == 0) && ((STAT & 0x8) > 0)) { HBL_INT = true; } - else { HBL_INT = false; } - if (((STAT & 3) == 1) && ((STAT & 0x10) > 0)) { VBL_INT = true; } - else { VBL_INT = false; } - // OAM not triggered? - // if (((STAT & 3) == 2) && STAT.Bit(5)) { OAM_INT = true; } else { OAM_INT = false; } - - if (((value & 0x40) > 0) && ((LCDC & 0x80) > 0)) - { - if (LY == LYC) { LYC_INT = true; } - else { LYC_INT = false; } - } - if (!((STAT & 0x40) > 0)) { LYC_INT = false; } - break; - case 0xFF42: // SCY - scroll_y = value; - break; - case 0xFF43: // SCX - scroll_x = value; - break; - case 0xFF44: // LY - LY = 0; /*reset*/ - break; - case 0xFF45: // LYC - // tests indicate that latching writes to LYC should take place 4 cycles after the write - // otherwise tests around LY boundaries will fail - LYC_t = value; - LYC_cd = 4; - break; - case 0xFF46: // DMA - DMA_addr = value; - DMA_start = true; - DMA_OAM_access = true; - DMA_clock = 0; - DMA_inc = 0; - break; - case 0xFF47: // BGP - BGP = value; - break; - case 0xFF48: // OBP0 - obj_pal_0 = value; - break; - case 0xFF49: // OBP1 - obj_pal_1 = value; - break; - case 0xFF4A: // WY - window_y = value; - break; - case 0xFF4B: // WX - window_x = value; - break; - - // These are GBC specific Regs - case 0xFF51: // HDMA1 - HDMA_src_hi = value; - cur_DMA_src = (uint32_t)(((HDMA_src_hi & 0xFF) << 8) | (cur_DMA_src & 0xF0)); - break; - case 0xFF52: // HDMA2 - HDMA_src_lo = value; - cur_DMA_src = (uint32_t)((cur_DMA_src & 0xFF00) | (HDMA_src_lo & 0xF0)); - break; - case 0xFF53: // HDMA3 - HDMA_dest_hi = value; - cur_DMA_dest = (uint32_t)(((HDMA_dest_hi & 0x1F) << 8) | (cur_DMA_dest & 0xF0)); - break; - case 0xFF54: // HDMA4 - HDMA_dest_lo = value; - cur_DMA_dest = (uint32_t)((cur_DMA_dest & 0xFF00) | (HDMA_dest_lo & 0xF0)); - break; - case 0xFF55: // HDMA5 - if (!HDMA_active) - { - HDMA_mode = ((value & 0x80) > 0); - HDMA_countdown = 4; - HDMA_tick = 0; - if (((value & 0x80) > 0)) - { - // HDMA during HBlank only, but only if screen is on, otherwise DMA immediately one block of data - // worms armaggedon requires HDMA to fire in hblank mode even if the screen is off. - HDMA_active = true; - HBL_HDMA_count = 0x10; - - last_HBL = LY - 1; - - HBL_test = true; - HBL_HDMA_go = false; - - if (!((LCDC & 0x80) > 0)) - { - HDMA_run_once = true; - } - } - else - { - // HDMA immediately - HDMA_active = true; - HDMA_transfer[0] = true; - } - - HDMA_length = ((value & 0x7F) + 1) * 16; - } - else - { - //terminate the transfer - if (!((value & 0x80) > 0)) - { - HDMA_active = false; - } - } - - break; - case 0xFF68: // BGPI - BG_bytes_index = (uint8_t)(value & 0x3F); - BG_bytes_inc = ((value & 0x80) == 0x80); - break; - case 0xFF69: // BGPD - if (VRAM_access_write) - { - BG_transfer_byte = value; - BG_bytes[BG_bytes_index] = value; - } - - // change the appropriate palette color - color_compute_BG(); - if (BG_bytes_inc) { BG_bytes_index++; BG_bytes_index &= 0x3F; } - break; - case 0xFF6A: // OBPI - OBJ_bytes_index = (uint8_t)(value & 0x3F); - OBJ_bytes_inc = ((value & 0x80) == 0x80); - break; - case 0xFF6B: // OBPD - OBJ_transfer_byte = value; - OBJ_bytes[OBJ_bytes_index] = value; - - // change the appropriate palette color - color_compute_OBJ(); - - if (OBJ_bytes_inc) { OBJ_bytes_index++; OBJ_bytes_index &= 0x3F; } - break; - } - } - - void tick() - { - // Do HDMA ticks - if (HDMA_active) - { - if (HDMA_length > 0) - { - if (!HDMA_mode) - { - if (HDMA_countdown > 0) - { - HDMA_countdown--; - } - else - { - // immediately transfer bytes, 2 bytes per cycles - if ((HDMA_tick % 2) == 0) - { - HDMA_byte = ReadMemory(cur_DMA_src); - } - else - { - VRAM[(VRAM_Bank[0] * 0x2000) + cur_DMA_dest] = HDMA_byte; - cur_DMA_dest = (uint32_t)((cur_DMA_dest + 1) & 0x1FFF); - cur_DMA_src = (uint32_t)((cur_DMA_src + 1) & 0xFFFF); - HDMA_length--; - } - - HDMA_tick++; - } - } - else - { - // only transfer during mode 0, and only 16 bytes at a time - if (((STAT & 3) == 0) && (LY != last_HBL) && HBL_test && (LY_inc == 1) && (cycle > 4)) - { - HBL_HDMA_go = true; - HBL_test = false; - } - else if (HDMA_run_once) - { - HBL_HDMA_go = true; - HBL_test = false; - HDMA_run_once = false; - } - - if (HBL_HDMA_go && (HBL_HDMA_count > 0)) - { - HDMA_transfer[0] = true; - - if (HDMA_countdown > 0) - { - HDMA_countdown--; - } - else - { - if ((HDMA_tick % 2) == 0) - { - HDMA_byte = ReadMemory(cur_DMA_src); - } - else - { - VRAM[(VRAM_Bank[0] * 0x2000) + cur_DMA_dest] = HDMA_byte; - cur_DMA_dest = (uint32_t)((cur_DMA_dest + 1) & 0x1FFF); - cur_DMA_src = (uint32_t)((cur_DMA_src + 1) & 0xFFFF); - HDMA_length--; - HBL_HDMA_count--; - } - - if ((HBL_HDMA_count == 0) && (HDMA_length != 0)) - { - - HBL_test = true; - last_HBL = LY; - HBL_HDMA_count = 0x10; - HBL_HDMA_go = false; - HDMA_countdown = 4; - } - - HDMA_tick++; - } - } - else - { - HDMA_transfer[0] = false; - } - } - } - else - { - HDMA_active = false; - HDMA_transfer[0] = false; - } - } - - // the ppu only does anything if it is turned on via bit 7 of LCDC - if (((LCDC & 0x80) > 0)) - { - // start the next scanline - if (cycle == 456) - { - // scanline callback - if ((LY + LY_inc) == _scanlineCallbackLine[0]) - { - if (scanlineCallback) - { - scanlineCallback(); - } - } - - cycle = 0; - LY += LY_inc; - cpu_LY[0] = LY; - - no_scan = false; - - if (LY == 0 && LY_inc == 0) - { - LY_inc = 1; - in_vblank[0] = false; - - //STAT &= 0xFC; - - // special note here, the y coordiate of the window is kept if the window is deactivated - // meaning it will pick up where it left off if re-enabled later - // so we don't reset it in the scanline loop - window_y_tile = 0; - window_y_latch = window_y; - window_y_tile_inc = 0; - window_started = false; - if (!((LCDC & 0x20) > 0)) { window_is_reset = true; } - } - - // Automatically restore access to VRAM at this time (force end drawing) - // Who Framed Roger Rabbit seems to run into this. - VRAM_access_write = true; - VRAM_access_read = true; - - if (LY == 144) - { - vblank_process(); - } - } - - // exit vblank if LCD went from off to on - if (LCD_was_off) - { - //VBL_INT = false; - in_vblank[0] = false; - LCD_was_off = false; - - // we exit vblank into mode 0 for 4 cycles - // but no hblank interrupt, presumably this only happens transitioning from mode 3 to 0 - STAT &= 0xFC; - - // also the LCD doesn't turn on right away - // also, the LCD does not enter mode 2 on scanline 0 when first turned on - no_scan = true; - cycle = 8; - } - - // the VBL stat is continuously asserted - if (LY >= 144) - { - if (((STAT & 0x10) > 0)) - { - if ((cycle >= 4) && (LY == 144)) - { - VBL_INT = true; - } - else if (LY > 144) - { - VBL_INT = true; - } - } - - if ((cycle == 2) && (LY == 144)) - { - // there is an edge case where a VBL INT is triggered if STAT bit 5 is set - if (((STAT & 0x20) > 0)) { VBL_INT = true; } - } - - if ((cycle == 4) && (LY == 144)) - { - HBL_INT = false; - - // set STAT mode to 1 (VBlank) and interrupt flag if it is enabled - STAT &= 0xFC; - STAT |= 0x01; - - if ((REG_FFFF[0] & 1) > 0) { FlagI[0] = true; } - REG_FF0F[0] |= 0x01; - } - - if ((cycle == 4) && (LY == 144)) - { - if (((STAT & 0x20) > 0)) { VBL_INT = false; } - } - - if ((cycle == 8) && (LY == 153)) - { - LY = 0; - LY_inc = 0; - cpu_LY[0] = LY; - } - } - - if (!in_vblank[0]) - { - if (no_scan) - { - // timings are slightly different if we just turned on the LCD - // there is no mode 2 (presumably it missed the trigger) - if (cycle < 85) - { - if (cycle == 8) - { - // clear the sprite table - for (uint32_t k = 0; k < 10; k++) - { - SL_sprites[k * 4] = 0; - SL_sprites[k * 4 + 1] = 0; - SL_sprites[k * 4 + 2] = 0; - SL_sprites[k * 4 + 3] = 0; - } - - if (LY != LYC) - { - LYC_INT = false; - STAT &= 0xFB; - } - - if ((LY == LYC) && !((STAT & 0x4) > 0)) - { - // set STAT coincidence FLAG and interrupt flag if it is enabled - STAT |= 0x04; - if (((STAT & 0x40) > 0)) { LYC_INT = true; } - } - } - - if (cycle == 84) - { - STAT &= 0xFC; - STAT |= 0x03; - OAM_INT = false; - - OAM_access_read = false; - OAM_access_write = false; - VRAM_access_read = false; - VRAM_access_write = false; - } - } - else - { - if (cycle >= 85) - { - if (cycle == 85) - { - // x-scroll is expected to be latched one cycle later - // this is fine since nothing has started in the rendering until the second cycle - // calculate the column number of the tile to start with - x_tile = (uint32_t)(scroll_x >> 3); - render_offset = scroll_x % 8; - } - - // render the screen and handle hblank - render(cycle - 85); - } - } - } - else - { - if (cycle <= 80) - { - if (cycle == 2) - { - if (LY != 0) - { - HBL_INT = false; - - if (((STAT & 0x20) > 0)) { OAM_INT = true; } - } - } - else if (cycle == 4) - { - // here mode 2 will be set to true and interrupts fired if enabled - STAT &= 0xFC; - STAT |= 0x2; - - if (LY == 0) - { - VBL_INT = false; - if (((STAT & 0x20) > 0)) { OAM_INT = true; } - } - } - - if (cycle == 80) - { - OAM_access_read = false; - OAM_access_write = true; - VRAM_access_read = false; - } - else - { - // here OAM scanning is performed - OAM_scan(cycle); - } - } - else if (cycle >= 83) - { - if (cycle == 84) - { - STAT &= 0xFC; - STAT |= 0x03; - OAM_INT = false; - OAM_access_write = false; - VRAM_access_write = false; - - // x-scroll is expected to be latched one cycle later - // this is fine since nothing has started in the rendering until the second cycle - // calculate the column number of the tile to start with - x_tile = (uint32_t)(scroll_x >> 3); - render_offset = scroll_x % 8; - } - - // render the screen and handle hblank - render(cycle - 83); - } - } - } - - if (LY_inc == 0) - { - if (cycle == 12) - { - LYC_INT = false; - STAT &= 0xFB; - } - else if (cycle == 14) - { - // Special case of LY = LYC - if ((LY == LYC) && !((STAT & 0x4) > 0)) - { - // set STAT coincidence FLAG and interrupt flag if it is enabled - STAT |= 0x04; - if (((STAT & 0x40) > 0)) { LYC_INT = true; } - } - } - } - - // here LY=LYC will be asserted or cleared (but only if LY isnt 0 as that's a special case) - if ((cycle == 4) && (LY != 0)) - { - if (LY_inc == 1) - { - LYC_INT = false; - STAT &= 0xFB; - } - } - else if ((cycle == 6) && (LY != 0)) - { - if ((LY == LYC) && !((STAT & 0x4) > 0)) - { - // set STAT coincidence FLAG and interrupt flag if it is enabled - STAT |= 0x04; - if (((STAT & 0x40) > 0)) { LYC_INT = true; } - } - } - - cycle++; - } - else - { - STAT &= 0xFC; - - VBL_INT = LYC_INT = HBL_INT = OAM_INT = false; - - in_vblank[0] = true; - - LCD_was_off = true; - - LY = 0; - cpu_LY[0] = LY; - - cycle = 0; - } - - // assert the STAT IRQ line if the line went from zero to 1 - stat_line = VBL_INT | LYC_INT | HBL_INT | OAM_INT; - - if (stat_line && !stat_line_old) - { - if ((REG_FFFF[0] & 0x2) > 0) { FlagI[0] = true; } - REG_FF0F[0] |= 0x02; - - //if (LY == 46) - //{ - //Console.Write(VBL_INT + " " + LYC_INT + " " + HBL_INT + " " + OAM_INT + " " + LY + " "); - //Console.Write(render_offset + " " + scroll_x + " " + total_counter + " "); - //Console.WriteLine(STAT + " " + cycle + " " + Core.cpu.TotalExecutedCycles); - //} - } - - stat_line_old = stat_line; - - // process latch delays - //latch_delay(); - - if (LYC_cd > 0) - { - LYC_cd--; - if (LYC_cd == 0) - { - LYC = LYC_t; - - if (((LCDC & 0x80) > 0)) - { - if (LY != LYC) { STAT &= 0xFB; LYC_INT = false; } - else { STAT |= 0x4; LYC_INT = true; } - } - } - } - } - - // might be needed, not sure yet - void latch_delay() - { - //BGP_l = BGP; - } - - void render(uint32_t render_cycle) - { - // we are now in STAT mode 3 - // NOTE: presumably the first necessary sprite is fetched at sprite evaulation - // i.e. just keeping track of the lowest x-value sprite - if (render_cycle == 0) - { - /* - OAM_access_read = false; - OAM_access_write = true; - VRAM_access_read = false; - */ - // window X is latched for the scanline, mid-line changes have no effect - window_x_latch = window_x; - - OAM_scan_index = 0; - read_case = 0; - internal_cycle = 0; - pre_render = true; - pre_render_2 = true; - tile_inc = 0; - pixel_counter = -8; - sl_use_index = 0; - fetch_sprite = false; - going_to_fetch = false; - first_fetch = true; - consecutive_sprite = (int32_t)(render_offset * (-1)) + 8; - no_sprites = false; - evaled_sprites = 0; - window_pre_render = false; - window_latch = ((LCDC & 0x20) > 0); - - total_counter = 0; - - // TODO: If Window is turned on midscanline what happens? When is this check done exactly? - if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY >= window_y_latch))) - { - window_y_tile_inc++; - if (window_y_tile_inc == 8) - { - window_y_tile_inc = 0; - window_y_tile++; - window_y_tile %= 32; - } - } - window_started = false; - - if (SL_sprites_index == 0) { no_sprites = true; } - // it is much easier to process sprites if we order them according to the rules of sprite priority first - if (!no_sprites) { reorder_and_assemble_sprites(); } - } - - // before anything else, we have to check if windowing is in effect - if (window_latch && !window_started && (LY >= window_y_latch) && (pixel_counter >= (int32_t)(window_x_latch - 7)) && (window_x_latch < 167)) - { - /* - Console.Write(LY); - Console.Write(" "); - Console.Write(cycle); - Console.Write(" "); - Console.Write(window_y_tile); - Console.Write(" "); - Console.Write(render_offset); - Console.Write(" "); - Console.Write(window_x_latch); - Console.Write(" "); - Console.WriteLine(pixel_counter); - */ - - if (window_x_latch == 0) - { - // if the window starts at zero, we still do the first access to the BG - // but then restart all over again at the window - if ((render_offset % 7) <= 6) - { - read_case = 9; - } - else - { - read_case = 10; - } - } - else - { - read_case = 4; - } - - window_pre_render = true; - - window_counter = 0; - render_counter = 0; - - // NOTE: pixel counter is >= window_x_latch - 7 here, so subtraction will result in a positive number - window_x_tile = (uint32_t)((pixel_counter - ((int32_t)window_x_latch - 7)) >> 3); - - window_tile_inc = 0; - window_started = true; - window_is_reset = false; - } - - if (!pre_render && !fetch_sprite) - { - // start shifting data into the LCD - if (render_counter >= (render_offset + 8)) - { - if ((tile_data_latch[2] & 0x20) > 0) - { - pixel = (tile_data_latch[0] & (1 << (render_counter % 8))) > 0 ? 1 : 0; - pixel |= (tile_data_latch[1] & (1 << (render_counter % 8))) > 0 ? 2 : 0; - } - else - { - pixel = (tile_data_latch[0] & (1 << (7 - (render_counter % 8)))) > 0 ? 1 : 0; - pixel |= (tile_data_latch[1] & (1 << (7 - (render_counter % 8)))) > 0 ? 2 : 0; - } - - uint32_t ref_pixel = pixel; - - uint32_t pal_num = tile_data_latch[2] & 0x7; - - bool use_sprite = false; - - uint32_t s_pixel = 0; - - // now we have the BG pixel, we next need the sprite pixel - if (!no_sprites) - { - bool have_sprite = false; - uint32_t sprite_attr = 0; - - if (sprite_present_list[pixel_counter] == 1) - { - have_sprite = true; - s_pixel = sprite_pixel_list[pixel_counter]; - sprite_attr = sprite_attr_list[pixel_counter]; - } - - if (have_sprite) - { - if (((LCDC & 0x2) > 0)) - { - if (!((sprite_attr & 0x80) > 0)) - { - use_sprite = true; - } - else if (ref_pixel == 0) - { - use_sprite = true; - } - - if (!((LCDC & 0x1) > 0)) - { - use_sprite = true; - } - - // There is another priority bit in GBC, that can still override sprite priority - if (((LCDC & 0x1) > 0) && ((tile_data_latch[2] & 0x80) > 0) && (ref_pixel != 0)) - { - use_sprite = false; - } - } - - if (use_sprite) - { - pal_num = sprite_attr & 7; - } - } - } - - // based on sprite priority and pixel values, pick a final pixel color - if (use_sprite) - { - _vidbuffer[LY * 160 + pixel_counter] = OBJ_palette[pal_num * 4 + s_pixel]; - } - else - { - _vidbuffer[LY * 160 + pixel_counter] = BG_palette[pal_num * 4 + pixel]; - } - - pixel_counter++; - - if (pixel_counter == 160) - { - read_case = 8; - hbl_countdown = 2; - } - } - else if (pixel_counter < 0) - { - pixel_counter++; - } - render_counter++; - } - - if (!fetch_sprite) - { - if (!pre_render_2) - { - // before we go on to read case 3, we need to know if we stall there or not - // Gekkio's tests show that if sprites are at position 0 or 1 (mod 8) - // then it takes an extra cycle (1 or 2 more t-states) to process them - - if (!no_sprites && (pixel_counter < 160)) - { - for (uint32_t i = 0; i < SL_sprites_index; i++) - { - if ((pixel_counter >= (int32_t)(SL_sprites[i * 4 + 1] - 8)) && - (pixel_counter < (int32_t)(SL_sprites[i * 4 + 1])) && - !((evaled_sprites & (1 << i)) > 0)) - { - going_to_fetch = true; - fetch_sprite = true; - } - } - } - } - - switch (read_case) - { - case 0: // read a background tile - if ((internal_cycle % 2) == 1) - { - // calculate the row number of the tiles to be fetched - y_tile = ((uint32_t)((uint32_t)scroll_y + (uint32_t)LY) >> 3) % 32; - - temp_fetch = y_tile * 32 + (x_tile + tile_inc) % 32; - tile_byte = VRAM[0x1800 + (((LCDC & 0x8) > 0) ? 1 : 0) * 0x400 + temp_fetch]; - tile_data[2] = VRAM[0x3800 + (((LCDC & 0x8) > 0) ? 1 : 0) * 0x400 + temp_fetch]; - VRAM_sel = ((tile_data[2] & 0x8) > 0) ? 1 : 0; - - BG_V_flip = ((tile_data[2] & 0x40) > 0); - - read_case = 1; - if (!pre_render) - { - tile_inc++; - } - } - break; - - case 1: // read from tile graphics (0) - if ((internal_cycle % 2) == 1) - { - y_scroll_offset = (scroll_y + LY) % 8; - - if (BG_V_flip) - { - y_scroll_offset = 7 - y_scroll_offset; - } - - if (((LCDC & 0x10) > 0)) - { - tile_data[0] = VRAM[(VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2]; - } - else - { - // same as before except now tile uint8_t represents a signed byte - if (((tile_byte & 0x80) > 0)) - { - tile_byte -= 256; - } - tile_data[0] = VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2]; - } - - read_case = 2; - } - break; - - case 2: // read from tile graphics (1) - if ((internal_cycle % 2) == 0) - { - pre_render_2 = false; - } - else - { - y_scroll_offset = (scroll_y + LY) % 8; - - if (BG_V_flip) - { - y_scroll_offset = 7 - y_scroll_offset; - } - - if (((LCDC & 0x10) > 0)) - { - // if LCDC somehow changed between the two reads, make sure we have a positive number - if (tile_byte < 0) - { - tile_byte += 256; - } - tile_data[1] = VRAM[(VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1]; - } - else - { - // same as before except now tile uint8_t represents a signed byte - if (((tile_byte & 0x80) > 0) && tile_byte > 0) - { - tile_byte -= 256; - } - tile_data[1] = VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1]; - } - - if (pre_render) - { - // here we set up rendering - pre_render = false; - - render_counter = 0; - latch_counter = 0; - read_case = 0; - } - else - { - read_case = 3; - } - } - break; - - case 3: // read from sprite data - if ((internal_cycle % 2) == 1) - { - read_case = 0; - latch_new_data = true; - } - break; - - case 4: // read from window data - if ((window_counter % 2) == 1) - { - temp_fetch = window_y_tile * 32 + (window_x_tile + window_tile_inc) % 32; - tile_byte = VRAM[0x1800 + (((LCDC & 0x40) > 0) ? 1 : 0) * 0x400 + temp_fetch]; - tile_data[2] = VRAM[0x3800 + (((LCDC & 0x40) > 0) ? 1 : 0) * 0x400 + temp_fetch]; - VRAM_sel = ((tile_data[2] & 0x8) > 0) ? 1 : 0; - BG_V_flip = ((tile_data[2] & 0x40) > 0); - - window_tile_inc++; - read_case = 5; - } - window_counter++; - break; - - case 5: // read from tile graphics (for the window) - if ((window_counter % 2) == 1) - { - y_scroll_offset = (window_y_tile_inc) % 8; - - if (BG_V_flip) - { - y_scroll_offset = 7 - y_scroll_offset; - } - - if (((LCDC & 0x10) > 0)) - { - tile_data[0] = VRAM[(VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2]; - } - else - { - // same as before except now tile uint8_t represents a signed byte - if (((tile_byte & 0x80) > 0)) - { - tile_byte -= 256; - } - tile_data[0] = VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2]; - } - - read_case = 6; - } - window_counter++; - break; - - case 6: // read from tile graphics (for the window) - if ((window_counter % 2) == 1) - { - y_scroll_offset = (window_y_tile_inc) % 8; - - if (BG_V_flip) - { - y_scroll_offset = 7 - y_scroll_offset; - } - - if (((LCDC & 0x10) > 0)) - { - // if LCDC somehow changed between the two reads, make sure we have a positive number - if (tile_byte < 0) - { - tile_byte += 256; - } - tile_data[1] = VRAM[(VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1]; - } - else - { - // same as before except now tile uint8_t represents a signed byte - if (((tile_byte & 0x80) > 0) && tile_byte > 0) - { - tile_byte -= 256; - } - tile_data[1] = VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1]; - } - - if (window_pre_render) - { - // here we set up rendering - // unlike for the normal background case, there is no pre-render period for the window - // so start shifting in data to the screen right away - if (window_x_latch <= 7) - { - if (render_offset == 0) - { - read_case = 4; - } - else - { - read_case = 9 + render_offset - 1; - } - render_counter = 8 - render_offset; - - render_offset = 7 - window_x_latch; - } - else - { - render_offset = 0; - read_case = 4; - render_counter = 8; - } - - latch_counter = 0; - latch_new_data = true; - window_pre_render = false; - } - else - { - read_case = 7; - } - } - window_counter++; - break; - - case 7: // read from sprite data - if ((window_counter % 2) == 1) - { - read_case = 4; - latch_new_data = true; - } - window_counter++; - break; - - case 8: // done reading, we are now in phase 0 - pre_render = true; - - // the other interrupts appear to be delayed by 1 CPU cycle, so do the same here - if (hbl_countdown > 0) - { - hbl_countdown--; - - if (hbl_countdown == 0) - { - OAM_access_read = true; - OAM_access_write = true; - VRAM_access_read = true; - VRAM_access_write = true; - } - else - { - STAT &= 0xFC; - STAT |= 0x00; - - if (((STAT & 0x8) > 0)) { HBL_INT = true; } - } - } - break; - - case 9: - // this is a degenerate case for starting the window at 0 - // kevtris' timing doc indicates an additional normal BG access - // but this information is thrown away, so it's faster to do this then constantly check - // for it in read case 0 - read_case = 4; - break; - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - read_case--; - break; - } - internal_cycle++; - - if (latch_new_data) - { - latch_new_data = false; - tile_data_latch[0] = tile_data[0]; - tile_data_latch[1] = tile_data[1]; - tile_data_latch[2] = tile_data[2]; - } - } - - // every in range sprite takes 6 cycles to process - // sprites located at x=0 still take 6 cycles to process even though they don't appear on screen - // sprites above x=168 do not take any cycles to process however - if (fetch_sprite) - { - if (going_to_fetch) - { - going_to_fetch = false; - - last_eval = 0; - - // at this time it is unknown what each cycle does, but we only need to accurately keep track of cycles - for (uint32_t i = 0; i < SL_sprites_index; i++) - { - if ((pixel_counter >= (int32_t)(SL_sprites[i * 4 + 1] - 8)) && - (pixel_counter < (int32_t)(SL_sprites[i * 4 + 1])) && - !((evaled_sprites & (1 << i)) > 0)) - { - sprite_fetch_counter += 6; - evaled_sprites |= (1 << i); - last_eval = SL_sprites[i * 4 + 1]; - } - } - - // x scroll offsets the penalty table - // there is no penalty if the next sprites to be fetched are within the currentfetch block (8 pixels) - if (first_fetch || ((int32_t)last_eval >= consecutive_sprite)) - { - if (((last_eval + render_offset) % 8) == 0) { sprite_fetch_counter += 5; } - else if (((last_eval + render_offset) % 8) == 1) { sprite_fetch_counter += 4; } - else if (((last_eval + render_offset) % 8) == 2) { sprite_fetch_counter += 3; } - else if (((last_eval + render_offset) % 8) == 3) { sprite_fetch_counter += 2; } - else if (((last_eval + render_offset) % 8) == 4) { sprite_fetch_counter += 1; } - else if (((last_eval + render_offset) % 8) == 5) { sprite_fetch_counter += 0; } - else if (((last_eval + render_offset) % 8) == 6) { sprite_fetch_counter += 0; } - else if (((last_eval + render_offset) % 8) == 7) { sprite_fetch_counter += 0; } - - consecutive_sprite = (uint32_t)(((last_eval + render_offset) >> 3) << 3) + 8 - render_offset; - - // special case exists here for sprites at zero with non-zero x-scroll. Not sure exactly the reason for it. - if (last_eval == 0 && render_offset != 0) - { - sprite_fetch_counter += render_offset; - } - } - - total_counter += sprite_fetch_counter; - - first_fetch = false; - } - else - { - sprite_fetch_counter--; - if (sprite_fetch_counter == 0) - { - fetch_sprite = false; - } - } - } - - } - - void process_sprite() - { - uint32_t y; - uint32_t VRAM_temp = ((SL_sprites[sl_use_index * 4 + 3] & 0x8) > 0) ? 1 : 0; - - if ((SL_sprites[sl_use_index * 4 + 3] & 0x40) > 0) - { - if (((LCDC & 0x4) > 0)) - { - y = LY - (SL_sprites[sl_use_index * 4] - 16); - y = 15 - y; - sprite_sel[0] = VRAM[(VRAM_temp * 0x2000) + (SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2]; - sprite_sel[1] = VRAM[(VRAM_temp * 0x2000) + (SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2 + 1]; - } - else - { - y = LY - (SL_sprites[sl_use_index * 4] - 16); - y = 7 - y; - sprite_sel[0] = VRAM[(VRAM_temp * 0x2000) + SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2]; - sprite_sel[1] = VRAM[(VRAM_temp * 0x2000) + SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2 + 1]; - } - } - else - { - if (((LCDC & 0x4) > 0)) - { - y = LY - (SL_sprites[sl_use_index * 4] - 16); - sprite_sel[0] = VRAM[(VRAM_temp * 0x2000) + (SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2]; - sprite_sel[1] = VRAM[(VRAM_temp * 0x2000) + (SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2 + 1]; - } - else - { - y = LY - (SL_sprites[sl_use_index * 4] - 16); - sprite_sel[0] = VRAM[(VRAM_temp * 0x2000) + SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2]; - sprite_sel[1] = VRAM[(VRAM_temp * 0x2000) + SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2 + 1]; - } - } - - if ((SL_sprites[sl_use_index * 4 + 3] & 0x20) > 0) - { - uint32_t b0, b1, b2, b3, b4, b5, b6, b7 = 0; - for (uint32_t i = 0; i < 2; i++) - { - b0 = (sprite_sel[i] & 0x01) << 7; - b1 = (sprite_sel[i] & 0x02) << 5; - b2 = (sprite_sel[i] & 0x04) << 3; - b3 = (sprite_sel[i] & 0x08) << 1; - b4 = (sprite_sel[i] & 0x10) >> 1; - b5 = (sprite_sel[i] & 0x20) >> 3; - b6 = (sprite_sel[i] & 0x40) >> 5; - b7 = (sprite_sel[i] & 0x80) >> 7; - - sprite_sel[i] = (uint8_t)(b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7); - } - } - } - - // order sprites according to x coordinate - // note that for sprites of equal x coordinate, priority goes to first on the list - void reorder_and_assemble_sprites() - { - sprite_ordered_index = 0; - - // In CGB mode, sprites are ordered solely based on their position in OAM, so they are already ordered - for (uint32_t j = 0; j < SL_sprites_index; j++) - { - sl_use_index = j; - process_sprite(); - SL_sprites_ordered[sprite_ordered_index * 4] = SL_sprites[j * 4 + 1]; - SL_sprites_ordered[sprite_ordered_index * 4 + 1] = sprite_sel[0]; - SL_sprites_ordered[sprite_ordered_index * 4 + 2] = sprite_sel[1]; - SL_sprites_ordered[sprite_ordered_index * 4 + 3] = SL_sprites[j * 4 + 3]; - sprite_ordered_index++; - } - - bool have_pixel = false; - uint8_t s_pixel = 0; - uint8_t sprite_attr = 0; - - for (uint32_t i = 0; i < 160; i++) - { - have_pixel = false; - for (uint32_t j = 0; j < SL_sprites_index; j++) - { - if ((i >= (SL_sprites_ordered[j * 4] - 8)) && - (i < SL_sprites_ordered[j * 4]) && - !have_pixel) - { - // we can use the current sprite, so pick out a pixel for it - uint32_t t_index = i - (SL_sprites_ordered[j * 4] - 8); - - t_index = 7 - t_index; - - sprite_data[0] = (uint8_t)((SL_sprites_ordered[j * 4 + 1] >> t_index) & 1); - sprite_data[1] = (uint8_t)(((SL_sprites_ordered[j * 4 + 2] >> t_index) & 1) << 1); - - s_pixel = (uint8_t)(sprite_data[0] + sprite_data[1]); - sprite_attr = (uint8_t)SL_sprites_ordered[j * 4 + 3]; - - // pixel color of 0 is transparent, so if this is the case we don't have a pixel - if (s_pixel != 0) - { - have_pixel = true; - } - } - } - - if (have_pixel) - { - sprite_present_list[i] = 1; - sprite_pixel_list[i] = s_pixel; - sprite_attr_list[i] = sprite_attr; - } - else - { - sprite_present_list[i] = 0; - } - } - } - - void OAM_scan(uint32_t OAM_cycle) - { - // we are now in STAT mode 2 - // TODO: maybe stat mode 2 flags are set at cycle 0 on visible scanlines? - if (OAM_cycle == 0) - { - OAM_access_read = false; - OAM_access_write = false; - - OAM_scan_index = 0; - SL_sprites_index = 0; - write_sprite = 0; - } - - // the gameboy has 80 cycles to scan through 40 sprites, picking out the first 10 it finds to draw - // the following is a guessed at implmenentation based on how NES does it, it's probably pretty close - if (OAM_cycle < 10) - { - // start by clearing the sprite table (probably just clears X on hardware, but let's be safe here.) - SL_sprites[OAM_cycle * 4] = 0; - SL_sprites[OAM_cycle * 4 + 1] = 0; - SL_sprites[OAM_cycle * 4 + 2] = 0; - SL_sprites[OAM_cycle * 4 + 3] = 0; - } - else - { - if (write_sprite == 0) - { - if (OAM_scan_index < 40) - { - int32_t temp = DMA_OAM_access ? OAM[OAM_scan_index * 4] : (int32_t)0xFF; - // (sprite Y - 16) equals LY, we have a sprite - if ((temp - 16) <= LY && - ((temp - 16) + 8 + (((LCDC & 0x4) > 0) ? 8 : 0)) > LY) - { - // always pick the first 10 in range sprites - if (SL_sprites_index < 10) - { - SL_sprites[SL_sprites_index * 4] = temp; - - write_sprite = 1; - } - else - { - // if we already have 10 sprites, there's nothing to do, increment the index - OAM_scan_index++; - } - } - else - { - OAM_scan_index++; - } - } - } - else - { - uint32_t temp2 = DMA_OAM_access ? OAM[OAM_scan_index * 4 + write_sprite] : (uint32_t)0xFF; - SL_sprites[SL_sprites_index * 4 + write_sprite] = temp2; - write_sprite++; - - if (write_sprite == 4) - { - write_sprite = 0; - SL_sprites_index++; - OAM_scan_index++; - } - } - } - } - - void Reset() - { - LCDC = 0; - STAT = 0x80; - scroll_y = 0; - scroll_x = 0; - LY = 0; - LYC = 0; - DMA_addr = 0; - BGP = 0xFF; - obj_pal_0 = 0; - obj_pal_1 = 0; - window_y = 0x0; - window_x = 0x0; - window_x_latch = 0xFF; - window_y_latch = 0xFF; - LY_inc = 1; - no_scan = false; - OAM_access_read = true; - VRAM_access_read = true; - OAM_access_write = true; - VRAM_access_write = true; - DMA_OAM_access = true; - - cycle = 0; - LYC_INT = false; - HBL_INT = false; - VBL_INT = false; - OAM_INT = false; - - stat_line = false; - stat_line_old = false; - - window_counter = 0; - window_pre_render = false; - window_started = false; - window_tile_inc = 0; - window_y_tile = 0; - window_x_tile = 0; - window_y_tile_inc = 0; - - BG_bytes_inc = false; - OBJ_bytes_inc = false; - BG_bytes_index = 0; - OBJ_bytes_index = 0; - BG_transfer_byte = 0; - OBJ_transfer_byte = 0; - - HDMA_src_hi = 0; - HDMA_src_lo = 0; - HDMA_dest_hi = 0; - HDMA_dest_lo = 0; - - VRAM_sel = 0; - BG_V_flip = false; - HDMA_active = false; - HDMA_mode = false; - cur_DMA_src = 0; - cur_DMA_dest = 0; - HDMA_length = 0; - HDMA_countdown = 0; - HBL_HDMA_count = 0; - last_HBL = 0; - HBL_HDMA_go = false; - HBL_test = false; - } - - }; - - #pragma endregion - - #pragma region GBC_GB_PPU - - class GBC_GB_PPU : public PPU - { - public: - uint8_t ReadReg(uint32_t addr) - { - uint8_t ret = 0; - //Console.WriteLine(Core.cpu.TotalExecutedCycles); - switch (addr) - { - case 0xFF40: ret = LCDC; break; // LCDC - case 0xFF41: ret = STAT; break; // STAT - case 0xFF42: ret = scroll_y; break; // SCY - case 0xFF43: ret = scroll_x; break; // SCX - case 0xFF44: ret = LY; break; // LY - case 0xFF45: ret = LYC; break; // LYC - case 0xFF46: ret = DMA_addr; break; // DMA - case 0xFF47: ret = BGP; break; // BGP - case 0xFF48: ret = obj_pal_0; break; // OBP0 - case 0xFF49: ret = obj_pal_1; break; // OBP1 - case 0xFF4A: ret = window_y; break; // WY - case 0xFF4B: ret = window_x; break; // WX - - // These are GBC specific Regs - case 0xFF51: ret = HDMA_src_hi; break; // HDMA1 - case 0xFF52: ret = HDMA_src_lo; break; // HDMA2 - case 0xFF53: ret = HDMA_dest_hi; break; // HDMA3 - case 0xFF54: ret = HDMA_dest_lo; break; // HDMA4 - case 0xFF55: ret = HDMA_ctrl(); break; // HDMA5 - case 0xFF68: ret = BG_pal_ret(); break; // BGPI - case 0xFF69: ret = BG_PAL_read(); break; // BGPD - case 0xFF6A: ret = OBJ_pal_ret(); break; // OBPI - case 0xFF6B: ret = OBJ_bytes[OBJ_bytes_index]; break; // OBPD - } - - return ret; - } - - void WriteReg(uint32_t addr, uint8_t value) - { - switch (addr) - { - case 0xFF40: // LCDC - if (((LCDC & 0x80) > 0) && !((value & 0x80) > 0)) - { - VRAM_access_read = true; - VRAM_access_write = true; - OAM_access_read = true; - OAM_access_write = true; - - clear_screen = true; - } - - if (!((LCDC & 0x80) > 0) && ((value & 0x80) > 0)) - { - // don't draw for one frame after turning on - blank_frame = true; - } - - LCDC = value; - break; - case 0xFF41: // STAT - // note that their is no stat interrupt bug in GBC - STAT = (uint8_t)((value & 0xF8) | (STAT & 7) | 0x80); - - if (((STAT & 3) == 0) && ((STAT & 0x8) > 0)) { HBL_INT = true; } - else { HBL_INT = false; } - if (((STAT & 3) == 1) && ((STAT & 0x10) > 0)) { VBL_INT = true; } - else { VBL_INT = false; } - // OAM not triggered? - // if (((STAT & 3) == 2) && STAT.Bit(5)) { OAM_INT = true; } else { OAM_INT = false; } - - if (((value & 0x40) > 0) && ((LCDC & 0x80) > 0)) - { - if (LY == LYC) { LYC_INT = true; } - else { LYC_INT = false; } - } - if (!((STAT & 0x40) > 0)) { LYC_INT = false; } - break; - case 0xFF42: // SCY - scroll_y = value; - break; - case 0xFF43: // SCX - scroll_x = value; - break; - case 0xFF44: // LY - LY = 0; /*reset*/ - break; - case 0xFF45: // LYC - // tests indicate that latching writes to LYC should take place 4 cycles after the write - // otherwise tests around LY boundaries will fail - LYC_t = value; - LYC_cd = 4; - break; - case 0xFF46: // DMA - DMA_addr = value; - DMA_start = true; - DMA_OAM_access = true; - DMA_clock = 0; - DMA_inc = 0; - break; - case 0xFF47: // BGP - BGP = value; - break; - case 0xFF48: // OBP0 - obj_pal_0 = value; - break; - case 0xFF49: // OBP1 - obj_pal_1 = value; - break; - case 0xFF4A: // WY - window_y = value; - break; - case 0xFF4B: // WX - window_x = value; - break; - - // These are GBC specific Regs - case 0xFF51: // HDMA1 - HDMA_src_hi = value; - cur_DMA_src = (uint32_t)(((HDMA_src_hi & 0xFF) << 8) | (cur_DMA_src & 0xF0)); - break; - case 0xFF52: // HDMA2 - HDMA_src_lo = value; - cur_DMA_src = (uint32_t)((cur_DMA_src & 0xFF00) | (HDMA_src_lo & 0xF0)); - break; - case 0xFF53: // HDMA3 - HDMA_dest_hi = value; - cur_DMA_dest = (uint32_t)(((HDMA_dest_hi & 0x1F) << 8) | (cur_DMA_dest & 0xF0)); - break; - case 0xFF54: // HDMA4 - HDMA_dest_lo = value; - cur_DMA_dest = (uint32_t)((cur_DMA_dest & 0xFF00) | (HDMA_dest_lo & 0xF0)); - break; - case 0xFF55: // HDMA5 - if (!HDMA_active) - { - HDMA_mode = ((value & 0x80) > 0); - HDMA_countdown = 4; - HDMA_tick = 0; - if (((value & 0x80) > 0)) - { - // HDMA during HBlank only, but only if screen is on, otherwise DMA immediately one block of data - // worms armaggedon requires HDMA to fire in hblank mode even if the screen is off. - HDMA_active = true; - HBL_HDMA_count = 0x10; - - last_HBL = LY - 1; - - HBL_test = true; - HBL_HDMA_go = false; - - if (!((LCDC & 0x80) > 0)) - { - HDMA_run_once = true; - } - } - else - { - // HDMA immediately - HDMA_active = true; - HDMA_transfer[0] = true; - } - - HDMA_length = ((value & 0x7F) + 1) * 16; - } - else - { - //terminate the transfer - if (!((value & 0x80) > 0)) - { - HDMA_active = false; - } - } - - break; - case 0xFF68: // BGPI - BG_bytes_index = (uint8_t)(value & 0x3F); - BG_bytes_inc = ((value & 0x80) == 0x80); - break; - case 0xFF69: // BGPD - if (VRAM_access_write) - { - BG_transfer_byte = value; - BG_bytes[BG_bytes_index] = value; - } - - // change the appropriate palette color - color_compute_BG(); - if (BG_bytes_inc) { BG_bytes_index++; BG_bytes_index &= 0x3F; } - break; - case 0xFF6A: // OBPI - OBJ_bytes_index = (uint8_t)(value & 0x3F); - OBJ_bytes_inc = ((value & 0x80) == 0x80); - break; - case 0xFF6B: // OBPD - OBJ_transfer_byte = value; - OBJ_bytes[OBJ_bytes_index] = value; - - // change the appropriate palette color - color_compute_OBJ(); - - if (OBJ_bytes_inc) { OBJ_bytes_index++; OBJ_bytes_index &= 0x3F; } - break; - } - } - - void tick() - { - // Do HDMA ticks - if (HDMA_active) - { - if (HDMA_length > 0) - { - if (!HDMA_mode) - { - if (HDMA_countdown > 0) - { - HDMA_countdown--; - } - else - { - // immediately transfer bytes, 2 bytes per cycles - if ((HDMA_tick % 2) == 0) - { - HDMA_byte = ReadMemory(cur_DMA_src); - } - else - { - VRAM[(VRAM_Bank[0] * 0x2000) + cur_DMA_dest] = HDMA_byte; - cur_DMA_dest = (uint32_t)((cur_DMA_dest + 1) & 0x1FFF); - cur_DMA_src = (uint32_t)((cur_DMA_src + 1) & 0xFFFF); - HDMA_length--; - } - - HDMA_tick++; - } - } - else - { - // only transfer during mode 0, and only 16 bytes at a time - if (((STAT & 3) == 0) && (LY != last_HBL) && HBL_test && (LY_inc == 1) && (cycle > 4)) - { - HBL_HDMA_go = true; - HBL_test = false; - } - else if (HDMA_run_once) - { - HBL_HDMA_go = true; - HBL_test = false; - HDMA_run_once = false; - } - - if (HBL_HDMA_go && (HBL_HDMA_count > 0)) - { - HDMA_transfer[0] = true; - - if (HDMA_countdown > 0) - { - HDMA_countdown--; - } - else - { - if ((HDMA_tick % 2) == 0) - { - HDMA_byte = ReadMemory(cur_DMA_src); - } - else - { - VRAM[(VRAM_Bank[0] * 0x2000) + cur_DMA_dest] = HDMA_byte; - cur_DMA_dest = (uint32_t)((cur_DMA_dest + 1) & 0x1FFF); - cur_DMA_src = (uint32_t)((cur_DMA_src + 1) & 0xFFFF); - HDMA_length--; - HBL_HDMA_count--; - } - - if ((HBL_HDMA_count == 0) && (HDMA_length != 0)) - { - - HBL_test = true; - last_HBL = LY; - HBL_HDMA_count = 0x10; - HBL_HDMA_go = false; - HDMA_countdown = 4; - } - - HDMA_tick++; - } - } - else - { - HDMA_transfer[0] = false; - } - } - } - else - { - HDMA_active = false; - HDMA_transfer[0] = false; - } - } - - // the ppu only does anything if it is turned on via bit 7 of LCDC - if (((LCDC & 0x80) > 0)) - { - // start the next scanline - if (cycle == 456) - { - // scanline callback - if ((LY + LY_inc) == _scanlineCallbackLine[0]) - { - if (scanlineCallback) - { - scanlineCallback(); - } - } - - cycle = 0; - LY += LY_inc; - cpu_LY[0] = LY; - - no_scan = false; - - if (LY == 0 && LY_inc == 0) - { - LY_inc = 1; - in_vblank[0] = false; - - //STAT &= 0xFC; - - // special note here, the y coordiate of the window is kept if the window is deactivated - // meaning it will pick up where it left off if re-enabled later - // so we don't reset it in the scanline loop - window_y_tile = 0; - window_y_latch = window_y; - window_y_tile_inc = 0; - window_started = false; - if (!((LCDC & 0x20) > 0)) { window_is_reset = true; } - } - - // Automatically restore access to VRAM at this time (force end drawing) - // Who Framed Roger Rabbit seems to run into this. - VRAM_access_write = true; - VRAM_access_read = true; - - if (LY == 144) - { - vblank_process(); - } - } - - // exit vblank if LCD went from off to on - if (LCD_was_off) - { - //VBL_INT = false; - in_vblank[0] = false; - LCD_was_off = false; - - // we exit vblank into mode 0 for 4 cycles - // but no hblank interrupt, presumably this only happens transitioning from mode 3 to 0 - STAT &= 0xFC; - - // also the LCD doesn't turn on right away - // also, the LCD does not enter mode 2 on scanline 0 when first turned on - no_scan = true; - cycle = 8; - } - - // the VBL stat is continuously asserted - if (LY >= 144) - { - if (((STAT & 0x10) > 0)) - { - if ((cycle >= 4) && (LY == 144)) - { - VBL_INT = true; - } - else if (LY > 144) - { - VBL_INT = true; - } - } - - if ((cycle == 2) && (LY == 144)) - { - // there is an edge case where a VBL INT is triggered if STAT bit 5 is set - if (((STAT & 0x20) > 0)) { VBL_INT = true; } - } - - if ((cycle == 4) && (LY == 144)) - { - HBL_INT = false; - - // set STAT mode to 1 (VBlank) and interrupt flag if it is enabled - STAT &= 0xFC; - STAT |= 0x01; - - if ((REG_FFFF[0] & 1) > 0) { FlagI[0] = true; } - REG_FF0F[0] |= 0x01; - } - - if ((cycle == 4) && (LY == 144)) - { - if (((STAT & 0x20) > 0)) { VBL_INT = false; } - } - - if ((cycle == 8) && (LY == 153)) - { - LY = 0; - LY_inc = 0; - cpu_LY[0] = LY; - } - } - - if (!in_vblank[0]) - { - if (no_scan) - { - // timings are slightly different if we just turned on the LCD - // there is no mode 2 (presumably it missed the trigger) - if (cycle < 85) - { - if (cycle == 8) - { - // clear the sprite table - for (uint32_t k = 0; k < 10; k++) - { - SL_sprites[k * 4] = 0; - SL_sprites[k * 4 + 1] = 0; - SL_sprites[k * 4 + 2] = 0; - SL_sprites[k * 4 + 3] = 0; - } - - if (LY != LYC) - { - LYC_INT = false; - STAT &= 0xFB; - } - - if ((LY == LYC) && !((STAT & 0x4) > 0)) - { - // set STAT coincidence FLAG and interrupt flag if it is enabled - STAT |= 0x04; - if (((STAT & 0x40) > 0)) { LYC_INT = true; } - } - } - - if (cycle == 84) - { - STAT &= 0xFC; - STAT |= 0x03; - OAM_INT = false; - - OAM_access_read = false; - OAM_access_write = false; - VRAM_access_read = false; - VRAM_access_write = false; - } - } - else - { - if (cycle >= 85) - { - if (cycle == 85) - { - // x-scroll is expected to be latched one cycle later - // this is fine since nothing has started in the rendering until the second cycle - // calculate the column number of the tile to start with - x_tile = (uint32_t)(scroll_x >> 3); - render_offset = scroll_x % 8; - } - - // render the screen and handle hblank - render(cycle - 85); - } - } - } - else - { - if (cycle <= 80) - { - if (cycle == 2) - { - if (LY != 0) - { - HBL_INT = false; - - if (((STAT & 0x20) > 0)) { OAM_INT = true; } - } - } - else if (cycle == 4) - { - // here mode 2 will be set to true and interrupts fired if enabled - STAT &= 0xFC; - STAT |= 0x2; - - if (LY == 0) - { - VBL_INT = false; - if (((STAT & 0x20) > 0)) { OAM_INT = true; } - } - } - - if (cycle == 80) - { - OAM_access_read = false; - OAM_access_write = true; - VRAM_access_read = false; - } - else - { - // here OAM scanning is performed - OAM_scan(cycle); - } - } - else if (cycle >= 83) - { - if (cycle == 84) - { - STAT &= 0xFC; - STAT |= 0x03; - OAM_INT = false; - OAM_access_write = false; - VRAM_access_write = false; - - // x-scroll is expected to be latched one cycle later - // this is fine since nothing has started in the rendering until the second cycle - // calculate the column number of the tile to start with - x_tile = (uint32_t)(scroll_x >> 3); - render_offset = scroll_x % 8; - } - - // render the screen and handle hblank - render(cycle - 83); - } - } - } - - if (LY_inc == 0) - { - if (cycle == 12) - { - LYC_INT = false; - STAT &= 0xFB; - } - else if (cycle == 14) - { - // Special case of LY = LYC - if ((LY == LYC) && !((STAT & 0x4) > 0)) - { - // set STAT coincidence FLAG and interrupt flag if it is enabled - STAT |= 0x04; - if (((STAT & 0x40) > 0)) { LYC_INT = true; } - } - } - } - - // here LY=LYC will be asserted or cleared (but only if LY isnt 0 as that's a special case) - if ((cycle == 4) && (LY != 0)) - { - if (LY_inc == 1) - { - LYC_INT = false; - STAT &= 0xFB; - } - } - else if ((cycle == 6) && (LY != 0)) - { - if ((LY == LYC) && !((STAT & 0x4) > 0)) - { - // set STAT coincidence FLAG and interrupt flag if it is enabled - STAT |= 0x04; - if (((STAT & 0x40) > 0)) { LYC_INT = true; } - } - } - - cycle++; - } - else - { - STAT &= 0xFC; - - VBL_INT = LYC_INT = HBL_INT = OAM_INT = false; - - in_vblank[0] = true; - - LCD_was_off = true; - - LY = 0; - cpu_LY[0] = LY; - - cycle = 0; - } - - // assert the STAT IRQ line if the line went from zero to 1 - stat_line = VBL_INT | LYC_INT | HBL_INT | OAM_INT; - - if (stat_line && !stat_line_old) - { - if ((REG_FFFF[0] & 0x2) > 0) { FlagI[0] = true; } - REG_FF0F[0] |= 0x02; - } - - stat_line_old = stat_line; - - // process latch delays - //latch_delay(); - - if (LYC_cd > 0) - { - LYC_cd--; - if (LYC_cd == 0) - { - LYC = LYC_t; - - if (((LCDC & 0x80) > 0)) - { - if (LY != LYC) { STAT &= 0xFB; LYC_INT = false; } - else { STAT |= 0x4; LYC_INT = true; } - } - } - } - } - - // might be needed, not sure yet - void latch_delay() - { - //BGP_l = BGP; - } - - void render(uint32_t render_cycle) - { - // we are now in STAT mode 3 - // NOTE: presumably the first necessary sprite is fetched at sprite evaulation - // i.e. just keeping track of the lowest x-value sprite - if (render_cycle == 0) - { - /* - OAM_access_read = false; - OAM_access_write = true; - VRAM_access_read = false; - */ - // window X is latched for the scanline, mid-line changes have no effect - window_x_latch = window_x; - - OAM_scan_index = 0; - read_case = 0; - internal_cycle = 0; - pre_render = true; - pre_render_2 = true; - tile_inc = 0; - pixel_counter = -8; - sl_use_index = 0; - fetch_sprite = false; - going_to_fetch = false; - first_fetch = true; - consecutive_sprite = (int32_t)(render_offset * (-1)) + 8; - no_sprites = false; - evaled_sprites = 0; - window_pre_render = false; - window_latch = ((LCDC & 0x20) > 0); - - total_counter = 0; - - // TODO: If Window is turned on midscanline what happens? When is this check done exactly? - if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY >= window_y_latch))) - { - window_y_tile_inc++; - if (window_y_tile_inc == 8) - { - window_y_tile_inc = 0; - window_y_tile++; - window_y_tile %= 32; - } - } - window_started = false; - - if (SL_sprites_index == 0) { no_sprites = true; } - // it is much easier to process sprites if we order them according to the rules of sprite priority first - if (!no_sprites) { reorder_and_assemble_sprites(); } - } - - // before anything else, we have to check if windowing is in effect - if (window_latch && !window_started && (LY >= window_y_latch) && (pixel_counter >= (int32_t)(window_x_latch - 7)) && (window_x_latch < 167)) - { - /* - Console.Write(LY); - Console.Write(" "); - Console.Write(cycle); - Console.Write(" "); - Console.Write(window_y_tile); - Console.Write(" "); - Console.Write(render_offset); - Console.Write(" "); - Console.Write(window_x_latch); - Console.Write(" "); - Console.WriteLine(pixel_counter); - */ - - if (window_x_latch == 0) - { - // if the window starts at zero, we still do the first access to the BG - // but then restart all over again at the window - if ((render_offset % 7) <= 6) - { - read_case = 9; - } - else - { - read_case = 10; - } - } - else - { - read_case = 4; - } - - window_pre_render = true; - - window_counter = 0; - render_counter = 0; - - // NOTE: pixel counter is >= window_x_latch - 7 here, so subtraction will result in a positive number - window_x_tile = (uint32_t)((pixel_counter - ((int32_t)window_x_latch - 7)) >> 3); - - window_tile_inc = 0; - window_started = true; - window_is_reset = false; - } - - if (!pre_render && !fetch_sprite) - { - // start shifting data into the LCD - if (render_counter >= (render_offset + 8)) - { - if (((tile_data_latch[2] & 0x20) > 0) && GBC_compat[0]) - { - pixel = (tile_data_latch[0] & (1 << (render_counter % 8))) > 0 ? 1 : 0; - pixel |= (tile_data_latch[1] & (1 << (render_counter % 8))) > 0 ? 2 : 0; - } - else - { - pixel = (tile_data_latch[0] & (1 << (7 - (render_counter % 8)))) > 0 ? 1 : 0; - pixel |= (tile_data_latch[1] & (1 << (7 - (render_counter % 8)))) > 0 ? 2 : 0; - } - - uint32_t ref_pixel = pixel; - - if (!GBC_compat[0]) - { - if (((LCDC & 0x1) > 0)) - { - pixel = (BGP >> (pixel * 2)) & 3; - } - else - { - pixel = 0; - } - } - - uint32_t pal_num = tile_data_latch[2] & 0x7; - - bool use_sprite = false; - - uint32_t s_pixel = 0; - - // now we have the BG pixel, we next need the sprite pixel - if (!no_sprites) - { - bool have_sprite = false; - uint32_t sprite_attr = 0; - - if (sprite_present_list[pixel_counter] == 1) - { - have_sprite = true; - s_pixel = sprite_pixel_list[pixel_counter]; - sprite_attr = sprite_attr_list[pixel_counter]; - } - - if (have_sprite) - { - if (((LCDC & 0x2) > 0)) - { - if (!((sprite_attr & 0x80) > 0)) - { - use_sprite = true; - } - else if (ref_pixel == 0) - { - use_sprite = true; - } - - if (!((LCDC & 0x1) > 0)) - { - use_sprite = true; - } - - // There is another priority bit in GBC, that can still override sprite priority - if (((LCDC & 0x1) > 0) && ((tile_data_latch[2] & 0x80) > 0) && (ref_pixel != 0) && GBC_compat[0]) - { - use_sprite = false; - } - } - - if (use_sprite) - { - pal_num = sprite_attr & 7; - - if (!GBC_compat[0]) - { - pal_num = ((sprite_attr & 0x10) > 0) ? 1 : 0; - - if (((sprite_attr & 0x10) > 0)) - { - pixel = (obj_pal_1 >> (s_pixel * 2)) & 3; - } - else - { - pixel = (obj_pal_0 >> (s_pixel * 2)) & 3; - } - } - } - } - } - - // based on sprite priority and pixel values, pick a final pixel color - if (GBC_compat[0]) - { - if (use_sprite) - { - _vidbuffer[LY * 160 + pixel_counter] = OBJ_palette[pal_num * 4 + s_pixel]; - } - else - { - _vidbuffer[LY * 160 + pixel_counter] = BG_palette[pal_num * 4 + pixel]; - } - } - else - { - if (use_sprite) - { - _vidbuffer[LY * 160 + pixel_counter] = OBJ_palette[pal_num * 4 + pixel]; - } - else - { - _vidbuffer[LY * 160 + pixel_counter] = BG_palette[pixel]; - } - } - - pixel_counter++; - - if (pixel_counter == 160) - { - read_case = 8; - hbl_countdown = 2; - } - } - else if (pixel_counter < 0) - { - pixel_counter++; - } - render_counter++; - } - - if (!fetch_sprite) - { - if (!pre_render_2) - { - // before we go on to read case 3, we need to know if we stall there or not - // Gekkio's tests show that if sprites are at position 0 or 1 (mod 8) - // then it takes an extra cycle (1 or 2 more t-states) to process them - - if (!no_sprites && (pixel_counter < 160)) - { - for (uint32_t i = 0; i < SL_sprites_index; i++) - { - if ((pixel_counter >= (int32_t)(SL_sprites[i * 4 + 1] - 8)) && - (pixel_counter < (int32_t)(SL_sprites[i * 4 + 1])) && - !((evaled_sprites & (1 << i)) > 0)) - { - going_to_fetch = true; - fetch_sprite = true; - } - } - } - } - - switch (read_case) - { - case 0: // read a background tile - if ((internal_cycle % 2) == 1) - { - // calculate the row number of the tiles to be fetched - y_tile = ((uint32_t)((uint32_t)scroll_y + (uint32_t)LY) >> 3) % 32; - - temp_fetch = y_tile * 32 + (x_tile + tile_inc) % 32; - tile_byte = VRAM[0x1800 + (((LCDC & 0x8) > 0) ? 1 : 0) * 0x400 + temp_fetch]; - tile_data[2] = VRAM[0x3800 + (((LCDC & 0x8) > 0) ? 1 : 0) * 0x400 + temp_fetch]; - VRAM_sel = ((tile_data[2] & 0x8) > 0) ? 1 : 0; - - BG_V_flip = ((tile_data[2] & 0x40) > 0) & GBC_compat[0]; - - read_case = 1; - if (!pre_render) - { - tile_inc++; - } - } - break; - - case 1: // read from tile graphics (0) - if ((internal_cycle % 2) == 1) - { - y_scroll_offset = (scroll_y + LY) % 8; - - if (BG_V_flip) - { - y_scroll_offset = 7 - y_scroll_offset; - } - - if (((LCDC & 0x10) > 0)) - { - tile_data[0] = VRAM[(VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2]; - } - else - { - // same as before except now tile uint8_t represents a signed byte - if (((tile_byte & 0x80) > 0)) - { - tile_byte -= 256; - } - tile_data[0] = VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2]; - } - - read_case = 2; - } - break; - - case 2: // read from tile graphics (1) - if ((internal_cycle % 2) == 0) - { - pre_render_2 = false; - } - else - { - y_scroll_offset = (scroll_y + LY) % 8; - - if (BG_V_flip) - { - y_scroll_offset = 7 - y_scroll_offset; - } - - if (((LCDC & 0x10) > 0)) - { - // if LCDC somehow changed between the two reads, make sure we have a positive number - if (tile_byte < 0) - { - tile_byte += 256; - } - tile_data[1] = VRAM[(VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1]; - } - else - { - // same as before except now tile uint8_t represents a signed byte - if (((tile_byte & 0x80) > 0) && tile_byte > 0) - { - tile_byte -= 256; - } - tile_data[1] = VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1]; - } - - if (pre_render) - { - // here we set up rendering - pre_render = false; - - render_counter = 0; - latch_counter = 0; - read_case = 0; - } - else - { - read_case = 3; - } - } - break; - - case 3: // read from sprite data - if ((internal_cycle % 2) == 1) - { - read_case = 0; - latch_new_data = true; - } - break; - - case 4: // read from window data - if ((window_counter % 2) == 1) - { - temp_fetch = window_y_tile * 32 + (window_x_tile + window_tile_inc) % 32; - tile_byte = VRAM[0x1800 + (((LCDC & 0x40) > 0) ? 1 : 0) * 0x400 + temp_fetch]; - tile_data[2] = VRAM[0x3800 + (((LCDC & 0x40) > 0) ? 1 : 0) * 0x400 + temp_fetch]; - VRAM_sel = ((tile_data[2] & 0x8) > 0) ? 1 : 0; - BG_V_flip = ((tile_data[2] & 0x40) > 0) & GBC_compat[0]; - - window_tile_inc++; - read_case = 5; - } - window_counter++; - break; - - case 5: // read from tile graphics (for the window) - if ((window_counter % 2) == 1) - { - y_scroll_offset = (window_y_tile_inc) % 8; - - if (BG_V_flip) - { - y_scroll_offset = 7 - y_scroll_offset; - } - - if (((LCDC & 0x10) > 0)) - { - tile_data[0] = VRAM[(VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2]; - } - else - { - // same as before except now tile uint8_t represents a signed byte - if (((tile_byte & 0x80) > 0)) - { - tile_byte -= 256; - } - tile_data[0] = VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2]; - } - - read_case = 6; - } - window_counter++; - break; - - case 6: // read from tile graphics (for the window) - if ((window_counter % 2) == 1) - { - y_scroll_offset = (window_y_tile_inc) % 8; - - if (BG_V_flip) - { - y_scroll_offset = 7 - y_scroll_offset; - } - - if (((LCDC & 0x10) > 0)) - { - // if LCDC somehow changed between the two reads, make sure we have a positive number - if (tile_byte < 0) - { - tile_byte += 256; - } - tile_data[1] = VRAM[(VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1]; - } - else - { - // same as before except now tile uint8_t represents a signed byte - if (((tile_byte & 0x80) > 0) && tile_byte > 0) - { - tile_byte -= 256; - } - tile_data[1] = VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1]; - } - - if (window_pre_render) - { - // here we set up rendering - // unlike for the normal background case, there is no pre-render period for the window - // so start shifting in data to the screen right away - if (window_x_latch <= 7) - { - if (render_offset == 0) - { - read_case = 4; - } - else - { - read_case = 9 + render_offset - 1; - } - render_counter = 8 - render_offset; - - render_offset = 7 - window_x_latch; - } - else - { - render_offset = 0; - read_case = 4; - render_counter = 8; - } - - latch_counter = 0; - latch_new_data = true; - window_pre_render = false; - } - else - { - read_case = 7; - } - } - window_counter++; - break; - - case 7: // read from sprite data - if ((window_counter % 2) == 1) - { - read_case = 4; - latch_new_data = true; - } - window_counter++; - break; - - case 8: // done reading, we are now in phase 0 - pre_render = true; - - // the other interrupts appear to be delayed by 1 CPU cycle, so do the same here - if (hbl_countdown > 0) - { - hbl_countdown--; - - if (hbl_countdown == 0) - { - OAM_access_read = true; - OAM_access_write = true; - VRAM_access_read = true; - VRAM_access_write = true; - } - else - { - STAT &= 0xFC; - STAT |= 0x00; - - if (((STAT & 0x8) > 0)) { HBL_INT = true; } - } - } - break; - - case 9: - // this is a degenerate case for starting the window at 0 - // kevtris' timing doc indicates an additional normal BG access - // but this information is thrown away, so it's faster to do this then constantly check - // for it in read case 0 - read_case = 4; - break; - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - read_case--; - break; - } - internal_cycle++; - - if (latch_new_data) - { - latch_new_data = false; - tile_data_latch[0] = tile_data[0]; - tile_data_latch[1] = tile_data[1]; - tile_data_latch[2] = tile_data[2]; - } - } - - // every in range sprite takes 6 cycles to process - // sprites located at x=0 still take 6 cycles to process even though they don't appear on screen - // sprites above x=168 do not take any cycles to process however - if (fetch_sprite) - { - if (going_to_fetch) - { - going_to_fetch = false; - - last_eval = 0; - - // at this time it is unknown what each cycle does, but we only need to accurately keep track of cycles - for (uint32_t i = 0; i < SL_sprites_index; i++) - { - if ((pixel_counter >= (int32_t)(SL_sprites[i * 4 + 1] - 8)) && - (pixel_counter < (int32_t)(SL_sprites[i * 4 + 1])) && - !((evaled_sprites & (1 << i)) > 0)) - { - sprite_fetch_counter += 6; - evaled_sprites |= (1 << i); - last_eval = SL_sprites[i * 4 + 1]; - } - } - - // x scroll offsets the penalty table - // there is no penalty if the next sprites to be fetched are within the currentfetch block (8 pixels) - if (first_fetch || ((int32_t)last_eval >= consecutive_sprite)) - { - if (((last_eval + render_offset) % 8) == 0) { sprite_fetch_counter += 5; } - else if (((last_eval + render_offset) % 8) == 1) { sprite_fetch_counter += 4; } - else if (((last_eval + render_offset) % 8) == 2) { sprite_fetch_counter += 3; } - else if (((last_eval + render_offset) % 8) == 3) { sprite_fetch_counter += 2; } - else if (((last_eval + render_offset) % 8) == 4) { sprite_fetch_counter += 1; } - else if (((last_eval + render_offset) % 8) == 5) { sprite_fetch_counter += 0; } - else if (((last_eval + render_offset) % 8) == 6) { sprite_fetch_counter += 0; } - else if (((last_eval + render_offset) % 8) == 7) { sprite_fetch_counter += 0; } - - - consecutive_sprite = (uint32_t)(((last_eval + render_offset) >> 3) << 3) + 8 - render_offset; - - // special case exists here for sprites at zero with non-zero x-scroll. Not sure exactly the reason for it. - if (last_eval == 0 && render_offset != 0) - { - sprite_fetch_counter += render_offset; - } - } - - total_counter += sprite_fetch_counter; - - first_fetch = false; - } - else - { - sprite_fetch_counter--; - if (sprite_fetch_counter == 0) - { - fetch_sprite = false; - } - } - } - - } - - void process_sprite() - { - uint32_t y; - uint32_t VRAM_temp = (((SL_sprites[sl_use_index * 4 + 3] & 0x8) > 0) && GBC_compat[0]) ? 1 : 0; - - if ((SL_sprites[sl_use_index * 4 + 3] & 0x40) > 0) - { - if (((LCDC & 0x4) > 0)) - { - y = LY - (SL_sprites[sl_use_index * 4] - 16); - y = 15 - y; - sprite_sel[0] = VRAM[(VRAM_temp * 0x2000) + (SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2]; - sprite_sel[1] = VRAM[(VRAM_temp * 0x2000) + (SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2 + 1]; - } - else - { - y = LY - (SL_sprites[sl_use_index * 4] - 16); - y = 7 - y; - sprite_sel[0] = VRAM[(VRAM_temp * 0x2000) + SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2]; - sprite_sel[1] = VRAM[(VRAM_temp * 0x2000) + SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2 + 1]; - } - } - else - { - if (((LCDC & 0x4) > 0)) - { - y = LY - (SL_sprites[sl_use_index * 4] - 16); - sprite_sel[0] = VRAM[(VRAM_temp * 0x2000) + (SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2]; - sprite_sel[1] = VRAM[(VRAM_temp * 0x2000) + (SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2 + 1]; - } - else - { - y = LY - (SL_sprites[sl_use_index * 4] - 16); - sprite_sel[0] = VRAM[(VRAM_temp * 0x2000) + SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2]; - sprite_sel[1] = VRAM[(VRAM_temp * 0x2000) + SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2 + 1]; - } - } - - if ((SL_sprites[sl_use_index * 4 + 3] & 0x20) > 0) - { - uint32_t b0, b1, b2, b3, b4, b5, b6, b7 = 0; - for (uint32_t i = 0; i < 2; i++) - { - b0 = (sprite_sel[i] & 0x01) << 7; - b1 = (sprite_sel[i] & 0x02) << 5; - b2 = (sprite_sel[i] & 0x04) << 3; - b3 = (sprite_sel[i] & 0x08) << 1; - b4 = (sprite_sel[i] & 0x10) >> 1; - b5 = (sprite_sel[i] & 0x20) >> 3; - b6 = (sprite_sel[i] & 0x40) >> 5; - b7 = (sprite_sel[i] & 0x80) >> 7; - - sprite_sel[i] = (uint8_t)(b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7); - } - } - } - - // order sprites according to x coordinate - // note that for sprites of equal x coordinate, priority goes to first on the list - void reorder_and_assemble_sprites() - { - sprite_ordered_index = 0; - - // In CGB mode, sprites are ordered solely based on their position in OAM, so they are already ordered - - if (GBC_compat[0]) - { - for (uint32_t j = 0; j < SL_sprites_index; j++) - { - sl_use_index = j; - process_sprite(); - SL_sprites_ordered[sprite_ordered_index * 4] = SL_sprites[j * 4 + 1]; - SL_sprites_ordered[sprite_ordered_index * 4 + 1] = sprite_sel[0]; - SL_sprites_ordered[sprite_ordered_index * 4 + 2] = sprite_sel[1]; - SL_sprites_ordered[sprite_ordered_index * 4 + 3] = SL_sprites[j * 4 + 3]; - sprite_ordered_index++; - } - } - else - { - for (int i = 0; i < 256; i++) - { - for (uint32_t j = 0; j < SL_sprites_index; j++) - { - if (SL_sprites[j * 4 + 1] == i) - { - sl_use_index = j; - process_sprite(); - SL_sprites_ordered[sprite_ordered_index * 4] = SL_sprites[j * 4 + 1]; - SL_sprites_ordered[sprite_ordered_index * 4 + 1] = sprite_sel[0]; - SL_sprites_ordered[sprite_ordered_index * 4 + 2] = sprite_sel[1]; - SL_sprites_ordered[sprite_ordered_index * 4 + 3] = SL_sprites[j * 4 + 3]; - sprite_ordered_index++; - } - } - } - } - - bool have_pixel = false; - uint8_t s_pixel = 0; - uint8_t sprite_attr = 0; - - for (uint32_t i = 0; i < 160; i++) - { - have_pixel = false; - for (uint32_t j = 0; j < SL_sprites_index; j++) - { - if ((i >= (SL_sprites_ordered[j * 4] - 8)) && - (i < SL_sprites_ordered[j * 4]) && - !have_pixel) - { - // we can use the current sprite, so pick out a pixel for it - uint32_t t_index = i - (SL_sprites_ordered[j * 4] - 8); - - t_index = 7 - t_index; - - sprite_data[0] = (uint8_t)((SL_sprites_ordered[j * 4 + 1] >> t_index) & 1); - sprite_data[1] = (uint8_t)(((SL_sprites_ordered[j * 4 + 2] >> t_index) & 1) << 1); - - s_pixel = (uint8_t)(sprite_data[0] + sprite_data[1]); - sprite_attr = (uint8_t)SL_sprites_ordered[j * 4 + 3]; - - // pixel color of 0 is transparent, so if this is the case we don't have a pixel - if (s_pixel != 0) - { - have_pixel = true; - } - } - } - - if (have_pixel) - { - sprite_present_list[i] = 1; - sprite_pixel_list[i] = s_pixel; - sprite_attr_list[i] = sprite_attr; - } - else - { - sprite_present_list[i] = 0; - } - } - } - - void OAM_scan(uint32_t OAM_cycle) - { - // we are now in STAT mode 2 - // TODO: maybe stat mode 2 flags are set at cycle 0 on visible scanlines? - if (OAM_cycle == 0) - { - OAM_access_read = false; - OAM_access_write = false; - - OAM_scan_index = 0; - SL_sprites_index = 0; - write_sprite = 0; - } - - // the gameboy has 80 cycles to scan through 40 sprites, picking out the first 10 it finds to draw - // the following is a guessed at implmenentation based on how NES does it, it's probably pretty close - if (OAM_cycle < 10) - { - // start by clearing the sprite table (probably just clears X on hardware, but let's be safe here.) - SL_sprites[OAM_cycle * 4] = 0; - SL_sprites[OAM_cycle * 4 + 1] = 0; - SL_sprites[OAM_cycle * 4 + 2] = 0; - SL_sprites[OAM_cycle * 4 + 3] = 0; - } - else - { - if (write_sprite == 0) - { - if (OAM_scan_index < 40) - { - int32_t temp = DMA_OAM_access ? OAM[OAM_scan_index * 4] : (int32_t)0xFF; - // (sprite Y - 16) equals LY, we have a sprite - if ((temp - 16) <= LY && - ((temp - 16) + 8 + (((LCDC & 0x4) > 0) ? 8 : 0)) > LY) - { - // always pick the first 10 in range sprites - if (SL_sprites_index < 10) - { - SL_sprites[SL_sprites_index * 4] = temp; - - write_sprite = 1; - } - else - { - // if we already have 10 sprites, there's nothing to do, increment the index - OAM_scan_index++; - } - } - else - { - OAM_scan_index++; - } - } - } - else - { - uint32_t temp2 = DMA_OAM_access ? OAM[OAM_scan_index * 4 + write_sprite] : (uint32_t)0xFF; - SL_sprites[SL_sprites_index * 4 + write_sprite] = temp2; - write_sprite++; - - if (write_sprite == 4) - { - write_sprite = 0; - SL_sprites_index++; - OAM_scan_index++; - } - } - } - } - - void Reset() - { - LCDC = 0; - STAT = 0x80; - scroll_y = 0; - scroll_x = 0; - LY = 0; - LYC = 0; - DMA_addr = 0; - BGP = 0xFF; - obj_pal_0 = 0; - obj_pal_1 = 0; - window_y = 0x0; - window_x = 0x0; - window_x_latch = 0xFF; - window_y_latch = 0xFF; - LY_inc = 1; - no_scan = false; - OAM_access_read = true; - VRAM_access_read = true; - OAM_access_write = true; - VRAM_access_write = true; - DMA_OAM_access = true; - - cycle = 0; - LYC_INT = false; - HBL_INT = false; - VBL_INT = false; - OAM_INT = false; - - stat_line = false; - stat_line_old = false; - - window_counter = 0; - window_pre_render = false; - window_started = false; - window_tile_inc = 0; - window_y_tile = 0; - window_x_tile = 0; - window_y_tile_inc = 0; - - BG_bytes_inc = false; - OBJ_bytes_inc = false; - BG_bytes_index = 0; - OBJ_bytes_index = 0; - BG_transfer_byte = 0; - OBJ_transfer_byte = 0; - - HDMA_src_hi = 0; - HDMA_src_lo = 0; - HDMA_dest_hi = 0; - HDMA_dest_lo = 0; - - VRAM_sel = 0; - BG_V_flip = false; - HDMA_active = false; - HDMA_mode = false; - cur_DMA_src = 0; - cur_DMA_dest = 0; - HDMA_length = 0; - HDMA_countdown = 0; - HBL_HDMA_count = 0; - last_HBL = 0; - HBL_HDMA_go = false; - HBL_test = false; - } - }; - - #pragma endregion -} diff --git a/libHawk/GBHawk/GBHawk/SerialPort.h b/libHawk/GBHawk/GBHawk/SerialPort.h deleted file mode 100644 index fcd2c88746..0000000000 --- a/libHawk/GBHawk/GBHawk/SerialPort.h +++ /dev/null @@ -1,210 +0,0 @@ -#include -#include -#include -#include - -using namespace std; - -namespace GBHawk -{ - class SerialPort - { - public: - - SerialPort() - { - - }; - - bool* GBC_compat = nullptr; - bool* FlagI = nullptr; - uint8_t* REG_FFFF = nullptr; - uint8_t* REG_FF0F = nullptr; - - bool serial_start; - bool can_pulse; - uint8_t serial_control; - uint8_t serial_data; - uint8_t going_out; - uint8_t coming_in; - uint32_t serial_clock; - uint32_t serial_bits; - uint32_t clk_rate; - - uint8_t ReadReg(int addr) - { - switch (addr) - { - case 0xFF01: - return serial_data; - case 0xFF02: - return serial_control; - } - - return 0xFF; - } - - void WriteReg(int addr, uint8_t value) - { - switch (addr) - { - case 0xFF01: - serial_data = value; - break; - - case 0xFF02: - if (((value & 0x80) > 0) && !serial_start) - { - serial_start = true; - serial_bits = 8; - if ((value & 1) > 0) - { - if (((value & 2) > 0) && GBC_compat[0]) - { - clk_rate = 16; - } - else - { - clk_rate = 512; - } - serial_clock = clk_rate; - can_pulse = true; - } - else - { - clk_rate = -1; - serial_clock = clk_rate; - can_pulse = false; - } - } - else if (serial_start) - { - if ((value & 1) > 0) - { - if (((value & 2) > 0) && GBC_compat[0]) - { - clk_rate = 16; - } - else - { - clk_rate = 512; - } - serial_clock = clk_rate; - can_pulse = true; - } - else - { - clk_rate = -1; - serial_clock = clk_rate; - can_pulse = false; - } - } - - if (GBC_compat[0]) - { - serial_control = (uint8_t)(0x7C | (value & 0x83)); // extra CGB bit - } - else - { - serial_control = (uint8_t)(0x7E | (value & 0x81)); // middle six bits always 1 - } - - break; - } - } - - - void serial_transfer_tick() - { - if (serial_start) - { - if (serial_clock > 0) { serial_clock--; } - - if (serial_clock == 0) - { - if (serial_bits > 0) - { - serial_data = (uint8_t)((serial_data << 1) | coming_in); - - serial_bits--; - - if (serial_bits == 0) - { - serial_control &= 0x7F; - serial_start = false; - - if ((REG_FFFF[0] & 0x8) > 0) { FlagI[0] = true; } - REG_FF0F[0] |= 0x08; - } - else - { - serial_clock = clk_rate; - if (clk_rate > 0) { can_pulse = true; } - } - } - } - } - } - - void Reset() - { - serial_control = 0x7E; - serial_data = 0x00; - serial_start = false; - serial_clock = 0; - serial_bits = 0; - clk_rate = 16; - going_out = 0; - coming_in = 1; - can_pulse = false; - } - - #pragma region State Save / Load - - uint8_t* SaveState(uint8_t* saver) - { - *saver = (uint8_t)(serial_start ? 1 : 0); saver++; - *saver = (uint8_t)(can_pulse ? 1 : 0); saver++; - - *saver = serial_control; saver++; - *saver = serial_data; saver++; - *saver = going_out; saver++; - *saver = coming_in; saver++; - - *saver = (uint8_t)(serial_clock & 0xFF); saver++; *saver = (uint8_t)((serial_clock >> 8) & 0xFF); saver++; - *saver = (uint8_t)((serial_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((serial_clock >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(serial_bits & 0xFF); saver++; *saver = (uint8_t)((serial_bits >> 8) & 0xFF); saver++; - *saver = (uint8_t)((serial_bits >> 16) & 0xFF); saver++; *saver = (uint8_t)((serial_bits >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(clk_rate & 0xFF); saver++; *saver = (uint8_t)((clk_rate >> 8) & 0xFF); saver++; - *saver = (uint8_t)((clk_rate >> 16) & 0xFF); saver++; *saver = (uint8_t)((clk_rate >> 24) & 0xFF); saver++; - - return saver; - } - - uint8_t* LoadState(uint8_t* loader) - { - serial_start = *loader == 1; loader++; - can_pulse = *loader == 1; loader++; - - serial_control = *loader; loader++; - serial_data = *loader; loader++; - going_out = *loader; loader++; - coming_in = *loader; loader++; - - serial_clock = *loader; loader++; serial_clock |= (*loader << 8); loader++; - serial_clock |= (*loader << 16); loader++; serial_clock |= (*loader << 24); loader++; - - serial_bits = *loader; loader++; serial_bits |= (*loader << 8); loader++; - serial_bits |= (*loader << 16); loader++; serial_bits |= (*loader << 24); loader++; - - clk_rate = *loader; loader++; clk_rate |= (*loader << 8); loader++; - clk_rate |= (*loader << 16); loader++; clk_rate |= (*loader << 24); loader++; - - return loader; - } - - #pragma endregion - }; -} diff --git a/libHawk/GBHawk/GBHawk/Timer.h b/libHawk/GBHawk/GBHawk/Timer.h deleted file mode 100644 index 752ced9a85..0000000000 --- a/libHawk/GBHawk/GBHawk/Timer.h +++ /dev/null @@ -1,221 +0,0 @@ -#include -#include -#include -#include - -using namespace std; - -namespace GBHawk -{ - class Timer - { - public: - - Timer() - { - - }; - - bool* FlagI = nullptr; - uint8_t* REG_FFFF = nullptr; - uint8_t* REG_FF0F = nullptr; - uint64_t* CPU_cycle_pntr = nullptr; - - bool old_state = false; - bool state = false; - bool reload_block = false; - - uint8_t timer_reload = 0; - uint8_t timer = 0; - uint8_t timer_old = 0; - uint8_t timer_control = 0; - uint8_t pending_reload = 0; - - uint32_t divider_reg = 0; - - uint64_t next_free_cycle = 0; - - uint8_t ReadReg(uint32_t addr) - { - uint8_t ret = 0; - - switch (addr) - { - case 0xFF04: ret = (uint8_t)(divider_reg >> 8); break; // DIV register - case 0xFF05: ret = timer; break; // TIMA (Timer Counter) - case 0xFF06: ret = timer_reload; break; // TMA (Timer Modulo) - case 0xFF07: ret = timer_control; break; // TAC (Timer Control) - } - - return ret; - } - - void WriteReg(int addr, uint8_t value) - { - switch (addr) - { - // DIV register - case 0xFF04: - divider_reg = 0; - break; - - // TIMA (Timer Counter) - case 0xFF05: - if (CPU_cycle_pntr[0] >= next_free_cycle) - { - timer_old = timer; - timer = value; - reload_block = true; - } - break; - - // TMA (Timer Modulo) - case 0xFF06: - timer_reload = value; - if (CPU_cycle_pntr[0] < next_free_cycle) - { - timer = timer_reload; - timer_old = timer; - } - break; - - // TAC (Timer Control) - case 0xFF07: - timer_control = (uint8_t)((timer_control & 0xf8) | (value & 0x7)); // only bottom 3 bits function - break; - } - } - - void tick() - { - divider_reg++; - - // pick a bit to test based on the current value of timer control - switch (timer_control & 3) - { - case 0: - state = (divider_reg & 0x200) > 0; - break; - case 1: - state = (divider_reg & 0x8) > 0; - break; - case 2: - state = (divider_reg & 0x20) > 0; - break; - case 3: - state = (divider_reg & 0x80) > 0; - break; - } - - // And it with the state of the timer on/off bit - state &= (timer_control & 4) > 0; - - // this procedure allows several glitchy timer ticks, since it only measures falling edge of the state - // so things like turning the timer off and resetting the divider will tick the timer - if (old_state && !state) - { - timer_old = timer; - timer++; - - // if overflow happens, set the interrupt flag and reload the timer (if applicable) - if (timer < timer_old) - { - if ((timer_control & 4) > 0) - { - pending_reload = 4; - reload_block = false; - } - else - { - //TODO: Check if timer still gets reloaded if TAC diabled causes overflow - if ((REG_FFFF[0] & 0x4) > 0) { FlagI[0] = true; } - REG_FF0F[0] |= 0x04; - } - } - } - - old_state = state; - - if (pending_reload > 0) - { - pending_reload--; - if (pending_reload == 0 && !reload_block) - { - timer = timer_reload; - timer_old = timer; - - next_free_cycle = 4 + CPU_cycle_pntr[0]; - - // set interrupts - if ((REG_FFFF[0] & 0x4) > 0) { FlagI[0] = true; } - REG_FF0F[0] |= 0x04; - } - } - } - - void Reset() - { - divider_reg = 8; // probably always 8 but not confirmed for GB as far as I know - timer_reload = 0; - timer = 0; - timer_old = 0; - timer_control = 0xF8; - pending_reload = 0; - old_state = false; - state = false; - reload_block = false; - next_free_cycle = 0; - } - - #pragma region State Save / Load - - uint8_t* SaveState(uint8_t* saver) - { - - *saver = (uint8_t)(old_state ? 1 : 0); saver++; - *saver = (uint8_t)(state ? 1 : 0); saver++; - *saver = (uint8_t)(reload_block ? 1 : 0); saver++; - - *saver = timer_reload; saver++; - *saver = timer; saver++; - *saver = timer_old; saver++; - *saver = timer_control; saver++; - *saver = pending_reload; saver++; - - *saver = (uint8_t)(divider_reg & 0xFF); saver++; *saver = (uint8_t)((divider_reg >> 8) & 0xFF); saver++; - *saver = (uint8_t)((divider_reg >> 16) & 0xFF); saver++; *saver = (uint8_t)((divider_reg >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(next_free_cycle & 0xFF); saver++; *saver = (uint8_t)((next_free_cycle >> 8) & 0xFF); saver++; - *saver = (uint8_t)((next_free_cycle >> 16) & 0xFF); saver++; *saver = (uint8_t)((next_free_cycle >> 24) & 0xFF); saver++; - *saver = (uint8_t)((next_free_cycle >> 32) & 0xFF); saver++; *saver = (uint8_t)((next_free_cycle >> 40) & 0xFF); saver++; - *saver = (uint8_t)((next_free_cycle >> 48) & 0xFF); saver++; *saver = (uint8_t)((next_free_cycle >> 56) & 0xFF); saver++; - - return saver; - } - - uint8_t* LoadState(uint8_t* loader) - { - old_state = *loader == 1; loader++; - state = *loader == 1; loader++; - reload_block = *loader == 1; loader++; - - timer_reload = *loader; loader++; - timer = *loader; loader++; - timer_old = *loader; loader++; - timer_control = *loader; loader++; - pending_reload = *loader; loader++; - - divider_reg = *loader; loader++; divider_reg |= (*loader << 8); loader++; - divider_reg |= (*loader << 16); loader++; divider_reg |= (*loader << 24); loader++; - - next_free_cycle = *loader; loader++; next_free_cycle |= ((uint64_t)*loader << 8); loader++; - next_free_cycle |= ((uint64_t)*loader << 16); loader++; next_free_cycle |= ((uint64_t)*loader << 24); loader++; - next_free_cycle |= ((uint64_t)*loader << 32); loader++; next_free_cycle |= ((uint64_t)*loader << 40); loader++; - next_free_cycle |= ((uint64_t)*loader << 48); loader++; next_free_cycle |= ((uint64_t)*loader << 56); loader++; - - return loader; - } - - #pragma endregion - }; -} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/cpp.hint b/libHawk/GBHawk/GBHawk/cpp.hint deleted file mode 100644 index 43a4f3526e..0000000000 --- a/libHawk/GBHawk/GBHawk/cpp.hint +++ /dev/null @@ -1,2 +0,0 @@ -#define GBHawk_API __declspec(dllexport) -#define GBHawk_API __declspec(dllimport)