From 7f2e1438ba7f26174c0da9d746a458ee29e9bae7 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 22 Mar 2020 19:34:00 -0500 Subject: [PATCH 01/15] VirtualPads - style console pads differently --- BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualPad.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualPad.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualPad.cs index 8e6034be1c..87e7f41d72 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualPad.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualPad.cs @@ -51,6 +51,12 @@ namespace BizHawk.Client.EmuHawk Size = UIHelper.Scale(_schema.Size); MaximumSize = UIHelper.Scale(_schema.Size); PadBox.Text = _schema.DisplayName; + + if (_schema.IsConsole) + { + this.PadBox.ForeColor = SystemColors.HotTrack; + } + foreach (var button in _schema.Buttons) { switch (button.Type) From 49b57bbb223b61ab65f7c70559e48ee3453e20fb Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 22 Mar 2020 19:54:19 -0500 Subject: [PATCH 02/15] Virtualpads - fix up vectrex - add console buttons, fix analog logic --- .../tools/VirtualPads/schema/VECSchema.cs | 91 +++++++++---------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/VECSchema.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/VECSchema.cs index 6ce0572cd4..60d16fdafa 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/VECSchema.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/VECSchema.cs @@ -16,25 +16,27 @@ namespace BizHawk.Client.EmuHawk var port1 = vecSyncSettings.Port1; var port2 = vecSyncSettings.Port2; - if (port1 == "Vectrex Digital Controller") + switch (port1) { - yield return StandardController(1); + case "Vectrex Digital Controller": + yield return StandardController(1); + break; + case "Vectrex Analog Controller": + yield return AnalogController(1); + break; } - if (port2 == "Vectrex Digital Controller") + switch (port2) { - yield return StandardController(2); + case "Vectrex Digital Controller": + yield return StandardController(2); + break; + case "Vectrex Analog Controller": + yield return AnalogController(2); + break; } - if (port1 == "Vectrex Analog Controller") - { - yield return AnalogController(1); - } - - if (port2 == "Vectrex Analog Controller") - { - yield return AnalogController(2); - } + yield return ConsoleButtons(); } private static PadSchema StandardController(int controller) @@ -48,22 +50,10 @@ namespace BizHawk.Client.EmuHawk ButtonSchema.Down(14, 56, controller), ButtonSchema.Left(2, 34, controller), ButtonSchema.Right(24, 34, controller), - new ButtonSchema(74, 34, controller, "Button 1") - { - DisplayName = "1" - }, - new ButtonSchema(98, 34, controller, "Button 2") - { - DisplayName = "2" - }, - new ButtonSchema(122, 34, controller, "Button 3") - { - DisplayName = "3" - }, - new ButtonSchema(146, 34, controller, "Button 4") - { - DisplayName = "4" - } + Button(74, 34, controller, 1), + Button(98, 34, controller, 2), + Button(122, 34, controller, 3), + Button(146, 34, controller, 4) } }; } @@ -73,25 +63,13 @@ namespace BizHawk.Client.EmuHawk var controllerDefRanges = new AnalogControls(controller).Definition.FloatRanges; return new PadSchema { - Size = new Size(280, 380), + Size = new Size(280, 300), Buttons = new[] { - new ButtonSchema(74, 34, controller, "Button 1") - { - DisplayName = "1" - }, - new ButtonSchema(98, 34, controller, "Button 2") - { - DisplayName = "2" - }, - new ButtonSchema(122, 34, controller, "Button 3") - { - DisplayName = "3" - }, - new ButtonSchema(146, 34, controller, "Button 4") - { - DisplayName = "4" - }, + Button(74, 34, controller, 1), + Button(98, 34, controller, 2), + Button(122, 34, controller, 3), + Button(146, 34, controller, 4), new AnalogSchema(2, 80, $"P{controller} Stick X") { AxisRange = controllerDefRanges[0], @@ -100,5 +78,26 @@ namespace BizHawk.Client.EmuHawk } }; } + + private static ButtonSchema Button(int x, int y, int controller, int button) + { + return new ButtonSchema(x, y, controller, $"Button {button}") + { + DisplayName = button.ToString() + }; + } + + private static PadSchema ConsoleButtons() + { + return new ConsoleSchema + { + Size = new Size(150, 50), + Buttons = new[] + { + new ButtonSchema(10, 15, "Reset"), + new ButtonSchema(58, 15, "Power") + } + }; + } } } From b2c2b5c362f2163002aad1d5ad50a8f1bbdb3494 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 22 Mar 2020 20:10:30 -0500 Subject: [PATCH 03/15] VirtualPads - Genesis activator - attempt to fix it up, it at least maps to correct buttons now --- .../tools/VirtualPads/schema/GenSchema.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/GenSchema.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/GenSchema.cs index 1f1f0d03ea..29b344680d 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/GenSchema.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/GenSchema.cs @@ -175,6 +175,8 @@ namespace BizHawk.Client.EmuHawk }; } + // TODO: don't know what L/U is, couldn't find documentation, went with U + // Also, which number corresponds to which direction? private static PadSchema Activator(int controller) { return new PadSchema @@ -182,15 +184,14 @@ namespace BizHawk.Client.EmuHawk Size = new Size(110, 110), Buttons = new[] { - ButtonSchema.Up(47, 10, controller), - ButtonSchema.Down(47, 73, controller), - ButtonSchema.Left(15, 43, controller), - ButtonSchema.Right(80, 43, controller), - new ButtonSchema(70, 65, controller, "A"), - new ButtonSchema(70, 20, controller, "B"), - new ButtonSchema(22, 20, controller, "C"), - new ButtonSchema(22, 65, controller, "A"), - new ButtonSchema(47, 43, controller, "Start") { DisplayName = "S" } + new ButtonSchema(15, 43, controller, "1U") { Icon = Properties.Resources.Back }, + new ButtonSchema(22, 20, controller, "2U") { Icon = Properties.Resources.NW }, + new ButtonSchema(47, 10, controller, "3U") { Icon = Properties.Resources.BlueUp }, + new ButtonSchema(70, 20, controller, "4U") { Icon = Properties.Resources.NE }, + new ButtonSchema(80, 43, controller, "5U") { Icon = Properties.Resources.Forward }, + new ButtonSchema(70, 65, controller, "6U") { Icon = Properties.Resources.SE }, + new ButtonSchema(47, 73, controller, "7U") { Icon = Properties.Resources.BlueDown }, + new ButtonSchema(22, 65, controller, "8U") { Icon = Properties.Resources.SW } } }; } From b52d674959d890f5a7603cc92221c25e785744fe Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 22 Mar 2020 20:14:09 -0500 Subject: [PATCH 04/15] virtualpads - cleanup --- .../tools/VirtualPads/schema/ButtonSchema.cs | 18 ++--- .../tools/VirtualPads/schema/GenSchema.cs | 17 ++-- .../tools/VirtualPads/schema/IntvSchema.cs | 81 ++++--------------- .../tools/VirtualPads/schema/SaturnSchema.cs | 2 +- 4 files changed, 36 insertions(+), 82 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/ButtonSchema.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/ButtonSchema.cs index b99f3a4d2f..ce9fbbeef8 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/ButtonSchema.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/ButtonSchema.cs @@ -1,6 +1,6 @@ using System.Drawing; using System.Windows.Forms; - +using BizHawk.Client.EmuHawk.Properties; using BizHawk.Emulation.Common; namespace BizHawk.Client.EmuHawk @@ -52,50 +52,50 @@ namespace BizHawk.Client.EmuHawk public static ButtonSchema Up(int x, int y, string name = null) => new ButtonSchema(x, y, name ?? "Up") { - Icon = Properties.Resources.BlueUp + Icon = Resources.BlueUp }; public static ButtonSchema Up(int x, int y, int controller) => new ButtonSchema(x, y, controller, "Up") { - Icon = Properties.Resources.BlueUp + Icon = Resources.BlueUp }; public static ButtonSchema Down(int x, int y, string name = null) => new ButtonSchema(x, y, name ?? "Down") { - Icon = Properties.Resources.BlueDown + Icon = Resources.BlueDown }; public static ButtonSchema Down(int x, int y, int controller) => new ButtonSchema(x, y, controller, "Down") { - Icon = Properties.Resources.BlueDown + Icon = Resources.BlueDown }; public static ButtonSchema Left(int x, int y, string name = null) => new ButtonSchema(x, y, name ?? "Left") { - Icon = Properties.Resources.Back + Icon = Resources.Back }; public static ButtonSchema Left(int x, int y, int controller) => new ButtonSchema(x, y, controller, "Left") { - Icon = Properties.Resources.Back + Icon = Resources.Back }; public static ButtonSchema Right(int x, int y, string name = null) => new ButtonSchema(x, y, name ?? "Right") { - Icon = Properties.Resources.Forward + Icon = Resources.Forward }; public static ButtonSchema Right(int x, int y, int controller) => new ButtonSchema(x, y, controller, "Right") { - Icon = Properties.Resources.Forward + Icon = Resources.Forward }; } diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/GenSchema.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/GenSchema.cs index 29b344680d..94e48bc8fe 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/GenSchema.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/GenSchema.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; +using BizHawk.Client.EmuHawk.Properties; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; @@ -184,14 +185,14 @@ namespace BizHawk.Client.EmuHawk Size = new Size(110, 110), Buttons = new[] { - new ButtonSchema(15, 43, controller, "1U") { Icon = Properties.Resources.Back }, - new ButtonSchema(22, 20, controller, "2U") { Icon = Properties.Resources.NW }, - new ButtonSchema(47, 10, controller, "3U") { Icon = Properties.Resources.BlueUp }, - new ButtonSchema(70, 20, controller, "4U") { Icon = Properties.Resources.NE }, - new ButtonSchema(80, 43, controller, "5U") { Icon = Properties.Resources.Forward }, - new ButtonSchema(70, 65, controller, "6U") { Icon = Properties.Resources.SE }, - new ButtonSchema(47, 73, controller, "7U") { Icon = Properties.Resources.BlueDown }, - new ButtonSchema(22, 65, controller, "8U") { Icon = Properties.Resources.SW } + new ButtonSchema(15, 43, controller, "1U") { Icon = Resources.Back }, + new ButtonSchema(22, 20, controller, "2U") { Icon = Resources.NW }, + new ButtonSchema(47, 10, controller, "3U") { Icon = Resources.BlueUp }, + new ButtonSchema(70, 20, controller, "4U") { Icon = Resources.NE }, + new ButtonSchema(80, 43, controller, "5U") { Icon = Resources.Forward }, + new ButtonSchema(70, 65, controller, "6U") { Icon = Resources.SE }, + new ButtonSchema(47, 73, controller, "7U") { Icon = Resources.BlueDown }, + new ButtonSchema(22, 65, controller, "8U") { Icon = Resources.SW } } }; } diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/IntvSchema.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/IntvSchema.cs index 9f2eb83b9d..0b09807c0b 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/IntvSchema.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/IntvSchema.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; +using BizHawk.Client.EmuHawk.Properties; using BizHawk.Common.ReflectionExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Intellivision; @@ -47,70 +48,22 @@ namespace BizHawk.Client.EmuHawk Size = new Size(148, 332), Buttons = StandardButtons(controller).Concat(new[] { - new ButtonSchema(51, 124, controller, "N") - { - Icon = Properties.Resources.BlueUp - }, - new ButtonSchema(63, 145, controller, "NNE") - { - Icon = Properties.Resources.NNE - }, - new ButtonSchema(39, 145, controller, "NNW") - { - Icon = Properties.Resources.NNW - }, - new ButtonSchema(75, 166, controller, "NE") - { - Icon = Properties.Resources.NE - }, - new ButtonSchema(27, 166, controller, "NW") - { - Icon = Properties.Resources.NW - }, - new ButtonSchema(87, 187, controller, "ENE") - { - Icon = Properties.Resources.ENE - }, - new ButtonSchema(15, 187, controller, "WNW") - { - Icon = Properties.Resources.WNW - }, - new ButtonSchema(99, 208, controller, "E") - { - Icon = Properties.Resources.Forward - }, - new ButtonSchema(3, 208, controller, "W") - { - Icon = Properties.Resources.Back - }, - new ButtonSchema(87, 229, controller, "ESE") - { - Icon = Properties.Resources.ESE - }, - new ButtonSchema(15, 229, controller, "WSW") - { - Icon = Properties.Resources.WSW - }, - new ButtonSchema(75, 250, controller, "SE") - { - Icon = Properties.Resources.SE - }, - new ButtonSchema(27, 250, controller, "SW") - { - Icon = Properties.Resources.SW - }, - new ButtonSchema(63, 271, controller, "SSE") - { - Icon = Properties.Resources.SSE - }, - new ButtonSchema(39, 271, controller, "SSW") - { - Icon = Properties.Resources.SSW - }, - new ButtonSchema(51, 292, controller, "S") - { - Icon = Properties.Resources.BlueDown - } + new ButtonSchema(51, 124, controller, "N") { Icon = Resources.BlueUp }, + new ButtonSchema(63, 145, controller, "NNE") { Icon = Resources.NNE }, + new ButtonSchema(39, 145, controller, "NNW") { Icon = Resources.NNW }, + new ButtonSchema(75, 166, controller, "NE") { Icon = Resources.NE }, + new ButtonSchema(27, 166, controller, "NW") { Icon = Resources.NW }, + new ButtonSchema(87, 187, controller, "ENE") { Icon = Resources.ENE }, + new ButtonSchema(15, 187, controller, "WNW") { Icon = Resources.WNW }, + new ButtonSchema(99, 208, controller, "E") { Icon = Resources.Forward }, + new ButtonSchema(3, 208, controller, "W") { Icon = Resources.Back }, + new ButtonSchema(87, 229, controller, "ESE") { Icon = Resources.ESE }, + new ButtonSchema(15, 229, controller, "WSW") { Icon = Resources.WSW }, + new ButtonSchema(75, 250, controller, "SE") { Icon = Resources.SE }, + new ButtonSchema(27, 250, controller, "SW") { Icon = Resources.SW }, + new ButtonSchema(63, 271, controller, "SSE") { Icon = Resources.SSE }, + new ButtonSchema(39, 271, controller, "SSW") { Icon = Resources.SSW }, + new ButtonSchema(51, 292, controller, "S") { Icon = Resources.BlueDown } }) }; } diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/SaturnSchema.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/SaturnSchema.cs index 44bc0b8a0e..b7cfcf5e93 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/SaturnSchema.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/SaturnSchema.cs @@ -113,7 +113,7 @@ namespace BizHawk.Client.EmuHawk { SecondaryNames = new[] { $"P{controller} Stick Vertical" }, AxisRange = axisRanges[0], - SecondaryAxisRange = axisRanges[1], + SecondaryAxisRange = axisRanges[1] }, new SingleFloatSchema(8, 12, controller, "Left Shoulder") { From b168ea060032ac1903c63878c1abca79de15b9b9 Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Mon, 23 Mar 2020 19:09:02 +1000 Subject: [PATCH 05/15] Add FxCop Analyzer and update StyleCop I thought StyleCop was missing a few rules... --- BizHawk.Common/BizHawk.Common.csproj | 4 +- Common.ruleset | 218 +++++++++++++++++++++++++++ CommonStyleCopAnalyzer.props | 2 +- 3 files changed, 222 insertions(+), 2 deletions(-) diff --git a/BizHawk.Common/BizHawk.Common.csproj b/BizHawk.Common/BizHawk.Common.csproj index c2d5c2d034..bdbb240826 100644 --- a/BizHawk.Common/BizHawk.Common.csproj +++ b/BizHawk.Common/BizHawk.Common.csproj @@ -8,7 +8,9 @@ - + diff --git a/Common.ruleset b/Common.ruleset index f8680f2a1b..5aa160e624 100644 --- a/Common.ruleset +++ b/Common.ruleset @@ -1,5 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CommonStyleCopAnalyzer.props b/CommonStyleCopAnalyzer.props index c5b8a86f5e..e6b54ebf0e 100644 --- a/CommonStyleCopAnalyzer.props +++ b/CommonStyleCopAnalyzer.props @@ -4,6 +4,6 @@ - + From 16ed9e7bc92a88e6e37d304a82abc773c99da1c1 Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Mon, 23 Mar 2020 20:03:38 +1000 Subject: [PATCH 06/15] Reorder modifiers (rule SA1206) --- BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs index 924e0cbcef..f80005713a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs @@ -12,7 +12,7 @@ using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS { [Core("MelonDS", "Arisotura", false, false, null, null, true)] - unsafe public partial class MelonDS : IEmulator + public unsafe partial class MelonDS : IEmulator { private BasicServiceProvider _serviceProvider; public IEmulatorServiceProvider ServiceProvider => _serviceProvider; From f50b4e4c54d735d98395ca74052dcb41e0065f00 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 22 Mar 2020 20:21:39 -0500 Subject: [PATCH 07/15] Odyssey2 - fix joypad.get(), apparently lua tables do not like keys that are just "." --- .../Consoles/Magnavox/Odyssey2/O2HawkControllerDeck.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2HawkControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2HawkControllerDeck.cs index 56ab5c2cc6..67f391b2f7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2HawkControllerDeck.cs +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2HawkControllerDeck.cs @@ -36,7 +36,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk "8", "9", "SPC", "?", "L", "P", "+", "W", "E", "R", "T", "U", "I", "O", "Q", "S", "D", "F", "G", "H", "J", "K", - "A", "Z", "X", "C", "V", "B", "M", ".", + "A", "Z", "X", "C", "V", "B", "M", "PERIOD", "-", "*", "/", "=", "YES", "NO", "CLR", "ENT", "Power" }) From 0717878faeed7bf06ad252605419b996bc001a1b Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 22 Mar 2020 20:22:12 -0500 Subject: [PATCH 08/15] Odyssey2 - Virtualpads - cleanup, add Power button --- .../tools/VirtualPads/schema/O2Schema.cs | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/O2Schema.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/O2Schema.cs index 68726ce83f..feca23393f 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/O2Schema.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/O2Schema.cs @@ -12,19 +12,9 @@ namespace BizHawk.Client.EmuHawk { public IEnumerable GetPadSchemas(IEmulator core) { - var O2SyncSettings = ((O2Hawk)core).GetSyncSettings().Clone(); - // var port1 = O2SyncSettings.Port1; - // var port2 = O2SyncSettings.Port2; - - // if (port1 == "O2 Controller") - // { - yield return StandardController(1); - // } - - // if (port2 == "O2 Controller") - // { - yield return StandardController(2); - // } + yield return StandardController(1); + yield return StandardController(2); + yield return ConsoleButtons(); } private static PadSchema StandardController(int controller) @@ -42,5 +32,17 @@ namespace BizHawk.Client.EmuHawk } }; } + + private static PadSchema ConsoleButtons() + { + return new ConsoleSchema + { + Size = new Size(75, 50), + Buttons = new[] + { + new ButtonSchema(10, 15, "Power") + } + }; + } } } From 7aa0b08dd53a5dde8de29f8a4b5e16e03f1d7086 Mon Sep 17 00:00:00 2001 From: adelikat Date: Mon, 23 Mar 2020 14:05:40 -0500 Subject: [PATCH 09/15] O2 virtualpad - add keyboard --- .../tools/VirtualPads/schema/O2Schema.cs | 68 ++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/O2Schema.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/O2Schema.cs index feca23393f..d405a39ce3 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/O2Schema.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/O2Schema.cs @@ -1,8 +1,6 @@ using System.Collections.Generic; using System.Drawing; - using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Consoles.O2Hawk; namespace BizHawk.Client.EmuHawk { @@ -14,6 +12,7 @@ namespace BizHawk.Client.EmuHawk { yield return StandardController(1); yield return StandardController(2); + yield return KeyboardButtons(); yield return ConsoleButtons(); } @@ -33,6 +32,71 @@ namespace BizHawk.Client.EmuHawk }; } + private static PadSchema KeyboardButtons() + { + return new PadSchema + { + Size = new Size(275, 200), + Buttons = new[] + { + new ButtonSchema(8, 14, "0"), + new ButtonSchema(33, 14, "1"), + new ButtonSchema(58, 14, "2"), + new ButtonSchema(83, 14, "3"), + new ButtonSchema(108, 14, "4"), + new ButtonSchema(133, 14, "5"), + new ButtonSchema(158, 14, "6"), + new ButtonSchema(183, 14, "7"), + new ButtonSchema(208, 14, "8"), + new ButtonSchema(233, 14, "9"), + + new ButtonSchema(8, 44, "+"), + new ButtonSchema(33, 44, "-"), + new ButtonSchema(58, 44, "*") { DisplayName = "x"}, + new ButtonSchema(83, 44, "/") { DisplayName = "÷" }, + new ButtonSchema(108, 44, "="), + new ButtonSchema(133, 44, "YES") { DisplayName = "y" }, + new ButtonSchema(158, 44, "NO") { DisplayName = "n" }, + new ButtonSchema(183, 44, "CLR") { DisplayName = "cl" }, + new ButtonSchema(216, 44, "ENT") { DisplayName = "enter" }, + + new ButtonSchema(8, 74, "Q"), + new ButtonSchema(33, 74, "W"), + new ButtonSchema(58, 74, "E"), + new ButtonSchema(83, 74, "R"), + new ButtonSchema(108, 74, "T"), + new ButtonSchema(133, 74, "YES") { DisplayName = "Y" }, + new ButtonSchema(158, 74, "U"), + new ButtonSchema(183, 74, "I"), + new ButtonSchema(208, 74, "O"), + new ButtonSchema(233, 74, "P"), + + new ButtonSchema(20, 104, "A"), + new ButtonSchema(45, 104, "S"), + new ButtonSchema(70, 104, "D"), + new ButtonSchema(95, 104, "F"), + new ButtonSchema(120, 104, "G"), + new ButtonSchema(145, 104, "H"), + new ButtonSchema(170, 104, "J"), + new ButtonSchema(195, 104, "K"), + new ButtonSchema(220, 104, "L"), + + + new ButtonSchema(33, 134, "Z"), + new ButtonSchema(58, 134, "X"), + new ButtonSchema(83, 134, "C"), + new ButtonSchema(108, 134, "V"), + new ButtonSchema(133, 134, "B"), + new ButtonSchema(158, 134, "NO") { DisplayName = "N" }, + new ButtonSchema(183, 134, "M"), + new ButtonSchema(208, 134, "PERIOD") { DisplayName = "." }, + new ButtonSchema(233, 134, "?"), + + new ButtonSchema(95, 164, "SPC") { DisplayName = " SPACE " } + } + }; + } + private static PadSchema ConsoleButtons() { return new ConsoleSchema From 8988c9bb8f6a0de8e32f59acf403fcc287cf4941 Mon Sep 17 00:00:00 2001 From: adelikat Date: Mon, 23 Mar 2020 14:06:05 -0500 Subject: [PATCH 10/15] O2 - bk2 mnemonics for some missing buttons --- BizHawk.Client.Common/movie/bk2/Bk2MnemonicConstants.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/BizHawk.Client.Common/movie/bk2/Bk2MnemonicConstants.cs b/BizHawk.Client.Common/movie/bk2/Bk2MnemonicConstants.cs index f0db06e68d..d01e89b862 100644 --- a/BizHawk.Client.Common/movie/bk2/Bk2MnemonicConstants.cs +++ b/BizHawk.Client.Common/movie/bk2/Bk2MnemonicConstants.cs @@ -424,6 +424,15 @@ namespace BizHawk.Client.Common { ["Lid"] = 'P', ["Touch"] = 'T' + }, + ["O2"] = new Dictionary + { + ["PERIOD"] = '.', + ["SPC"] = 's', + ["YES"] = 'y', + ["NO"] = 'n', + ["CLR"] = 'c', + ["ENT"] = 'e' } }; } From c5043d2ec384ac08e522cf34a221f07caf3eede5 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 23 Mar 2020 21:21:42 -0400 Subject: [PATCH 11/15] O2Hawk: fix PAl timing a bit --- .../Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs | 4 +--- .../Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs index 52a1b25e05..4618d1b4cb 100644 --- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs @@ -12,6 +12,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk public bool in_vblank_old; public bool in_vblank; public bool vblank_rise; + public uint ticker; public bool FrameAdvance(IController controller, bool render, bool rendersound) { @@ -59,8 +60,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk { // PAL timing is: 17.7 / 5 ppu // and 17.7 / 9 for cpu (divide by 3 externally then by 3 again internally) - int ticker = 0; - while (frame_chk) { ticker++; @@ -68,7 +67,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk if ((ticker % 5) == 0) { ppu.tick(); - if ((ticker % 10) == 0) { ppu.Audio_tick(); diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs index 394705f00b..1c89f6127a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs @@ -32,6 +32,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk ser.Sync(nameof(in_vblank), ref in_vblank); ser.Sync(nameof(in_vblank_old), ref in_vblank_old); ser.Sync(nameof(vblank_rise), ref vblank_rise); + ser.Sync(nameof(ticker), ref ticker); ser.Sync(nameof(RAM_en), ref RAM_en); ser.Sync(nameof(ppu_en), ref ppu_en); From 26619d367b7f05f46bcaa0a619e47a4d74aeb920 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 23 Mar 2020 21:30:06 -0400 Subject: [PATCH 12/15] O2Hawk: remove some unused code --- .../Magnavox/Odyssey2/O2Hawk.IEmulator.cs | 3 - .../Magnavox/Odyssey2/O2Hawk.IStatable.cs | 1 - .../Consoles/Magnavox/Odyssey2/O2Hawk.cs | 5 - .../Consoles/Magnavox/Odyssey2/ReadMe.txt | 1 - .../Consoles/Magnavox/Odyssey2/SerialPort.cs | 147 ------------------ 5 files changed, 157 deletions(-) delete mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/ReadMe.txt delete mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/SerialPort.cs diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs index 4618d1b4cb..04ccc5bd21 100644 --- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs @@ -75,7 +75,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk if ((ticker % 9) == 0) { - serialport.serial_transfer_tick(); cpu.ExecuteOne(); } @@ -94,7 +93,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk { ppu.tick(); ppu.tick(); - serialport.serial_transfer_tick(); ppu.Audio_tick(); cpu.ExecuteOne(); @@ -112,7 +110,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk { ppu.tick(); ppu.tick(); - serialport.serial_transfer_tick(); ppu.Audio_tick(); cpu.ExecuteOne(); diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs index 1c89f6127a..17bc6a5a25 100644 --- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs @@ -19,7 +19,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk cpu.SyncState(ser); mapper.SyncState(ser); ppu.SyncState(ser); - serialport.SyncState(ser); ser.Sync(nameof(core), ref core, false); ser.Sync("Lag", ref _lagcount); diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs index 63b990249c..3ba5ca80a7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs @@ -37,7 +37,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk public I8048 cpu; public PPU ppu; - public SerialPort serialport; public bool is_pal; @@ -56,8 +55,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk WritePort = WritePort, OnExecFetch = ExecFetch, }; - - serialport = new SerialPort(); _settings = (O2Settings)settings ?? new O2Settings(); _syncSettings = (O2SyncSettings)syncSettings ?? new O2SyncSettings(); @@ -86,7 +83,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk ppu.Core = this; cpu.Core = this; - serialport.Core = this; ser.Register(this); ser.Register(ppu); @@ -134,7 +130,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk WritePort(2, 0xFF); ppu.Reset(); - serialport.Reset(); cpu.SetCallbacks(ReadMemory, PeekMemory, PeekMemory, WriteMemory); } diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/ReadMe.txt b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/ReadMe.txt deleted file mode 100644 index bc60bf4b01..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/ReadMe.txt +++ /dev/null @@ -1 +0,0 @@ -TODO: diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/SerialPort.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/SerialPort.cs deleted file mode 100644 index a3e4cf3bc4..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/SerialPort.cs +++ /dev/null @@ -1,147 +0,0 @@ -using BizHawk.Common; - -namespace BizHawk.Emulation.Cores.Consoles.O2Hawk -{ - public class SerialPort - { - public O2Hawk Core { get; set; } - - public byte serial_control; - public byte serial_data; - public bool serial_start; - public bool can_pulse; - public int serial_clock; - public int serial_bits; - public int clk_rate; - public byte going_out; - public byte coming_in; - - public byte ReadReg(int addr) - { - switch (addr) - { - case 0xFF01: - return serial_data; - case 0xFF02: - return serial_control; - } - - return 0xFF; - } - - public void WriteReg(int addr, byte 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)) - { - 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)) - { - 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; - } - } - - serial_control = (byte)(0x7E | (value & 0x81)); // middle six bits always 1 - - break; - } - } - - - public void serial_transfer_tick() - { - if (serial_start) - { - if (serial_clock > 0) { serial_clock--; } - - if (serial_clock == 0) - { - if (serial_bits > 0) - { - byte temp = coming_in; - serial_data = (byte)((serial_data << 1) | temp); - - serial_bits--; - - if (serial_bits == 0) - { - serial_control &= 0x7F; - serial_start = false; - } - else - { - serial_clock = clk_rate; - if (clk_rate > 0) { can_pulse = true; } - } - } - } - } - } - - public void Reset() - { - serial_control = 0x7E; - serial_start = false; - serial_data = 0x00; - going_out = 0; - coming_in = 1; - } - - public void SyncState(Serializer ser) - { - ser.Sync(nameof(serial_control), ref serial_control); - ser.Sync(nameof(serial_data), ref serial_data); - ser.Sync(nameof(serial_start), ref serial_start); - ser.Sync(nameof(serial_clock), ref serial_clock); - ser.Sync(nameof(serial_bits), ref serial_bits); - ser.Sync(nameof(clk_rate), ref clk_rate); - ser.Sync(nameof(going_out), ref going_out); - ser.Sync(nameof(coming_in), ref coming_in); - ser.Sync(nameof(can_pulse), ref can_pulse); - } - } -} From d0cf22039190cac921bc09149d393f9c3db94717 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 24 Mar 2020 12:05:49 -0400 Subject: [PATCH 13/15] GBHawk: start C++'ification --- libHawk/GBHawk/GBHawk.sln | 31 + libHawk/GBHawk/GBHawk/AY_3_8910.h | 442 ++++ libHawk/GBHawk/GBHawk/Core.h | 271 ++ libHawk/GBHawk/GBHawk/GBHawk.cpp | 131 + libHawk/GBHawk/GBHawk/GBHawk.h | 5 + libHawk/GBHawk/GBHawk/GBHawk.vcxproj | 172 ++ libHawk/GBHawk/GBHawk/LR35902.cpp | 29 + libHawk/GBHawk/GBHawk/LR35902.h | 3431 ++++++++++++++++++++++++++ libHawk/GBHawk/GBHawk/Memory.cpp | 229 ++ libHawk/GBHawk/GBHawk/Memory.h | 138 ++ libHawk/GBHawk/GBHawk/TMS9918A.h | 610 +++++ libHawk/GBHawk/GBHawk/cpp.hint | 2 + 12 files changed, 5491 insertions(+) create mode 100644 libHawk/GBHawk/GBHawk.sln create mode 100644 libHawk/GBHawk/GBHawk/AY_3_8910.h create mode 100644 libHawk/GBHawk/GBHawk/Core.h create mode 100644 libHawk/GBHawk/GBHawk/GBHawk.cpp create mode 100644 libHawk/GBHawk/GBHawk/GBHawk.h create mode 100644 libHawk/GBHawk/GBHawk/GBHawk.vcxproj create mode 100644 libHawk/GBHawk/GBHawk/LR35902.cpp create mode 100644 libHawk/GBHawk/GBHawk/LR35902.h create mode 100644 libHawk/GBHawk/GBHawk/Memory.cpp create mode 100644 libHawk/GBHawk/GBHawk/Memory.h create mode 100644 libHawk/GBHawk/GBHawk/TMS9918A.h create mode 100644 libHawk/GBHawk/GBHawk/cpp.hint diff --git a/libHawk/GBHawk/GBHawk.sln b/libHawk/GBHawk/GBHawk.sln new file mode 100644 index 0000000000..3a944659dd --- /dev/null +++ b/libHawk/GBHawk/GBHawk.sln @@ -0,0 +1,31 @@ + +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/AY_3_8910.h b/libHawk/GBHawk/GBHawk/AY_3_8910.h new file mode 100644 index 0000000000..4892c2af17 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/AY_3_8910.h @@ -0,0 +1,442 @@ +#include +#include +#include +#include + +using namespace std; + +namespace GBHawk +{ + class AY_3_8910 + { + public: + + #pragma region AY_3_8910 + + AY_3_8910() + { + Reset(); + } + + bool A_on, B_on, C_on; + bool A_up, B_up, C_up; + bool A_noise, B_noise, C_noise; + bool env_vol_A, env_vol_B, env_vol_C; + + uint8_t env_shape; + uint8_t port_sel; + uint8_t vol_A, vol_B, vol_C; + uint8_t Register[16] = {}; + + uint32_t psg_clock; + uint32_t sq_per_A, sq_per_B, sq_per_C; + uint32_t clock_A, clock_B, clock_C; + + uint32_t env_per; + uint32_t env_clock; + + int32_t env_E; + int32_t E_up_down; + + uint32_t noise_clock; + uint32_t noise_per; + uint32_t noise = 0x1; + + int32_t old_sample; + + // non stated if only on frame boundaries + bool sound_out_A; + bool sound_out_B; + bool sound_out_C; + + uint8_t Clock_Divider; + + int32_t current_sample; + uint32_t sampleclock; + uint32_t num_samples; + int32_t samples[9000] = {}; + + void Reset() + { + clock_A = clock_B = clock_C = 0x1000; + noise_clock = 0x20; + port_sel = 0; + + for (int i = 0; i < 16; i++) + { + Register[i] = 0x0; + } + sync_psg_state(); + } + + short Sample() + { + return current_sample; + } + + const uint32_t VolumeTable[16] = + { + 0x0000, 0x0055, 0x0079, 0x00AB, 0x00F1, 0x0155, 0x01E3, 0x02AA, + 0x03C5, 0x0555, 0x078B, 0x0AAB, 0x0F16, 0x1555, 0x1E2B, 0x2AAA + }; + + uint8_t ReadReg() + { + return Register[port_sel]; + } + + void sync_psg_state() + { + sq_per_A = (Register[0] & 0xFF) | (((Register[1] & 0xF) << 8)); + if (sq_per_A == 0) + { + sq_per_A = 0x1000; + } + + sq_per_B = (Register[2] & 0xFF) | (((Register[3] & 0xF) << 8)); + if (sq_per_B == 0) + { + sq_per_B = 0x1000; + } + + sq_per_C = (Register[4] & 0xFF) | (((Register[5] & 0xF) << 8)); + if (sq_per_C == 0) + { + sq_per_C = 0x1000; + } + + env_per = (Register[11] & 0xFF) | (((Register[12] & 0xFF) << 8)); + if (env_per == 0) + { + env_per = 0x10000; + } + + env_per *= 2; + + A_on = (Register[7] & 0x1) > 0; + B_on = (Register[7] & 0x2) > 0; + C_on = (Register[7] & 0x4) > 0; + A_noise = (Register[7] & 0x8) > 0; + B_noise = (Register[7] & 0x10) > 0; + C_noise = (Register[7] & 0x20) > 0; + + noise_per = Register[6] & 0x1F; + if (noise_per == 0) + { + noise_per = 0x20; + } + + uint8_t shape_select = Register[13] & 0xF; + + if (shape_select < 4) { env_shape = 0; } + else if (shape_select < 8) { env_shape = 1; } + else { env_shape = 2 + (shape_select - 8); } + + vol_A = Register[8] & 0xF; + env_vol_A = ((Register[8] >> 4) & 0x1) > 0; + + vol_B = Register[9] & 0xF; + env_vol_B = ((Register[9] >> 4) & 0x1) > 0; + + vol_C = Register[10] & 0xF; + env_vol_C = ((Register[10] >> 4) & 0x1) > 0; + } + + void WriteReg(uint8_t value) + { + value &= 0xFF; + + if (port_sel != 0xE) { Register[port_sel] = value; } + + + sync_psg_state(); + + if (port_sel == 13) + { + env_clock = env_per; + + if (env_shape == 0 || env_shape == 2 || env_shape == 3 || env_shape == 4 || env_shape == 5) + { + env_E = 15; + E_up_down = -1; + } + else + { + env_E = 0; + E_up_down = 1; + } + } + } + + void generate_sound() + { + // there are 8 cpu cycles for every psg cycle + clock_A--; + clock_B--; + clock_C--; + + noise_clock--; + env_clock--; + + // clock noise + if (noise_clock == 0) + { + noise = (noise >> 1) ^ (((noise &0x1) > 0) ? 0x10004 : 0); + noise_clock = noise_per; + } + + if (env_clock == 0) + { + env_clock = env_per; + + env_E += E_up_down; + + if (env_E == 16 || env_E == -1) + { + // we just completed a period of the envelope, determine what to do now based on the envelope shape + if (env_shape == 0 || env_shape == 1 || env_shape == 3 || env_shape == 9) + { + E_up_down = 0; + env_E = 0; + } + else if (env_shape == 5 || env_shape == 7) + { + E_up_down = 0; + env_E = 15; + } + else if (env_shape == 4 || env_shape == 8) + { + if (env_E == 16) + { + env_E = 15; + E_up_down = -1; + } + else + { + env_E = 0; + E_up_down = 1; + } + } + else if (env_shape == 2) + { + env_E = 15; + } + else + { + env_E = 0; + } + } + } + + if (clock_A == 0) + { + A_up = !A_up; + clock_A = sq_per_A; + } + + if (clock_B == 0) + { + B_up = !B_up; + clock_B = sq_per_B; + } + + if (clock_C == 0) + { + C_up = !C_up; + clock_C = sq_per_C; + } + + sound_out_A = (((noise & 0x1) > 0) | A_noise) & (A_on | A_up); + sound_out_B = (((noise & 0x1) > 0) | B_noise) & (B_on | B_up); + sound_out_C = (((noise & 0x1) > 0) | C_noise) & (C_on | C_up); + + // now calculate the volume of each channel and add them together + current_sample = 0; + + if (env_vol_A) + { + current_sample = (sound_out_A ? VolumeTable[env_E] : 0); + } + else + { + current_sample = (sound_out_A ? VolumeTable[vol_A] : 0); + } + + if (env_vol_B) + { + current_sample += (sound_out_B ? VolumeTable[env_E] : 0); + } + else + { + current_sample += (sound_out_B ? VolumeTable[vol_B] : 0); + } + + if (env_vol_C) + { + current_sample += (sound_out_C ? VolumeTable[env_E] : 0); + } + else + { + current_sample += (sound_out_C ? VolumeTable[vol_C] : 0); + } + + current_sample *= 2; + + if ((current_sample != old_sample) && (num_samples < 4500)) + { + samples[num_samples * 2] = sampleclock; + samples[num_samples * 2 + 1] = current_sample - old_sample; + num_samples++; + old_sample = current_sample; + } + } + + #pragma endregion + + #pragma region State Save / Load + + uint8_t* SaveState(uint8_t* saver) + { + *saver = (uint8_t)(A_on ? 1 : 0); saver++; + *saver = (uint8_t)(B_on ? 1 : 0); saver++; + *saver = (uint8_t)(C_on ? 1 : 0); saver++; + *saver = (uint8_t)(A_up ? 1 : 0); saver++; + *saver = (uint8_t)(B_up ? 1 : 0); saver++; + *saver = (uint8_t)(C_up ? 1 : 0); saver++; + *saver = (uint8_t)(A_noise ? 1 : 0); saver++; + *saver = (uint8_t)(B_noise ? 1 : 0); saver++; + *saver = (uint8_t)(C_noise ? 1 : 0); saver++; + *saver = (uint8_t)(env_vol_A ? 1 : 0); saver++; + *saver = (uint8_t)(env_vol_B ? 1 : 0); saver++; + *saver = (uint8_t)(env_vol_C ? 1 : 0); saver++; + + *saver = env_shape; saver++; + *saver = port_sel; saver++; + *saver = vol_A; saver++; + *saver = vol_B; saver++; + *saver = vol_C; saver++; + + for (int i = 0; i < 16; i++) { *saver = Register[i]; saver++; } + + *saver = (uint8_t)(psg_clock & 0xFF); saver++; *saver = (uint8_t)((psg_clock >> 8) & 0xFF); saver++; + *saver = (uint8_t)((psg_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((psg_clock >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(sq_per_A & 0xFF); saver++; *saver = (uint8_t)((sq_per_A >> 8) & 0xFF); saver++; + *saver = (uint8_t)((sq_per_A >> 16) & 0xFF); saver++; *saver = (uint8_t)((sq_per_A >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(sq_per_B & 0xFF); saver++; *saver = (uint8_t)((sq_per_B >> 8) & 0xFF); saver++; + *saver = (uint8_t)((sq_per_B >> 16) & 0xFF); saver++; *saver = (uint8_t)((sq_per_B >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(sq_per_C & 0xFF); saver++; *saver = (uint8_t)((sq_per_C >> 8) & 0xFF); saver++; + *saver = (uint8_t)((sq_per_C >> 16) & 0xFF); saver++; *saver = (uint8_t)((sq_per_C >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(clock_A & 0xFF); saver++; *saver = (uint8_t)((clock_A >> 8) & 0xFF); saver++; + *saver = (uint8_t)((clock_A >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_A >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(clock_B & 0xFF); saver++; *saver = (uint8_t)((clock_B >> 8) & 0xFF); saver++; + *saver = (uint8_t)((clock_B >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_B >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(clock_C & 0xFF); saver++; *saver = (uint8_t)((clock_C >> 8) & 0xFF); saver++; + *saver = (uint8_t)((clock_C >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_C >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(env_per & 0xFF); saver++; *saver = (uint8_t)((env_per >> 8) & 0xFF); saver++; + *saver = (uint8_t)((env_per >> 16) & 0xFF); saver++; *saver = (uint8_t)((env_per >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(env_clock & 0xFF); saver++; *saver = (uint8_t)((env_clock >> 8) & 0xFF); saver++; + *saver = (uint8_t)((env_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((env_clock >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(env_E & 0xFF); saver++; *saver = (uint8_t)((env_E >> 8) & 0xFF); saver++; + *saver = (uint8_t)((env_E >> 16) & 0xFF); saver++; *saver = (uint8_t)((env_E >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(E_up_down & 0xFF); saver++; *saver = (uint8_t)((E_up_down >> 8) & 0xFF); saver++; + *saver = (uint8_t)((E_up_down >> 16) & 0xFF); saver++; *saver = (uint8_t)((E_up_down >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(noise_clock & 0xFF); saver++; *saver = (uint8_t)((noise_clock >> 8) & 0xFF); saver++; + *saver = (uint8_t)((noise_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise_clock >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(noise_per & 0xFF); saver++; *saver = (uint8_t)((noise_per >> 8) & 0xFF); saver++; + *saver = (uint8_t)((noise_per >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise_per >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(noise & 0xFF); saver++; *saver = (uint8_t)((noise >> 8) & 0xFF); saver++; + *saver = (uint8_t)((noise >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(old_sample & 0xFF); saver++; *saver = (uint8_t)((old_sample >> 8) & 0xFF); saver++; + *saver = (uint8_t)((old_sample >> 16) & 0xFF); saver++; *saver = (uint8_t)((old_sample >> 24) & 0xFF); saver++; + + return saver; + } + + uint8_t* LoadState(uint8_t* loader) + { + A_on = *loader == 1; loader++; + B_on = *loader == 1; loader++; + C_on = *loader == 1; loader++; + A_up = *loader == 1; loader++; + B_up = *loader == 1; loader++; + C_up = *loader == 1; loader++; + A_noise = *loader == 1; loader++; + B_noise = *loader == 1; loader++; + C_noise = *loader == 1; loader++; + env_vol_A = *loader == 1; loader++; + env_vol_B = *loader == 1; loader++; + env_vol_C = *loader == 1; loader++; + + env_shape = *loader; loader++; + port_sel = *loader; loader++; + vol_A = *loader; loader++; + vol_B = *loader; loader++; + vol_C = *loader; loader++; + + for (int i = 0; i < 16; i++) { Register[i] = *loader; loader++; } + + psg_clock = *loader; loader++; psg_clock |= (*loader << 8); loader++; + psg_clock |= (*loader << 16); loader++; psg_clock |= (*loader << 24); loader++; + + sq_per_A = *loader; loader++; sq_per_A |= (*loader << 8); loader++; + sq_per_A |= (*loader << 16); loader++; sq_per_A |= (*loader << 24); loader++; + + sq_per_B = *loader; loader++; sq_per_B |= (*loader << 8); loader++; + sq_per_B |= (*loader << 16); loader++; sq_per_B |= (*loader << 24); loader++; + + sq_per_C = *loader; loader++; sq_per_C |= (*loader << 8); loader++; + sq_per_C |= (*loader << 16); loader++; sq_per_C |= (*loader << 24); loader++; + + clock_A = *loader; loader++; clock_A |= (*loader << 8); loader++; + clock_A |= (*loader << 16); loader++; clock_A |= (*loader << 24); loader++; + + clock_B = *loader; loader++; clock_B |= (*loader << 8); loader++; + clock_B |= (*loader << 16); loader++; clock_B |= (*loader << 24); loader++; + + clock_C = *loader; loader++; clock_C |= (*loader << 8); loader++; + clock_C |= (*loader << 16); loader++; clock_C |= (*loader << 24); loader++; + + env_per = *loader; loader++; env_per |= (*loader << 8); loader++; + env_per |= (*loader << 16); loader++; env_per |= (*loader << 24); loader++; + + env_clock = *loader; loader++; env_clock |= (*loader << 8); loader++; + env_clock |= (*loader << 16); loader++; env_clock |= (*loader << 24); loader++; + + env_E = *loader; loader++; env_E |= (*loader << 8); loader++; + env_E |= (*loader << 16); loader++; env_E |= (*loader << 24); loader++; + + E_up_down = *loader; loader++; E_up_down |= (*loader << 8); loader++; + E_up_down |= (*loader << 16); loader++; E_up_down |= (*loader << 24); loader++; + + noise_clock = *loader; loader++; noise_clock |= (*loader << 8); loader++; + noise_clock |= (*loader << 16); loader++; noise_clock |= (*loader << 24); loader++; + + noise_per = *loader; loader++; noise_per |= (*loader << 8); loader++; + noise_per |= (*loader << 16); loader++; noise_per |= (*loader << 24); loader++; + + noise = *loader; loader++; noise |= (*loader << 8); loader++; + noise |= (*loader << 16); loader++; noise |= (*loader << 24); loader++; + + old_sample = *loader; loader++; old_sample |= (*loader << 8); loader++; + old_sample |= (*loader << 16); loader++; old_sample |= (*loader << 24); loader++; + + return loader; + } + + #pragma endregion + }; +} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/Core.h b/libHawk/GBHawk/GBHawk/Core.h new file mode 100644 index 0000000000..d937b697cb --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Core.h @@ -0,0 +1,271 @@ +#include +#include +#include +#include + +#include "LR35902.h" +#include "AY_3_8910.h" +#include "TMS9918A.h" +#include "Memory.h" + +namespace GBHawk +{ + class GBCore + { + public: + GBCore() + { + MemMap.cpu_pntr = &cpu; + MemMap.vdp_pntr = &vdp; + MemMap.psg_pntr = &psg; + cpu.mem_ctrl = &MemMap; + vdp.IRQ_PTR = &cpu.FlagI; + vdp.SHOW_BG = vdp.SHOW_SPRITES = true; + psg.Clock_Divider = 16; + sl_case = 0; + }; + + TMS9918A vdp; + Z80A cpu; + AY_3_8910 psg; + MemoryManager MemMap; + + uint8_t sl_case = 0; + + void Load_BIOS(uint8_t* bios, uint8_t* basic) + { + MemMap.Load_BIOS(bios, basic); + } + + void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1, uint32_t ext_rom_mapper_1, uint8_t* ext_rom_2, uint32_t ext_rom_size_2, uint32_t ext_rom_mapper_2) + { + MemMap.Load_ROM(ext_rom_1, ext_rom_size_1, ext_rom_mapper_1, ext_rom_2, ext_rom_size_2, ext_rom_mapper_2); + } + + bool FrameAdvance(uint8_t controller_1, uint8_t controller_2, uint8_t* kb_rows_ptr, bool render, bool rendersound) + { + if ((MemMap.psg_pntr->Register[0xF] & 0x40) > 0) + { + MemMap.psg_pntr->Register[0xE] = controller_2; + } + else + { + MemMap.psg_pntr->Register[0xE] = controller_1; + } + + MemMap.controller_byte_1 = controller_1; + MemMap.controller_byte_2 = controller_2; + MemMap.kb_rows = kb_rows_ptr; + MemMap.start_pressed = (controller_1 & 0x80) > 0; + MemMap.lagged = true; + + uint32_t scanlinesPerFrame = 262; + vdp.SpriteLimit = true; + + psg.num_samples = 0; + psg.sampleclock = 0; + + for (uint32_t i = 0; i < scanlinesPerFrame; i++) + { + vdp.ScanLine = i; + + vdp.RenderScanline(i); + + if (vdp.ScanLine == 192) + { + vdp.InterruptPendingSet(true); + + if (vdp.EnableInterrupts()) { cpu.FlagI = true; } + } + + switch (sl_case) + { + case 0: + for (int i = 0; i < 14; i++) + { + cpu.ExecuteOne(16); + psg.sampleclock+=16; + psg.generate_sound(); + } + cpu.ExecuteOne(4); + psg.sampleclock += 4; + sl_case = 1; + break; + + case 1: + cpu.ExecuteOne(12); + psg.sampleclock += 12; + psg.generate_sound(); + + for (int i = 0; i < 13; i++) + { + cpu.ExecuteOne(16); + psg.sampleclock += 16; + psg.generate_sound(); + } + cpu.ExecuteOne(8); + psg.sampleclock += 8; + sl_case = 2; + break; + + case 2: + cpu.ExecuteOne(8); + psg.sampleclock += 8; + psg.generate_sound(); + + for (int i = 0; i < 13; i++) + { + cpu.ExecuteOne(16); + psg.sampleclock += 16; + psg.generate_sound(); + } + cpu.ExecuteOne(12); + psg.sampleclock += 12; + sl_case = 3; + break; + case 3: + cpu.ExecuteOne(4); + psg.sampleclock += 4; + psg.generate_sound(); + + for (int i = 0; i < 14; i++) + { + cpu.ExecuteOne(16); + psg.sampleclock += 16; + psg.generate_sound(); + } + sl_case = 0; + break; + } + } + + return MemMap.lagged; + } + + void GetVideo(uint32_t* dest) + { + uint32_t* src = vdp.FrameBuffer; + uint32_t* dst = dest; + + std::memcpy(dst, src, sizeof uint32_t * 256 * 192); + } + + uint32_t GetAudio(int32_t* dest, int32_t* n_samp) + { + int32_t* src = psg.samples; + int32_t* dst = dest; + + std::memcpy(dst, src, sizeof int32_t * psg.num_samples * 2); + n_samp[0] = psg.num_samples; + + return psg.sampleclock; + } + + #pragma region State Save / Load + + void SaveState(uint8_t* saver) + { + saver = vdp.SaveState(saver); + saver = cpu.SaveState(saver); + saver = psg.SaveState(saver); + saver = MemMap.SaveState(saver); + + *saver = sl_case; saver++; + } + + void LoadState(uint8_t* loader) + { + loader = vdp.LoadState(loader); + loader = cpu.LoadState(loader); + loader = psg.LoadState(loader); + loader = MemMap.LoadState(loader); + + sl_case = *loader; loader++; + } + + #pragma endregion + + #pragma region Memory Domain Functions + + uint8_t GetSysBus(uint32_t addr) + { + cpu.bank_num = cpu.bank_offset = addr & 0xFFFF; + cpu.bank_offset &= cpu.low_mask; + cpu.bank_num = (cpu.bank_num >> cpu.bank_shift)& cpu.high_mask; + + return cpu.MemoryMap[cpu.bank_num][cpu.bank_offset]; + } + + uint8_t GetVRAM(uint32_t addr) + { + return vdp.VRAM[addr & 0x3FFF]; + } + + uint8_t GetRAM(uint32_t addr) + { + return MemMap.ram[addr & 0xFFFF]; + } + + #pragma endregion + + #pragma region Tracer + + void SetTraceCallback(void (*callback)(int)) + { + cpu.TraceCallback = callback; + } + + int GetHeaderLength() + { + return 105 + 1; + } + + int GetDisasmLength() + { + return 48 + 1; + } + + int GetRegStringLength() + { + return 86 + 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.NMI_event, l); + } + else + { + memcpy(d, cpu.IRQ_event, l); + } + } + + #pragma endregion + }; +} + diff --git a/libHawk/GBHawk/GBHawk/GBHawk.cpp b/libHawk/GBHawk/GBHawk/GBHawk.cpp new file mode 100644 index 0000000000..cbdc64dbb7 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/GBHawk.cpp @@ -0,0 +1,131 @@ +// 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.basic_rom; + delete p->MemMap.rom_1; + delete p->MemMap.rom_2; + std::free(p); +} + +// load bios and basic into the core +GBHawk_EXPORT void GB_load_bios(GBCore* p, uint8_t* bios, uint8_t* basic) +{ + p->Load_BIOS(bios, basic); +} + +// load a rom into the core +GBHawk_EXPORT void GB_load(GBCore* p, uint8_t* rom_1, uint32_t size_1, uint32_t mapper_1, uint8_t* rom_2, uint32_t size_2, uint8_t mapper_2) +{ + p->Load_ROM(rom_1, size_1, mapper_1, rom_2, size_2, mapper_2); +} + +// advance a frame +GBHawk_EXPORT bool GB_frame_advance(GBCore* p, uint8_t ctrl1, uint8_t ctrl2, uint8_t* kbrows, bool render, bool sound) +{ + return p->FrameAdvance(ctrl1, ctrl2, kbrows, render, sound); +} + +// 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, int32_t* n_samp) +{ + return p->GetAudio(dest, n_samp); +} + +#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_getsysbus(GBCore* p, uint32_t addr) { + return p->GetSysBus(addr); +} + +GBHawk_EXPORT uint8_t GB_getvram(GBCore* p, uint32_t addr) { + return p->GetVRAM(addr); +} + +GBHawk_EXPORT uint8_t GB_getram(GBCore* p, uint32_t addr) { + return p->GetRAM(addr); +} + +#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 \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/GBHawk.h b/libHawk/GBHawk/GBHawk/GBHawk.h new file mode 100644 index 0000000000..36ab931b4b --- /dev/null +++ b/libHawk/GBHawk/GBHawk/GBHawk.h @@ -0,0 +1,5 @@ +#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 new file mode 100644 index 0000000000..547228280b --- /dev/null +++ b/libHawk/GBHawk/GBHawk/GBHawk.vcxproj @@ -0,0 +1,172 @@ + + + + + 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 + + + + 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 new file mode 100644 index 0000000000..d264e78980 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/LR35902.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +#include "Memory.h" +#include "LR35902.h" + +using namespace std; + +namespace GBHawk +{ + void LR35902::WriteMemory(uint32_t addr, uint8_t value) + { + if ((addr & 0xFFFF) >= 0xFFFC) + { + mem_ctrl->MemoryWrite(addr, value); + } + } + + uint8_t LR35902::ReadMemory(uint32_t addr) + { + return mem_ctrl->HardwareRead(addr); + } + + uint8_t LR35902::SpeedFunc(uint32_t addr) + { + return mem_ctrl->HardwareRead(addr); + } +} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/LR35902.h b/libHawk/GBHawk/GBHawk/LR35902.h new file mode 100644 index 0000000000..0f350d9b49 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/LR35902.h @@ -0,0 +1,3431 @@ +#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; + + // Memory is usually mostly static, so it is efficient to access it with a pointer and write mask + // the size of the pointer matrix and masks is system dependent. + // This also assumes a simple relationship between bank and write mask + // some systems might require more detailed mask, maybe even the same size as read + const uint32_t low_mask = 0x3FF; + const uint32_t high_mask = 0x3F; + const uint32_t bank_shift = 10; + + // these are not savestated as they are automatically adjusted from the memory map upon load + uint32_t bank_num; + uint32_t bank_offset; + uint8_t* MemoryMap[64]; + uint8_t MemoryMapMask[64]; + + void WriteMemory(uint32_t, uint8_t); + uint8_t ReadMemory(uint32_t); + uint8_t SpeedFunc(uint32_t); + + // State variables + uint64_t TotalExecutedCycles; + + uint32_t EI_pending; + bool interrupts_enabled; + + // variables for executing instructions + int instr_pntr = 0; + int opcode; + bool CB_prefix; + bool halted; + bool stopped; + bool jammed; + int LY; + + // unsaved variables + bool checker; + uint8_t Regs[14] = {}; + + bool was_FlagI, FlagI; + + + uint32_t PRE_SRC; + // variables for executing instructions + uint32_t stepper = 0; + uint32_t instr_pntr = 0; + uint32_t bus_pntr = 0; + uint32_t mem_pntr = 0; + uint32_t irq_pntr = 0; + uint32_t IRQS; + uint32_t Ztemp2_saver = 0; + uint32_t IRQS_cond_offset; + + uint64_t TotalExecutedCycles; + + uint32_t* cur_instr_ofst = nullptr; + uint32_t* cur_bus_ofst = nullptr; + uint32_t* cur_mem_ofst = nullptr; + uint32_t* cur_irqs_ofst = nullptr; + + // non-state variables + bool checker; + + + uint32_t Ztemp1, Ztemp2, Ztemp3, Ztemp4; + uint32_t Reg16_d, Reg16_s, ans, temp, carry; + uint32_t cur_instr[60] = {}; // only used for building + uint32_t instr_table[256 * 2 * 60 + 60 * 8] = {}; // compiled instruction table + + #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] = (uint32_t)((Regs[5] & ~0x10) | (value ? 0x10 : 0x00)); } + + inline bool FlagHget() { return (Regs[5] & 0x20) != 0; }; + inline void FlagHset(bool value) { Regs[5] = (uint32_t)((Regs[5] & ~0x20) | (value ? 0x20 : 0x00)); } + + inline bool FlagNget() { return (Regs[5] & 0x40) != 0; }; + inline void FlagNset(bool value) { Regs[5] = (uint32_t)((Regs[5] & ~0x40) | (value ? 0x40 : 0x00)); } + + inline bool FlagZget() { return (Regs[5] & 0x80) != 0; }; + inline void FlagZset(bool value) { Regs[5] = (uint32_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] = (uint32_t)(value & 0xFF); Regs[1] = (uint32_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(uint32_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) { 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++], instr_table[instr_pntr++]); + break; + case WR: + Write_Func(instr_table[instr_pntr++], instr_table[instr_pntr++], instr_table[instr_pntr++]); + break; + case TR: + TR_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]); + break; + case ADD16: + ADD16_Func(instr_table[instr_pntr++], instr_table[instr_pntr++], instr_table[instr_pntr++], instr_table[instr_pntr++]); + break; + case ADD8: + ADD8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]); + break; + case SUB8: + SUB8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]); + break; + case ADC8: + ADC8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]); + break; + case SBC8: + SBC8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]); + break; + case INC16: + INC16_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]); + break; + case INC8: + INC8_Func(instr_table[instr_pntr++]); + break; + case DEC16: + DEC16_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]); + 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++]); + break; + case XOR8: + XOR8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]); + break; + case OR8: + OR8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]); + break; + case CP8: + CP8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]); + 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++]); + break; + case RES: + RES_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]); + break; + case SET: + SET_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]); + break; + case EI: + if (EI_pending == 0) { EI_pending = 2; } + break; + case DI: + interrupts_enabled = false; + EI_pending = 0; + break; + case HALT: + halted = true; + + bool temp = false; + + if (instr_table[instr_pntr++] == 1) + { + temp = FlagI; + } + else + { + temp = 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 (temp && 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 (temp) + { + // 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++]); + break; + case ADDS: + ADDS_Func(instr_table[instr_pntr++], instr_table[instr_pntr++], instr_table[instr_pntr++], instr_table[instr_pntr++]); + 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++], instr_table[instr_pntr++]); + 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 + uint32_t bit_check = instr_table[instr_pntr++]; + //Console.WriteLine(interrupt_src + " " + interrupt_enable + " " + TotalExecutedCycles); + + if (((interrupt_src[0] & (1 << bit_check)) > 0) && ((interrupt_enable & (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]; + 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 -= int_clear; } + + if ((interrupt_src[0] & interrupt_enable) == 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 + + // local variables for operations, not stated + uint32_t Reg16_d, Reg16_s, c; + uint32_t ans, ans_l, ans_h, temp; + uint8_t a_d; + bool imm; + + + 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 + void Read_Func_F(uint32_t dest, uint32_t src_l, uint32_t src_h) + { + Regs[dest] = (uint32_t)(ReadMemory((uint32_t)(Regs[src_l] | (Regs[src_h]) << 8)) & 0xF0); + } + + 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, (uint8_t)Regs[src]); + } + + void TR_Func(uint32_t dest, uint32_t src) + { + Regs[dest] = Regs[src]; + } + + 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] = ans_l; + Regs[dest_h] = ans_h; + } + + 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] = ans; + } + + 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] = ans; + } + + void BIT_Func(uint32_t bit, uint32_t src) + { + FlagZset(!Regs[src].Bit(bit)); + FlagHset(true); + FlagNset(false); + } + + void SET_Func(uint32_t bit, uint32_t src) + { + Regs[src] |= (uint32_t)(1 << bit); + } + + void RES_Func(uint32_t bit, uint32_t src) + { + Regs[src] &= (uint32_t)(0xFF - (1 << bit)); + } + + void ASGN_Func(uint32_t src, uint32_t val) + { + Regs[src] = val; + } + + void SWAP_Func(uint32_t src) + { + temp = (uint32_t)((Regs[src] << 4) & 0xF0); + Regs[src] = (uint32_t)(temp | (Regs[src] >> 4)); + + FlagZset(Regs[src] == 0); + FlagHset(false); + FlagNset(false); + FlagCset(false); + } + + void SLA_Func(uint32_t src) + { + FlagCset(Regs[src].Bit(7)); + + Regs[src] = (uint32_t)((Regs[src] << 1) & 0xFF); + + FlagZset(Regs[src] == 0); + FlagHset(false); + FlagNset(false); + } + + void SRA_Func(uint32_t src) + { + FlagCset(Regs[src].Bit(0)); + + temp = (uint32_t)(Regs[src] & 0x80); // MSB doesn't change in this operation + + Regs[src] = (uint32_t)((Regs[src] >> 1) | temp); + + FlagZset(Regs[src] == 0); + FlagHset(false); + FlagNset(false); + } + + void SRL_Func(uint32_t src) + { + FlagCset(Regs[src].Bit(0)); + + Regs[src] = (uint32_t)(Regs[src] >> 1); + + FlagZset(Regs[src] == 0); + FlagHset(false); + FlagNset(false); + } + + void CPL_Func(uint32_t src) + { + Regs[src] = (uint32_t)((~Regs[src]) & 0xFF); + + FlagHset(true); + FlagNset(true); + } + + void CCF_Func(uint32_t src) + { + FlagCset(!FlagCget()); + FlagHset(false); + FlagNset(false); + } + + void SCF_Func(uint32_t src) + { + FlagCset(true); + FlagHset(false); + FlagNset(false); + } + + void AND8_Func(uint32_t dest, uint32_t src) + { + Regs[dest] = (uint32_t)(Regs[dest] & Regs[src]); + + FlagZset(Regs[dest] == 0); + FlagCset(false); + FlagHset(true); + FlagNset(false); + } + + void OR8_Func(uint32_t dest, uint32_t src) + { + Regs[dest] = (uint32_t)(Regs[dest] | Regs[src]); + + FlagZset(Regs[dest] == 0); + FlagCset(false); + FlagHset(false); + FlagNset(false); + } + + void XOR8_Func(uint32_t dest, uint32_t src) + { + Regs[dest] = (uint32_t)(Regs[dest] ^ Regs[src]); + + FlagZset(Regs[dest] == 0); + FlagCset(false); + FlagHset(false); + FlagNset(false); + } + + 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); + } + + void RRC_Func(uint32_t src) + { + imm = src == Aim; + if (imm) { src = A; } + + FlagCset(Regs[src].Bit(0)); + + Regs[src] = (uint32_t)((FlagCget() ? 0x80 : 0) | (Regs[src] >> 1)); + + FlagZset(imm ? false : (Regs[src] == 0)); + FlagHset(false); + FlagNset(false); + } + + void RR_Func(uint32_t src) + { + imm = src == Aim; + if (imm) { src = A; } + + c = FlagCget() ? 0x80 : 0; + + FlagCset(Regs[src].Bit(0)); + + Regs[src] = (uint32_t)(c | (Regs[src] >> 1)); + + FlagZset(imm ? false : (Regs[src] == 0)); + FlagHset(false); + FlagNset(false); + } + + void RLC_Func(uint32_t src) + { + imm = src == Aim; + if (imm) { src = A; } + + c = Regs[src].Bit(7) ? 1 : 0; + FlagCset(Regs[src].Bit(7)); + + Regs[src] = (uint32_t)(((Regs[src] << 1) & 0xFF) | c); + + FlagZset(imm ? false : (Regs[src] == 0)); + FlagHset(false); + FlagNset(false); + } + + void RL_Func(uint32_t src) + { + imm = src == Aim; + if (imm) { src = A; } + + c = FlagCget() ? 1 : 0; + FlagCset(Regs[src].Bit(7)); + + Regs[src] = (uint32_t)(((Regs[src] << 1) & 0xFF) | c); + + FlagZset(imm ? false : (Regs[src] == 0)); + FlagHset(false); + FlagNset(false); + } + + 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] = ans; + } + + 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] = ans; + } + + 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] = (uint32_t)(Reg16_d & 0xFF); + Regs[src_h] = (uint32_t)((Reg16_d & 0xFF00) >> 8); + } + + 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] = (uint32_t)(Reg16_d & 0xFF); + Regs[src_h] = (uint32_t)((Reg16_d & 0xFF00) >> 8); + } + + 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] = ans; + } + + 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] = ans; + } + + // DA code courtesy of AWJ: http://forums.nesdev.com/viewtopic.php?f=20&t=15944 + 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] = a_d; + + FlagZset(a_d == 0); + FlagHset(false); + } + + // used for signed operations + 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] = ans_l; + Regs[dest_h] += temp; + Regs[dest_h] &= 0xFF; + + } + + #pragma endregion + + #pragma region Disassemble + + // disassemblies will also return strings of the same length + const char* TraceHeader = "Z80A: PC, machine code, mnemonic, operands, registers (AF, BC, DE, HL, IX, IY, SP, Cy), flags (CNP3H5ZS)"; + const char* Un_halt_event = " ==Un-halted== "; + const char* IRQ_event = " ====IRQ==== "; + const char* Un_halt_event = " ==Un-stopped== "; + const char* No_Reg = " "; + const char* Reg_template = "AF:AAFF BC:BBCC DE:DDEE HL:HHLL Ix:IxIx Iy:IyIy SP:SPSP Cy:FEDCBA9876543210 CNP3H5ZSE"; + 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 = "AF:"; + temp_reg = (Regs[A] << 8) + Regs[F]; + sprintf_s(val_char_1, 5, "%04X", temp_reg); + reg_state.append(val_char_1, 4); + + reg_state.append(" BC:"); + temp_reg = (Regs[B] << 8) + Regs[C]; + sprintf_s(val_char_1, 5, "%04X", temp_reg); + reg_state.append(val_char_1, 4); + + reg_state.append(" DE:"); + temp_reg = (Regs[D] << 8) + Regs[E]; + sprintf_s(val_char_1, 5, "%04X", temp_reg); + reg_state.append(val_char_1, 4); + + reg_state.append(" HL:"); + temp_reg = (Regs[H] << 8) + Regs[L]; + sprintf_s(val_char_1, 5, "%04X", temp_reg); + reg_state.append(val_char_1, 4); + + 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", (uint64_t)TotalExecutedCycles)); + 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 ? "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++) + { + bank_num = bank_offset = (RegPCget() + i) & 0xFFFF; + bank_offset &= low_mask; + bank_num = (bank_num >> bank_shift)& high_mask; + + char* val_char_1 = replacer; + sprintf_s(val_char_1, 5, "%02X", MemoryMap[bank_num][bank_offset]); + 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("nn") != string::npos) + { + size_t str_loc = format.find("nn"); + + bank_num = bank_offset = addr[0] & 0xFFFF; + bank_offset &= low_mask; + bank_num = (bank_num >> bank_shift) & high_mask; + addr[0]++; + + val_char_1 = replacer; + sprintf_s(val_char_1, 5, "%02X", MemoryMap[bank_num][bank_offset]); + string val1(val_char_1, 2); + + bank_num = bank_offset = addr[0] & 0xFFFF; + bank_offset &= low_mask; + bank_num = (bank_num >> bank_shift)& high_mask; + addr[0]++; + + val_char_2 = replacer; + sprintf_s(val_char_2, 5, "%02X", MemoryMap[bank_num][bank_offset]); + string val2(val_char_2, 2); + + format.erase(str_loc, 2); + format.insert(str_loc, val1); + format.insert(str_loc, val2); + } + + if (format.find("n") != string::npos) + { + size_t str_loc = format.find("n"); + + bank_num = bank_offset = addr[0] & 0xFFFF; + bank_offset &= low_mask; + bank_num = (bank_num >> bank_shift)& high_mask; + addr[0]++; + + val_char_1 = replacer; + sprintf_s(val_char_1, 5, "%02X", MemoryMap[bank_num][bank_offset]); + string val1(val_char_1, 2); + + format.erase(str_loc, 1); + format.insert(str_loc, val1); + } + + if (format.find("+d") != string::npos) + { + size_t str_loc = format.find("+d"); + + bank_num = bank_offset = addr[0] & 0xFFFF; + bank_offset &= low_mask; + bank_num = (bank_num >> bank_shift)& high_mask; + addr[0]++; + + val_char_1 = replacer; + sprintf_s(val_char_1, 5, "%+04d", (int8_t)MemoryMap[bank_num][bank_offset]); + string val1(val_char_1, 4); + + format.erase(str_loc, 2); + format.insert(str_loc, val1); + } + if (format.find("d") != string::npos) + { + size_t str_loc = format.find("d"); + + bank_num = bank_offset = addr[0] & 0xFFFF; + bank_offset &= low_mask; + bank_num = (bank_num >> bank_shift)& high_mask; + addr[0]++; + + val_char_1 = replacer; + sprintf_s(val_char_1, 5, "%+04d", (int8_t)MemoryMap[bank_num][bank_offset]); + string val1(val_char_1, 4); + + format.erase(str_loc, 1); + 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; + + bank_num = bank_offset = addr & 0xFFFF; + bank_offset &= low_mask; + bank_num = (bank_num >> bank_shift) & high_mask; + addr++; + + uint32_t A = MemoryMap[bank_num][bank_offset]; + string format; + switch (A) + { + case 0xCB: + bank_num = bank_offset = addr & 0xFFFF; + bank_offset &= low_mask; + bank_num = (bank_num >> bank_shift) & high_mask; + addr++; + + A = MemoryMap[bank_num][bank_offset]; + 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", // 00 + "RLC C", // 01 + "RLC D", // 02 + "RLC E", // 03 + "RLC H", // 04 + "RLC L", // 05 + "RLC (HL)", // 06 + "RLC A", // 07 + "RRC B", // 08 + "RRC C", // 09 + "RRC D", // 0a + "RRC E", // 0b + "RRC H", // 0c + "RRC L", // 0d + "RRC (HL)", // 0e + "RRC A", // 0f + "RL B", // 10 + "RL C", // 11 + "RL D", // 12 + "RL E", // 13 + "RL H", // 14 + "RL L", // 15 + "RL (HL)", // 16 + "RL A", // 17 + "RR B", // 18 + "RR C", // 19 + "RR D", // 1a + "RR E", // 1b + "RR H", // 1c + "RR L", // 1d + "RR (HL)", // 1e + "RR A", // 1f + "SLA B", // 20 + "SLA C", // 21 + "SLA D", // 22 + "SLA E", // 23 + "SLA H", // 24 + "SLA L", // 25 + "SLA (HL)", // 26 + "SLA A", // 27 + "SRA B", // 28 + "SRA C", // 29 + "SRA D", // 2a + "SRA E", // 2b + "SRA H", // 2c + "SRA L", // 2d + "SRA (HL)", // 2e + "SRA A", // 2f + "SWAP B", // 30 + "SWAP C", // 31 + "SWAP D", // 32 + "SWAP E", // 33 + "SWAP H", // 34 + "SWAP L", // 35 + "SWAP (HL)", // 36 + "SWAP A", // 37 + "SRL B", // 38 + "SRL C", // 39 + "SRL D", // 3a + "SRL E", // 3b + "SRL H", // 3c + "SRL L", // 3d + "SRL (HL)", // 3e + "SRL A", // 3f + "BIT 0,B", // 40 + "BIT 0,C", // 41 + "BIT 0,D", // 42 + "BIT 0,E", // 43 + "BIT 0,H", // 44 + "BIT 0,L", // 45 + "BIT 0,(HL)", // 46 + "BIT 0,A", // 47 + "BIT 1,B", // 48 + "BIT 1,C", // 49 + "BIT 1,D", // 4a + "BIT 1,E", // 4b + "BIT 1,H", // 4c + "BIT 1,L", // 4d + "BIT 1,(HL)", // 4e + "BIT 1,A", // 4f + "BIT 2,B", // 50 + "BIT 2,C", // 51 + "BIT 2,D", // 52 + "BIT 2,E", // 53 + "BIT 2,H", // 54 + "BIT 2,L", // 55 + "BIT 2,(HL)", // 56 + "BIT 2,A", // 57 + "BIT 3,B", // 58 + "BIT 3,C", // 59 + "BIT 3,D", // 5a + "BIT 3,E", // 5b + "BIT 3,H", // 5c + "BIT 3,L", // 5d + "BIT 3,(HL)", // 5e + "BIT 3,A", // 5f + "BIT 4,B", // 60 + "BIT 4,C", // 61 + "BIT 4,D", // 62 + "BIT 4,E", // 63 + "BIT 4,H", // 64 + "BIT 4,L", // 65 + "BIT 4,(HL)", // 66 + "BIT 4,A", // 67 + "BIT 5,B", // 68 + "BIT 5,C", // 69 + "BIT 5,D", // 6a + "BIT 5,E", // 6b + "BIT 5,H", // 6c + "BIT 5,L", // 6d + "BIT 5,(HL)", // 6e + "BIT 5,A", // 6f + "BIT 6,B", // 70 + "BIT 6,C", // 71 + "BIT 6,D", // 72 + "BIT 6,E", // 73 + "BIT 6,H", // 74 + "BIT 6,L", // 75 + "BIT 6,(HL)", // 76 + "BIT 6,A", // 77 + "BIT 7,B", // 78 + "BIT 7,C", // 79 + "BIT 7,D", // 7a + "BIT 7,E", // 7b + "BIT 7,H", // 7c + "BIT 7,L", // 7d + "BIT 7,(HL)", // 7e + "BIT 7,A", // 7f + "RES 0,B", // 80 + "RES 0,C", // 81 + "RES 0,D", // 82 + "RES 0,E", // 83 + "RES 0,H", // 84 + "RES 0,L", // 85 + "RES 0,(HL)", // 86 + "RES 0,A", // 87 + "RES 1,B", // 88 + "RES 1,C", // 89 + "RES 1,D", // 8a + "RES 1,E", // 8b + "RES 1,H", // 8c + "RES 1,L", // 8d + "RES 1,(HL)", // 8e + "RES 1,A", // 8f + "RES 2,B", // 90 + "RES 2,C", // 91 + "RES 2,D", // 92 + "RES 2,E", // 93 + "RES 2,H", // 94 + "RES 2,L", // 95 + "RES 2,(HL)", // 96 + "RES 2,A", // 97 + "RES 3,B", // 98 + "RES 3,C", // 99 + "RES 3,D", // 9a + "RES 3,E", // 9b + "RES 3,H", // 9c + "RES 3,L", // 9d + "RES 3,(HL)", // 9e + "RES 3,A", // 9f + "RES 4,B", // a0 + "RES 4,C", // a1 + "RES 4,D", // a2 + "RES 4,E", // a3 + "RES 4,H", // a4 + "RES 4,L", // a5 + "RES 4,(HL)", // a6 + "RES 4,A", // a7 + "RES 5,B", // a8 + "RES 5,C", // a9 + "RES 5,D", // aa + "RES 5,E", // ab + "RES 5,H", // ac + "RES 5,L", // ad + "RES 5,(HL)", // ae + "RES 5,A", // af + "RES 6,B", // b0 + "RES 6,C", // b1 + "RES 6,D", // b2 + "RES 6,E", // b3 + "RES 6,H", // b4 + "RES 6,L", // b5 + "RES 6,(HL)", // b6 + "RES 6,A", // b7 + "RES 7,B", // b8 + "RES 7,C", // b9 + "RES 7,D", // ba + "RES 7,E", // bb + "RES 7,H", // bc + "RES 7,L", // bd + "RES 7,(HL)", // be + "RES 7,A", // bf + "SET 0,B", // c0 + "SET 0,C", // c1 + "SET 0,D", // c2 + "SET 0,E", // c3 + "SET 0,H", // c4 + "SET 0,L", // c5 + "SET 0,(HL)", // c6 + "SET 0,A", // c7 + "SET 1,B", // c8 + "SET 1,C", // c9 + "SET 1,D", // ca + "SET 1,E", // cb + "SET 1,H", // cc + "SET 1,L", // cd + "SET 1,(HL)", // ce + "SET 1,A", // cf + "SET 2,B", // d0 + "SET 2,C", // d1 + "SET 2,D", // d2 + "SET 2,E", // d3 + "SET 2,H", // d4 + "SET 2,L", // d5 + "SET 2,(HL)", // d6 + "SET 2,A", // d7 + "SET 3,B", // d8 + "SET 3,C", // d9 + "SET 3,D", // da + "SET 3,E", // db + "SET 3,H", // dc + "SET 3,L", // dd + "SET 3,(HL)", // de + "SET 3,A", // df + "SET 4,B", // e0 + "SET 4,C", // e1 + "SET 4,D", // e2 + "SET 4,E", // e3 + "SET 4,H", // e4 + "SET 4,L", // e5 + "SET 4,(HL)", // e6 + "SET 4,A", // e7 + "SET 5,B", // e8 + "SET 5,C", // e9 + "SET 5,D", // ea + "SET 5,E", // eb + "SET 5,H", // ec + "SET 5,L", // ed + "SET 5,(HL)", // ee + "SET 5,A", // ef + "SET 6,B", // f0 + "SET 6,C", // f1 + "SET 6,D", // f2 + "SET 6,E", // f3 + "SET 6,H", // f4 + "SET 6,L", // f5 + "SET 6,(HL)", // f6 + "SET 6,A", // f7 + "SET 7,B", // f8 + "SET 7,C", // f9 + "SET 7,D", // fa + "SET 7,E", // fb + "SET 7,H", // fc + "SET 7,L", // fd + "SET 7,(HL)", // fe + "SET 7,A", // ff + }; + + #pragma endregion + + #pragma region State Save / Load + + uint8_t* SaveState(uint8_t* saver) + { + *saver = (uint8_t)(NO_prefix ? 1 : 0); saver++; + *saver = (uint8_t)(CB_prefix ? 1 : 0); saver++; + *saver = (uint8_t)(IX_prefix ? 1 : 0); saver++; + *saver = (uint8_t)(EXTD_prefix ? 1 : 0); saver++; + *saver = (uint8_t)(IY_prefix ? 1 : 0); saver++; + *saver = (uint8_t)(IXCB_prefix ? 1 : 0); saver++; + *saver = (uint8_t)(IYCB_prefix ? 1 : 0); saver++; + *saver = (uint8_t)(halted ? 1 : 0); saver++; + *saver = (uint8_t)(I_skip ? 1 : 0); saver++; + *saver = (uint8_t)(FlagI ? 1 : 0); saver++; + *saver = (uint8_t)(FlagW ? 1 : 0); saver++; + *saver = (uint8_t)(IFF1 ? 1 : 0); saver++; + *saver = (uint8_t)(IFF2 ? 1 : 0); saver++; + *saver = (uint8_t)(nonMaskableInterrupt ? 1 : 0); saver++; + *saver = (uint8_t)(nonMaskableInterruptPending ? 1 : 0); saver++; + *saver = (uint8_t)(jp_cond_chk ? 1 : 0); saver++; + *saver = (uint8_t)(cond_chk_fail ? 1 : 0); saver++; + + *saver = opcode; saver++; + *saver = temp_R; saver++; + *saver = EI_pending; saver++; + *saver = interruptMode; saver++; + *saver = ExternalDB; saver++; + *saver = instr_bank; saver++; + + for (int i = 0; i < 36; i++) { *saver = Regs[i]; saver++; } + + *saver = (uint8_t)(PRE_SRC & 0xFF); saver++; *saver = (uint8_t)((PRE_SRC >> 8) & 0xFF); saver++; + *saver = (uint8_t)((PRE_SRC >> 16) & 0xFF); saver++; *saver = (uint8_t)((PRE_SRC >> 24) & 0xFF); 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)(bus_pntr & 0xFF); saver++; *saver = (uint8_t)((bus_pntr >> 8) & 0xFF); saver++; + *saver = (uint8_t)((bus_pntr >> 16) & 0xFF); saver++; *saver = (uint8_t)((bus_pntr >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(mem_pntr & 0xFF); saver++; *saver = (uint8_t)((mem_pntr >> 8) & 0xFF); saver++; + *saver = (uint8_t)((mem_pntr >> 16) & 0xFF); saver++; *saver = (uint8_t)((mem_pntr >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(irq_pntr & 0xFF); saver++; *saver = (uint8_t)((irq_pntr >> 8) & 0xFF); saver++; + *saver = (uint8_t)((irq_pntr >> 16) & 0xFF); saver++; *saver = (uint8_t)((irq_pntr >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(IRQS & 0xFF); saver++; *saver = (uint8_t)((IRQS >> 8) & 0xFF); saver++; + *saver = (uint8_t)((IRQS >> 16) & 0xFF); saver++; *saver = (uint8_t)((IRQS >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(Ztemp2_saver & 0xFF); saver++; *saver = (uint8_t)((Ztemp2_saver >> 8) & 0xFF); saver++; + *saver = (uint8_t)((Ztemp2_saver >> 16) & 0xFF); saver++; *saver = (uint8_t)((Ztemp2_saver >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(IRQS_cond_offset & 0xFF); saver++; *saver = (uint8_t)((IRQS_cond_offset >> 8) & 0xFF); saver++; + *saver = (uint8_t)((IRQS_cond_offset >> 16) & 0xFF); saver++; *saver = (uint8_t)((IRQS_cond_offset >> 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 >> 16) & 0x32); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 40) & 0xFF); saver++; + *saver = (uint8_t)((TotalExecutedCycles >> 16) & 0x48); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 56) & 0xFF); saver++; + + return saver; + } + + uint8_t* LoadState(uint8_t* loader) + { + NO_prefix = *loader == 1; loader++; + CB_prefix = *loader == 1; loader++; + IX_prefix = *loader == 1; loader++; + EXTD_prefix = *loader == 1; loader++; + IY_prefix = *loader == 1; loader++; + IXCB_prefix = *loader == 1; loader++; + IYCB_prefix = *loader == 1; loader++; + halted = *loader == 1; loader++; + I_skip = *loader == 1; loader++; + FlagI = *loader == 1; loader++; + FlagW = *loader == 1; loader++; + IFF1 = *loader == 1; loader++; + IFF2 = *loader == 1; loader++; + nonMaskableInterrupt = *loader == 1; loader++; + nonMaskableInterruptPending = *loader == 1; loader++; + jp_cond_chk = *loader == 1; loader++; + cond_chk_fail = *loader == 1; loader++; + + opcode = *loader; loader++; + temp_R = *loader; loader++; + EI_pending = *loader; loader++; + interruptMode = *loader; loader++; + ExternalDB = *loader; loader++; + instr_bank = *loader; loader++; + + for (int i = 0; i < 36; i++) { Regs[i] = *loader; loader++; } + + PRE_SRC = *loader; loader++; PRE_SRC |= (*loader << 8); loader++; + PRE_SRC |= (*loader << 16); loader++; PRE_SRC |= (*loader << 24); loader++; + + instr_pntr = *loader; loader++; instr_pntr |= (*loader << 8); loader++; + instr_pntr |= (*loader << 16); loader++; instr_pntr |= (*loader << 24); loader++; + + bus_pntr = *loader; loader++; bus_pntr |= (*loader << 8); loader++; + bus_pntr |= (*loader << 16); loader++; bus_pntr |= (*loader << 24); loader++; + + mem_pntr = *loader; loader++; mem_pntr |= (*loader << 8); loader++; + mem_pntr |= (*loader << 16); loader++; mem_pntr |= (*loader << 24); loader++; + + irq_pntr = *loader; loader++; irq_pntr |= (*loader << 8); loader++; + irq_pntr |= (*loader << 16); loader++; irq_pntr |= (*loader << 24); loader++; + + IRQS = *loader; loader++; IRQS |= (*loader << 8); loader++; + IRQS |= (*loader << 16); loader++; IRQS |= (*loader << 24); loader++; + + Ztemp2_saver = *loader; loader++; Ztemp2_saver |= (*loader << 8); loader++; + Ztemp2_saver |= (*loader << 16); loader++; Ztemp2_saver |= (*loader << 24); loader++; + + IRQS_cond_offset = *loader; loader++; IRQS_cond_offset |= (*loader << 8); loader++; + IRQS_cond_offset |= (*loader << 16); loader++; IRQS_cond_offset |= (*loader << 24); loader++; + + // load instruction pointers based on state + if (instr_bank == 0) + { + cur_instr_ofst = &NoIndex[opcode * 38]; + cur_bus_ofst = &NoIndexBUSRQ[opcode * 19]; + cur_mem_ofst = &NoIndexMEMRQ[opcode * 19]; + cur_irqs_ofst = &NoIndexIRQS[opcode]; + } + else if (instr_bank == 1) + { + cur_instr_ofst = &CBIndex[opcode * 38]; + cur_bus_ofst = &CBIndexBUSRQ[opcode * 19]; + cur_mem_ofst = &CBIndexMEMRQ[opcode * 19]; + cur_irqs_ofst = &CBIndexIRQS[opcode]; + } + else if (instr_bank == 2) + { + cur_instr_ofst = &EXTIndex[opcode * 38]; + cur_bus_ofst = &EXTIndexBUSRQ[opcode * 19]; + cur_mem_ofst = &EXTIndexMEMRQ[opcode * 19]; + cur_irqs_ofst = &EXTIndexIRQS[opcode]; + } + else if (instr_bank == 3) + { + cur_instr_ofst = &IXIndex[opcode * 38]; + cur_bus_ofst = &IXIndexBUSRQ[opcode * 19]; + cur_mem_ofst = &IXIndexMEMRQ[opcode * 19]; + cur_irqs_ofst = &IXIndexIRQS[opcode]; + } + else if (instr_bank == 4) + { + cur_instr_ofst = &IYIndex[opcode * 38]; + cur_bus_ofst = &IYIndexBUSRQ[opcode * 19]; + cur_mem_ofst = &IYIndexMEMRQ[opcode * 19]; + cur_irqs_ofst = &IYIndexIRQS[opcode]; + } + else if (instr_bank == 5) + { + cur_instr_ofst = &IXYCBIndex[opcode * 38]; + cur_bus_ofst = &IXYCBIndexBUSRQ[opcode * 19]; + cur_mem_ofst = &IXYCBIndexMEMRQ[opcode * 19]; + cur_irqs_ofst = &IXYCBIndexIRQS[opcode]; + } + else if (instr_bank == 6) + { + cur_instr_ofst = &Reset_CPU[0]; + cur_bus_ofst = &Reset_BUSRQ[0]; + cur_mem_ofst = &Reset_MEMRQ[0]; + cur_irqs_ofst = &Reset_IRQS; + } + else if (instr_bank == 7) + { + cur_instr_ofst = &LD_OP_R_INST[0]; + cur_instr_ofst[14] = Ztemp2_saver; + cur_bus_ofst = &LD_OP_R_BUSRQ[0]; + cur_mem_ofst = &LD_OP_R_MEMRQ[0]; + cur_irqs_ofst = &LD_OP_R_IRQS; + } + else if (instr_bank == 8) + { + cur_instr_ofst = &LD_CP_R_INST[0]; + cur_instr_ofst[14] = Ztemp2_saver; + cur_bus_ofst = &LD_CP_R_BUSRQ[0]; + cur_mem_ofst = &LD_CP_R_MEMRQ[0]; + cur_irqs_ofst = &LD_CP_R_IRQS; + } + else if (instr_bank == 9) + { + cur_instr_ofst = &REP_OP_I_INST[0]; + cur_instr_ofst[8] = Ztemp2_saver; + cur_bus_ofst = &REP_OP_I_BUSRQ[0]; + cur_mem_ofst = &REP_OP_I_MEMRQ[0]; + cur_irqs_ofst = &REP_OP_I_IRQS; + } + else if (instr_bank == 10) + { + cur_instr_ofst = &REP_OP_O_INST[0]; + cur_bus_ofst = &REP_OP_O_BUSRQ[0]; + cur_mem_ofst = &REP_OP_O_MEMRQ[0]; + cur_irqs_ofst = &REP_OP_O_IRQS; + } + else if (instr_bank == 11) + { + cur_instr_ofst = &NO_HALT_INST[0]; + cur_bus_ofst = &NO_HALT_BUSRQ[0]; + cur_mem_ofst = &NO_HALT_MEMRQ[0]; + cur_irqs_ofst = &NO_HALT_IRQS; + } + else if (instr_bank == 12) + { + cur_instr_ofst = &NMI_INST[0]; + cur_bus_ofst = &NMI_BUSRQ[0]; + cur_mem_ofst = &NMI_MEMRQ[0]; + cur_irqs_ofst = &NMI_IRQS; + } + else if (instr_bank == 13) + { + cur_instr_ofst = &IRQ0_INST[0]; + cur_bus_ofst = &IRQ0_BUSRQ[0]; + cur_mem_ofst = &IRQ0_MEMRQ[0]; + cur_irqs_ofst = &IRQ0_IRQS; + } + else if (instr_bank == 14) + { + cur_instr_ofst = &IRQ1_INST[0]; + cur_bus_ofst = &IRQ1_BUSRQ[0]; + cur_mem_ofst = &IRQ1_MEMRQ[0]; + cur_irqs_ofst = &IRQ1_IRQS; + } + else if (instr_bank == 15) + { + cur_instr_ofst = &IRQ2_INST[0]; + cur_bus_ofst = &IRQ2_BUSRQ[0]; + cur_mem_ofst = &IRQ2_MEMRQ[0]; + cur_irqs_ofst = &IRQ2_IRQS; + } + + if (cond_chk_fail) + { + cur_irqs_ofst = &False_IRQS[IRQS_cond_offset]; + } + + 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/Memory.cpp b/libHawk/GBHawk/GBHawk/Memory.cpp new file mode 100644 index 0000000000..bec2e266d1 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Memory.cpp @@ -0,0 +1,229 @@ +#include +#include +#include +#include + +#include "Memory.h" +#include "LR35902.h" +#include "TMS9918A.h" +#include "AY_3_8910.h" + +using namespace std; + +namespace GBHawk +{ + uint8_t MemoryManager::HardwareRead(uint32_t port) + { + port &= 0xFF; + + if (port == 0x98) // VDP + { + return vdp_pntr->ReadData(); + } + else if (port == 0x99) // VDP + { + return vdp_pntr->ReadVdpStatus(); + } + else if (port == 0xA2) + { + if (psg_pntr->port_sel == 0xE) { lagged = false; } + return psg_pntr->ReadReg(); + } + else if (port == 0xA8) + { + return PortA8; + } + else if (port == 0xA9) + { + lagged = false; + return ~kb_rows[kb_rows_sel]; + } + else if (port == 0xAA) + { + // TODO: casette, caps lamp, keyboard sound click + return kb_rows_sel; + } + + return 0xFF; + } + + void MemoryManager::HardwareWrite(uint32_t port, uint8_t value) + { + port &= 0xFF; + + if (port == 0x98) // VDP + { + vdp_pntr->WriteVdpData(value); + } + else if(port == 0x99) // VDP + { + vdp_pntr->WriteVdpControl(value); + } + else if (port == 0xA0) + { + psg_pntr->port_sel = (value & 0xF); + } + else if (port == 0xA1) + { + psg_pntr->WriteReg(value); + + // update controller port data if port F is written to + if (psg_pntr->port_sel == 0xF) + { + if ((psg_pntr->Register[0xF] & 0x40) > 0) + { + psg_pntr->Register[0xE] = controller_byte_2; + } + else + { + psg_pntr->Register[0xE] = controller_byte_1; + } + } + } + else if (port == 0xA8) + { + PortA8 = value; + remap(); + } + else if (port == 0xAA) + { + kb_rows_sel = value & 0xF; + remap(); + } + } + + void MemoryManager::remap() + { + if ((PortA8 & 3) == 0) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i] = &bios_rom[(0x400 * i)]; + cpu_pntr->MemoryMapMask[i] = 0; + } + } + else if ((PortA8 & 3) == 1) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i] = &rom_1[(0x400 * i)]; + cpu_pntr->MemoryMapMask[i] = 0; + } + } + else if ((PortA8 & 3) == 2) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i] = &rom_2[(0x400 * i)]; + cpu_pntr->MemoryMapMask[i] = 0; + } + } + else if ((PortA8 & 3) == 3) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i] = &ram[(0x400 * i)]; + cpu_pntr->MemoryMapMask[i] = 0xFF; + } + } + + if (((PortA8 >> 2) & 3) == 0) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i + 16] = &basic_rom[(0x400 * i)]; + cpu_pntr->MemoryMapMask[i + 16] = 0; + } + } + else if (((PortA8 >> 2) & 3) == 1) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i + 16] = &rom_1[0x4000 + (0x400 * i)]; + cpu_pntr->MemoryMapMask[i + 16] = 0; + } + } + else if (((PortA8 >> 2) & 3) == 2) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i + 16] = &rom_2[0x4000 + (0x400 * i)]; + cpu_pntr->MemoryMapMask[i + 16] = 0; + } + } + else if (((PortA8 >> 2) & 3) == 3) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i + 16] = &ram[0x4000 + (0x400 * i)]; + cpu_pntr->MemoryMapMask[i + 16] = 0xFF; + } + } + + if (((PortA8 >> 4) & 3) == 0) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i + 32] = &unmapped[0]; + cpu_pntr->MemoryMapMask[i + 32] = 0; + } + } + else if (((PortA8 >> 4) & 3) == 1) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i + 32] = &rom_1[0x8000 + (0x400 * i)]; + cpu_pntr->MemoryMapMask[i + 32] = 0; + } + } + else if (((PortA8 >> 4) & 3) == 2) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i + 32] = &rom_2[0x8000 + (0x400 * i)]; + cpu_pntr->MemoryMapMask[i + 32] = 0; + } + } + else if (((PortA8 >> 4) & 3) == 3) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i + 32] = &ram[0x8000 + (0x400 * i)]; + cpu_pntr->MemoryMapMask[i + 32] = 0xFF; + } + } + + if (((PortA8 >> 6) & 3) == 0) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i + 48] = &unmapped[0]; + cpu_pntr->MemoryMapMask[i + 48] = 0; + } + } + else if (((PortA8 >> 6) & 3) == 1) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i + 48] = &rom_1[0xC000 + (0x400 * i)]; + cpu_pntr->MemoryMapMask[i + 48] = 0; + } + } + else if (((PortA8 >> 6) & 3) == 2) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i + 48] = &rom_2[0xC000 + (0x400 * i)]; + cpu_pntr->MemoryMapMask[i + 48] = 0; + } + } + else if (((PortA8 >> 6) & 3) == 3) + { + for (uint32_t i = 0; i < 16; i++) + { + cpu_pntr->MemoryMap[i + 48] = &ram[0xC000 + (0x400 * i)]; + cpu_pntr->MemoryMapMask[i + 48] = 0xFF; + } + } + } +} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/Memory.h b/libHawk/GBHawk/GBHawk/Memory.h new file mode 100644 index 0000000000..23021c9938 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Memory.h @@ -0,0 +1,138 @@ +#include +#include +#include +#include + +using namespace std; + +namespace GBHawk +{ + class Z80A; + class TMS9918A; + class AY_3_8910; + + class MemoryManager + { + public: + + TMS9918A* vdp_pntr = nullptr; + AY_3_8910* psg_pntr = nullptr; + Z80A* cpu_pntr = nullptr; + uint8_t* rom_1 = nullptr; + uint8_t* rom_2 = nullptr; + uint8_t* bios_rom = nullptr; + uint8_t* basic_rom = nullptr; + + // initialized by core loading, not savestated + uint32_t rom_size_1; + uint32_t rom_mapper_1; + uint32_t rom_size_2; + uint32_t rom_mapper_2; + + // controls are not stated + uint8_t controller_byte_1, controller_byte_2; + uint8_t* kb_rows; + + // State + bool PortDEEnabled = false; + bool lagged; + bool start_pressed; + + uint8_t kb_rows_sel; + uint8_t PortA8 = 0x00; + uint8_t reg_FFFC, reg_FFFD, reg_FFFE, reg_FFFF; + uint8_t ram[0x10000] = {}; + uint8_t cart_ram[0x8000] = {}; + uint8_t unmapped[0x400] = {}; + + MemoryManager() + { + + }; + + uint8_t HardwareRead(uint32_t value); + + void HardwareWrite(uint32_t addr, uint8_t value); + + void remap(); + + // NOTE: only called from source when both are available and of correct size (0x4000) + void Load_BIOS(uint8_t* bios, uint8_t* basic) + { + bios_rom = new uint8_t[0x4000]; + basic_rom = new uint8_t[0x4000]; + + memcpy(bios_rom, bios, 0x4000); + memcpy(basic_rom, basic, 0x4000); + } + + void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1, uint32_t ext_rom_mapper_1, uint8_t* ext_rom_2, uint32_t ext_rom_size_2, uint32_t ext_rom_mapper_2) + { + rom_1 = new uint8_t[ext_rom_size_1]; + rom_2 = new uint8_t[ext_rom_size_2]; + + memcpy(rom_1, ext_rom_1, ext_rom_size_1); + memcpy(rom_2, ext_rom_2, ext_rom_size_2); + + rom_size_1 = ext_rom_size_1 / 0x4000; + rom_mapper_1 = ext_rom_mapper_1; + + rom_size_2 = ext_rom_size_2 / 0x4000; + rom_mapper_2 = ext_rom_mapper_2; + + // default memory map setup + PortA8 = 0; + + remap(); + } + + void MemoryWrite(uint32_t addr, uint8_t value) + { + + } + + #pragma region State Save / Load + + uint8_t* SaveState(uint8_t* saver) + { + *saver = (uint8_t)(PortDEEnabled ? 1 : 0); saver++; + *saver = (uint8_t)(lagged ? 1 : 0); saver++; + *saver = (uint8_t)(start_pressed ? 1 : 0); saver++; + + *saver = kb_rows_sel; saver++; + *saver = PortA8; saver++; + *saver = reg_FFFC; saver++; + *saver = reg_FFFD; saver++; + *saver = reg_FFFE; saver++; + *saver = reg_FFFF; saver++; + + std::memcpy(saver, &ram, 0x10000); saver += 0x10000; + std::memcpy(saver, &cart_ram, 0x8000); saver += 0x8000; + + return saver; + } + + uint8_t* LoadState(uint8_t* loader) + { + PortDEEnabled = *loader == 1; loader++; + lagged = *loader == 1; loader++; + start_pressed = *loader == 1; loader++; + + kb_rows_sel = *loader; loader++; + PortA8 = *loader; loader++; + reg_FFFC = *loader; loader++; + reg_FFFD = *loader; loader++; + reg_FFFE = *loader; loader++; + reg_FFFF = *loader; loader++; + + std::memcpy(&ram, loader, 0x10000); loader += 0x10000; + std::memcpy(&cart_ram, loader, 0x8000); loader += 0x8000; + + remap(); + + return loader; + } + + #pragma endregion + }; +} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/TMS9918A.h b/libHawk/GBHawk/GBHawk/TMS9918A.h new file mode 100644 index 0000000000..c62bed5e25 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/TMS9918A.h @@ -0,0 +1,610 @@ +#include +#include +#include +#include + +using namespace std; + +namespace GBHawk +{ + class TMS9918A + { + public: + #pragma region VDP + + TMS9918A() + { + + } + + bool* IRQ_PTR = nullptr; + + // external flags to display background or sprites + bool SHOW_BG, SHOW_SPRITES; + bool SpriteLimit; + + // VDP State + bool VdpWaitingForLatchInt = true; + bool VdpWaitingForLatchByte = true; + bool VIntPending; + bool HIntPending; + + uint8_t StatusByte; + uint8_t VdpLatch; + uint8_t VdpBuffer; + uint8_t TmsMode; + uint8_t Registers[8] = {}; + uint8_t VRAM[0x4000]; //16kb video RAM + + int32_t ScanLine; + uint32_t VdpAddress; + uint32_t ColorTableBase; + uint32_t PatternGeneratorBase; + uint32_t SpritePatternGeneratorBase; + uint32_t TmsPatternNameTableBase; + uint32_t TmsSpriteAttributeBase; + + uint32_t FrameBuffer[192 * 256] = {}; + uint8_t ScanlinePriorityBuffer[256] = {}; + uint8_t SpriteCollisionBuffer[256] = {}; + + // constants after load, not stated + uint32_t BackgroundColor = 0; + uint32_t IPeriod = 228; + + // temporary variables not stated if on frame boundary + bool is_top; + uint32_t yc; + uint32_t yofs; + uint32_t FrameBufferOffset; + uint32_t PatternNameOffset; + uint32_t ScreenBGColor; + uint32_t yrow; + uint32_t PatternGeneratorOffset; + uint32_t ColorOffset; + uint32_t pn; + uint32_t pv; + uint32_t colorEntry; + uint32_t fgIndex; + uint32_t bgIndex; + uint32_t fgColor; + uint32_t bgColor; + uint32_t lColorIndex; + uint32_t rColorIndex; + uint32_t lColor; + uint32_t rColor; + + uint32_t PaletteTMS9918[16] = + { + 0xFF000000, + 0xFF000000, + 0xFF47B73B, + 0xFF7CCF6F, + 0xFF5D4EFF, + 0xFF8072FF, + 0xFFB66247, + 0xFF5DC8ED, + 0xFFD76B48, + 0xFFFB8F6C, + 0xFFC3CD41, + 0xFFD3DA76, + 0xFF3E9F2F, + 0xFFB664C7, + 0xFFCCCCCC, + 0xFFFFFFFF + }; + + bool Mode1Bit() { return (Registers[1] & 16) > 0; } + bool Mode2Bit() { return (Registers[0] & 2) > 0; } + bool Mode3Bit() { return (Registers[1] & 8) > 0; } + bool EnableDoubledSprites() { return (Registers[1] & 1) > 0; } + bool EnableLargeSprites() { return (Registers[1] & 2) > 0; } + bool EnableInterrupts() { return (Registers[1] & 32) > 0; } + bool DisplayOn() { return (Registers[1] & 64) > 0; } + bool Mode16k() { return (Registers[1] & 128) > 0; } + + bool InterruptPendingGet() { return (StatusByte & 0x80) != 0; } + void InterruptPendingSet(bool value) { StatusByte = (uint8_t)((StatusByte & ~0x02) | (value ? 0x80 : 0x00)); } + + void WriteVdpControl(uint8_t value) + { + if (VdpWaitingForLatchByte) + { + VdpLatch = value; + VdpWaitingForLatchByte = false; + VdpAddress = (uint32_t)((VdpAddress & 0x3F00) | value); + return; + } + + VdpWaitingForLatchByte = true; + VdpAddress = (uint32_t)(((value & 63) << 8) | VdpLatch); + VdpAddress &= 0x3FFF; + switch (value & 0xC0) + { + case 0x00: // read VRAM + VdpBuffer = VRAM[VdpAddress]; + VdpAddress++; + VdpAddress &= 0x3FFF; + break; + case 0x40: // write VRAM + break; + case 0x80: // VDP register write + WriteRegister(value & 0x0F, VdpLatch); + break; + } + } + + void WriteVdpData(uint8_t value) + { + VdpWaitingForLatchByte = true; + VdpBuffer = value; + + VRAM[VdpAddress] = value; + //if (!Mode16k) + // Console.WriteLine("VRAM written while not in 16k addressing mode!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + VdpAddress++; + VdpAddress &= 0x3FFF; + } + + void WriteRegister(uint32_t reg, uint8_t data) + { + if (reg >= 8) return; + + Registers[reg] = data; + switch (reg) + { + case 0: // Mode Control Register 1 + CheckVideoMode(); + break; + case 1: // Mode Control Register 2 + CheckVideoMode(); + IRQ_PTR[0] = (EnableInterrupts() && InterruptPendingGet()); + break; + case 2: // Name Table Base Address + TmsPatternNameTableBase = (Registers[2] << 10) & 0x3C00; + break; + case 3: // Color Table Base Address + ColorTableBase = (Registers[3] << 6) & 0x3FC0; + break; + case 4: // Pattern Generator Base Address + PatternGeneratorBase = (Registers[4] << 11) & 0x3800; + break; + case 5: // Sprite Attribute Table Base Address + TmsSpriteAttributeBase = (Registers[5] << 7) & 0x3F80; + break; + case 6: // Sprite Pattern Generator Base Adderss + SpritePatternGeneratorBase = (Registers[6] << 11) & 0x3800; + break; + } + } + + uint8_t ReadVdpStatus() + { + VdpWaitingForLatchByte = true; + uint8_t returnValue = StatusByte; + StatusByte &= 0x1F; + IRQ_PTR[0] = false; + + return returnValue; + } + + uint8_t ReadData() + { + VdpWaitingForLatchByte = true; + uint8_t value = VdpBuffer; + VdpBuffer = VRAM[VdpAddress]; + VdpAddress++; + VdpAddress &= 0x3FFF; + return value; + } + + void CheckVideoMode() + { + if (Mode1Bit()) TmsMode = 1; + else if (Mode2Bit()) TmsMode = 2; + else if (Mode3Bit()) TmsMode = 3; + else TmsMode = 0; + } + + void RenderScanline(int32_t scanLine) + { + if (scanLine >= 192) + return; + + if (TmsMode == 2) + { + RenderBackgroundM2(scanLine); + RenderTmsSprites(scanLine); + } + else if (TmsMode == 0) + { + RenderBackgroundM0(scanLine); + RenderTmsSprites(scanLine); + } + else if (TmsMode == 3) + { + RenderBackgroundM3(scanLine); + RenderTmsSprites(scanLine); + } + else if (TmsMode == 1) + { + RenderBackgroundM1(scanLine); + // no sprites (text mode) + } + } + + void RenderBackgroundM0(uint32_t scanLine) + { + if (DisplayOn() == false) + { + for (int i = 0; i < 256; i++) { FrameBuffer[scanLine * 256 + i] = 0; }; + return; + } + + yc = scanLine / 8; + yofs = scanLine % 8; + FrameBufferOffset = scanLine * 256; + PatternNameOffset = TmsPatternNameTableBase + (yc * 32); + ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; + + for (uint32_t xc = 0; xc < 32; xc++) + { + pn = VRAM[PatternNameOffset++]; + pv = VRAM[PatternGeneratorBase + (pn * 8) + yofs]; + colorEntry = VRAM[ColorTableBase + (pn / 8)]; + fgIndex = (colorEntry >> 4) & 0x0F; + bgIndex = colorEntry & 0x0F; + fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex]; + bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex]; + + FrameBuffer[FrameBufferOffset++] = ((pv & 0x80) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x40) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x20) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x10) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x08) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x04) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x02) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x01) > 0) ? fgColor : bgColor; + } + } + + void RenderBackgroundM1(uint32_t scanLine) + { + if (DisplayOn() == false) + { + for (int i = 0; i < 256; i++) { FrameBuffer[scanLine * 256 + i] = 0; }; + return; + } + + yc = scanLine / 8; + yofs = scanLine % 8; + FrameBufferOffset = scanLine * 256; + PatternNameOffset = TmsPatternNameTableBase + (yc * 40); + ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; + + for (uint32_t xc = 0; xc < 40; xc++) + { + pn = VRAM[PatternNameOffset++]; + pv = VRAM[PatternGeneratorBase + (pn * 8) + yofs]; + colorEntry = Registers[7]; + fgIndex = (colorEntry >> 4) & 0x0F; + bgIndex = colorEntry & 0x0F; + fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex]; + bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex]; + + FrameBuffer[FrameBufferOffset++] = ((pv & 0x80) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x40) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x20) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x10) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x08) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x04) > 0) ? fgColor : bgColor; + } + } + + void RenderBackgroundM2(uint32_t scanLine) + { + if (DisplayOn() == false) + { + for (int i = 0; i < 256; i++) { FrameBuffer[scanLine * 256 + i] = 0; }; + return; + } + + yrow = scanLine / 8; + yofs = scanLine % 8; + FrameBufferOffset = scanLine * 256; + PatternNameOffset = TmsPatternNameTableBase + (yrow * 32); + PatternGeneratorOffset = (((Registers[4] & 4) << 11) & 0x2000); + ColorOffset = (ColorTableBase & 0x2000); + ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; + + for (uint32_t xc = 0; xc < 32; xc++) + { + pn = VRAM[PatternNameOffset++] + ((yrow / 8) * 0x100); + pv = VRAM[PatternGeneratorOffset + (pn * 8) + yofs]; + colorEntry = VRAM[ColorOffset + (pn * 8) + yofs]; + fgIndex = (colorEntry >> 4) & 0x0F; + bgIndex = colorEntry & 0x0F; + fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex]; + bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex]; + + FrameBuffer[FrameBufferOffset++] = ((pv & 0x80) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x40) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x20) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x10) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x08) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x04) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x02) > 0) ? fgColor : bgColor; + FrameBuffer[FrameBufferOffset++] = ((pv & 0x01) > 0) ? fgColor : bgColor; + } + } + + void RenderBackgroundM3(uint32_t scanLine) + { + if (DisplayOn() == false) + { + for (int i = 0; i < 256; i++) { FrameBuffer[scanLine * 256 + i] = 0; }; + return; + } + + yc = scanLine / 8; + is_top = (scanLine & 4) == 0; // am I in the top 4 pixels of an 8-pixel character? + FrameBufferOffset = scanLine * 256; + PatternNameOffset = TmsPatternNameTableBase + (yc * 32); + ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; + + for (uint32_t xc = 0; xc < 32; xc++) + { + pn = VRAM[PatternNameOffset++]; + pv = VRAM[PatternGeneratorBase + (pn * 8) + ((yc & 3) * 2) + (is_top ? 0 : 1)]; + + lColorIndex = pv & 0xF; + rColorIndex = pv >> 4; + lColor = lColorIndex == 0 ? ScreenBGColor : PaletteTMS9918[lColorIndex]; + rColor = rColorIndex == 0 ? ScreenBGColor : PaletteTMS9918[rColorIndex]; + + FrameBuffer[FrameBufferOffset++] = lColor; + FrameBuffer[FrameBufferOffset++] = lColor; + FrameBuffer[FrameBufferOffset++] = lColor; + FrameBuffer[FrameBufferOffset++] = lColor; + FrameBuffer[FrameBufferOffset++] = rColor; + FrameBuffer[FrameBufferOffset++] = rColor; + FrameBuffer[FrameBufferOffset++] = rColor; + FrameBuffer[FrameBufferOffset] = rColor; + } + } + + inline void RenderTmsSprites(int32_t scanLine) + { + if (EnableDoubledSprites() == false) + { + RenderTmsSpritesStandard(scanLine); + } + else + { + RenderTmsSpritesDouble(scanLine); + } + } + + void RenderTmsSpritesStandard(int32_t scanLine) + { + if (DisplayOn() == false) return; + + for (uint32_t i = 0; i < 256; i++) + { + ScanlinePriorityBuffer[i] = 0; + SpriteCollisionBuffer[i] = 0; + }; + + bool LargeSprites = EnableLargeSprites(); + + int32_t SpriteSize = 8; + if (LargeSprites) SpriteSize *= 2; + const int32_t OneCellSize = 8; + + int32_t NumSpritesOnScanline = 0; + for (int32_t i = 0; i < 32; i++) + { + int32_t SpriteBase = TmsSpriteAttributeBase + (i * 4); + int32_t y = VRAM[SpriteBase++]; + int32_t x = VRAM[SpriteBase++]; + int32_t Pattern = VRAM[SpriteBase++]; + int32_t Color = VRAM[SpriteBase]; + + if (y == 208) break; // terminator sprite + if (y > 224) y -= 256; // sprite Y wrap + y++; // inexplicably, sprites start on Y+1 + if (y > scanLine || y + SpriteSize <= scanLine) continue; // sprite is not on this scanline + if ((Color & 0x80) > 0) x -= 32; // Early Clock adjustment + + if (++NumSpritesOnScanline == 5) + { + StatusByte &= 0xE0; // Clear FS0-FS4 bits + StatusByte |= (uint8_t)i; // set 5th sprite index + StatusByte |= 0x40; // set overflow bit + break; + } + + if (LargeSprites) Pattern &= 0xFC; // 16x16 sprites forced to 4-uint8_t alignment + int32_t SpriteLine = scanLine - y; + + // pv contains the VRAM uint8_t holding the pattern data for this character at this scanline. + // each uint8_t contains the pattern data for each the 8 pixels on this line. + // the bit-shift further down on PV pulls out the relevant horizontal pixel. + + int8_t pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine]; + + for (int32_t xp = 0; xp < SpriteSize && x + xp < 256; xp++) + { + if (x + xp < 0) continue; + if (LargeSprites && xp == OneCellSize) + pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine + 16]; + + if (Color != 0 && (pv & (1 << (7 - (xp & 7)))) > 0) + { + if (SpriteCollisionBuffer[x + xp] != 0) + StatusByte |= 0x20; // Set sprite collision flag + + if (ScanlinePriorityBuffer[x + xp] == 0) + { + ScanlinePriorityBuffer[x + xp] = 1; + SpriteCollisionBuffer[x + xp] = 1; + FrameBuffer[(scanLine * 256) + x + xp] = PaletteTMS9918[Color & 0x0F]; + } + } + } + } + } + + void RenderTmsSpritesDouble(int32_t scanLine) + { + if (DisplayOn() == false) return; + + for (uint32_t i = 0; i < 256; i++) + { + ScanlinePriorityBuffer[i] = 0; + SpriteCollisionBuffer[i] = 0; + }; + + bool LargeSprites = EnableLargeSprites(); + + int32_t SpriteSize = 8; + if (LargeSprites) SpriteSize *= 2; + SpriteSize *= 2; // because sprite magnification + const int32_t OneCellSize = 16; // once 8-pixel cell, doubled, will take 16 pixels + + int32_t NumSpritesOnScanline = 0; + for (int32_t i = 0; i < 32; i++) + { + int32_t SpriteBase = TmsSpriteAttributeBase + (i * 4); + int32_t y = VRAM[SpriteBase++]; + int32_t x = VRAM[SpriteBase++]; + int32_t Pattern = VRAM[SpriteBase++]; + int32_t Color = VRAM[SpriteBase]; + + if (y == 208) break; // terminator sprite + if (y > 224) y -= 256; // sprite Y wrap + y++; // inexplicably, sprites start on Y+1 + if (y > scanLine || y + SpriteSize <= scanLine) continue; // sprite is not on this scanline + if ((Color & 0x80) > 0) x -= 32; // Early Clock adjustment + + if (++NumSpritesOnScanline == 5) + { + StatusByte &= 0xE0; // Clear FS0-FS4 bits + StatusByte |= (uint8_t)i; // set 5th sprite index + StatusByte |= 0x40; // set overflow bit + break; + } + + if (LargeSprites) Pattern &= 0xFC; // 16x16 sprites forced to 4-byte alignment + int32_t SpriteLine = scanLine - y; + SpriteLine /= 2; // because of sprite magnification + + int8_t pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine]; + + for (int32_t xp = 0; xp < SpriteSize && x + xp < 256; xp++) + { + if (x + xp < 0) continue; + if (LargeSprites && xp == OneCellSize) + pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine + 16]; + + if (Color != 0 && (pv & (1 << (7 - ((xp / 2) & 7)))) > 0) // xp/2 is due to sprite magnification + { + if (SpriteCollisionBuffer[x + xp] != 0) + StatusByte |= 0x20; // Set sprite collision flag + + if (ScanlinePriorityBuffer[x + xp] == 0) + { + ScanlinePriorityBuffer[x + xp] = 1; + SpriteCollisionBuffer[x + xp] = 1; + FrameBuffer[(scanLine * 256) + x + xp] = PaletteTMS9918[Color & 0x0F]; + } + } + } + } + } + + #pragma endregion + + #pragma region State Save / Load + + uint8_t* SaveState(uint8_t* saver) + { + *saver = (uint8_t)(VdpWaitingForLatchInt ? 1 : 0); saver++; + *saver = (uint8_t)(VdpWaitingForLatchByte ? 1 : 0); saver++; + *saver = (uint8_t)(VIntPending ? 1 : 0); saver++; + *saver = (uint8_t)(HIntPending ? 1 : 0); saver++; + + *saver = StatusByte; saver++; + *saver = VdpLatch; saver++; + *saver = VdpBuffer; saver++; + *saver = TmsMode; saver++; + + std::memcpy(saver, &Registers, 8); saver += 8; + std::memcpy(saver, &VRAM, 0x4000); saver += 0x4000; + + *saver = (uint8_t)(ScanLine & 0xFF); saver++; *saver = (uint8_t)((ScanLine >> 8) & 0xFF); saver++; + *saver = (uint8_t)((ScanLine >> 16) & 0xFF); saver++; *saver = (uint8_t)((ScanLine >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(VdpAddress & 0xFF); saver++; *saver = (uint8_t)((VdpAddress >> 8) & 0xFF); saver++; + *saver = (uint8_t)((VdpAddress >> 16) & 0xFF); saver++; *saver = (uint8_t)((VdpAddress >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(ColorTableBase & 0xFF); saver++; *saver = (uint8_t)((ColorTableBase >> 8) & 0xFF); saver++; + *saver = (uint8_t)((ColorTableBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((ColorTableBase >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(PatternGeneratorBase & 0xFF); saver++; *saver = (uint8_t)((PatternGeneratorBase >> 8) & 0xFF); saver++; + *saver = (uint8_t)((PatternGeneratorBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((PatternGeneratorBase >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(SpritePatternGeneratorBase & 0xFF); saver++; *saver = (uint8_t)((SpritePatternGeneratorBase >> 8) & 0xFF); saver++; + *saver = (uint8_t)((SpritePatternGeneratorBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((SpritePatternGeneratorBase >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(TmsPatternNameTableBase & 0xFF); saver++; *saver = (uint8_t)((TmsPatternNameTableBase >> 8) & 0xFF); saver++; + *saver = (uint8_t)((TmsPatternNameTableBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((TmsPatternNameTableBase >> 24) & 0xFF); saver++; + + *saver = (uint8_t)(TmsSpriteAttributeBase & 0xFF); saver++; *saver = (uint8_t)((TmsSpriteAttributeBase >> 8) & 0xFF); saver++; + *saver = (uint8_t)((TmsSpriteAttributeBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((TmsSpriteAttributeBase >> 24) & 0xFF); saver++; + + return saver; + } + + uint8_t* LoadState(uint8_t* loader) + { + VdpWaitingForLatchInt = *loader == 1; loader++; + VdpWaitingForLatchByte = *loader == 1; loader++; + VIntPending = *loader == 1; loader++; + HIntPending = *loader == 1; loader++; + + StatusByte = *loader; loader++; + VdpLatch = *loader; loader++; + VdpBuffer = *loader; loader++; + TmsMode = *loader; loader++; + + std::memcpy(&Registers, loader, 8); loader += 8; + std::memcpy(&VRAM, loader, 0x4000); loader += 0x4000; + + ScanLine = *loader; loader++; ScanLine |= (*loader << 8); loader++; + ScanLine |= (*loader << 16); loader++; ScanLine |= (*loader << 24); loader++; + + VdpAddress = *loader; loader++; VdpAddress |= (*loader << 8); loader++; + VdpAddress |= (*loader << 16); loader++; VdpAddress |= (*loader << 24); loader++; + + ColorTableBase = *loader; loader++; ColorTableBase |= (*loader << 8); loader++; + ColorTableBase |= (*loader << 16); loader++; ColorTableBase |= (*loader << 24); loader++; + + PatternGeneratorBase = *loader; loader++; PatternGeneratorBase |= (*loader << 8); loader++; + PatternGeneratorBase |= (*loader << 16); loader++; PatternGeneratorBase |= (*loader << 24); loader++; + + SpritePatternGeneratorBase = *loader; loader++; SpritePatternGeneratorBase |= (*loader << 8); loader++; + SpritePatternGeneratorBase |= (*loader << 16); loader++; SpritePatternGeneratorBase |= (*loader << 24); loader++; + + TmsPatternNameTableBase = *loader; loader++; TmsPatternNameTableBase |= (*loader << 8); loader++; + TmsPatternNameTableBase |= (*loader << 16); loader++; TmsPatternNameTableBase |= (*loader << 24); loader++; + + TmsSpriteAttributeBase = *loader; loader++; TmsSpriteAttributeBase |= (*loader << 8); loader++; + TmsSpriteAttributeBase |= (*loader << 16); loader++; TmsSpriteAttributeBase |= (*loader << 24); loader++; + + return loader; + } + + #pragma endregion + }; +} diff --git a/libHawk/GBHawk/GBHawk/cpp.hint b/libHawk/GBHawk/GBHawk/cpp.hint new file mode 100644 index 0000000000..43a4f3526e --- /dev/null +++ b/libHawk/GBHawk/GBHawk/cpp.hint @@ -0,0 +1,2 @@ +#define GBHawk_API __declspec(dllexport) +#define GBHawk_API __declspec(dllimport) From 373a05dcb4038aa4ea3a558c8d2825c7025294f4 Mon Sep 17 00:00:00 2001 From: campbell000 Date: Tue, 24 Mar 2020 13:40:18 -0400 Subject: [PATCH 14/15] Fixes joypad.set() method in Lua Console (#1898) * Fixed lua joypad set method to accept button inputs with "P{controller}" designations. Also allowed joypad set method to accept 0 or 1 as per documentation * Added comment --- .../Api/Classes/JoypadApi.cs | 4 +- .../lua/EmuLuaLibrary.Joypad.cs | 2 +- BizHawk.Emulation.Common/Extensions.cs | 41 +++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.Common/Api/Classes/JoypadApi.cs b/BizHawk.Client.Common/Api/Classes/JoypadApi.cs index 79dce1ff00..0671cd82c2 100644 --- a/BizHawk.Client.Common/Api/Classes/JoypadApi.cs +++ b/BizHawk.Client.Common/Api/Classes/JoypadApi.cs @@ -44,7 +44,9 @@ namespace BizHawk.Client.Common public void Set(Dictionary buttons, int? controller = null) { - foreach (var button in Global.InputManager.ActiveController.Definition.BoolButtons) + // If a controller is specified, we need to iterate over unique button names. If not, we iterate over + // ALL button names with P{controller} prefixes + foreach (var button in Global.InputManager.ActiveController.ToBoolButtonNameList(controller)) { Set(button, buttons.TryGetValue(button, out var state) ? state : (bool?) null, controller); } diff --git a/BizHawk.Client.Common/lua/EmuLuaLibrary.Joypad.cs b/BizHawk.Client.Common/lua/EmuLuaLibrary.Joypad.cs index c94b150020..12990100f4 100644 --- a/BizHawk.Client.Common/lua/EmuLuaLibrary.Joypad.cs +++ b/BizHawk.Client.Common/lua/EmuLuaLibrary.Joypad.cs @@ -45,7 +45,7 @@ namespace BizHawk.Client.Common public void Set(LuaTable buttons, int? controller = null) { var dict = new Dictionary(); - foreach (var k in buttons.Keys) dict[k.ToString()] = (bool) buttons[k]; + foreach (var k in buttons.Keys) dict[k.ToString()] = Convert.ToBoolean(buttons[k]); // Accepts 1/0 or true/false APIs.Joypad.Set(dict, controller); } diff --git a/BizHawk.Emulation.Common/Extensions.cs b/BizHawk.Emulation.Common/Extensions.cs index dcf2998b2c..3f70690cee 100644 --- a/BizHawk.Emulation.Common/Extensions.cs +++ b/BizHawk.Emulation.Common/Extensions.cs @@ -314,6 +314,47 @@ namespace BizHawk.Emulation.Common return !info.GetCustomAttributes(false).Any(a => a is FeatureNotImplementedAttribute); } + /// + /// Gets a list of boolean button names. If a controller number is specified, only returns button names + /// (without the "P" prefix) that match that controller number. If a controller number is NOT specified, + /// then all button names are returned. + /// + /// For example, consider example "P1 A", "P1 B", "P2 A", "P2 B". See below for sample outputs: + /// - ToBoolButtonNameList(controller, 1) -> [A, B] + /// - ToBoolButtonNameList(controller, 2) -> [A, B] + /// - ToBoolButtonNameList(controller, null) -> [P1 A, P1 B, P2 A, P2 B] + /// + public static List ToBoolButtonNameList(this IController controller, int? controllerNum = null) + { + return ToControlNameList(controller.Definition.BoolButtons, controllerNum); + } + + /// + /// See ToBoolButtonNameList(). Works the same except with float controls + /// + public static List ToFloatControlNameList(this IController controller, int? controllerNum = null) + { + return ToControlNameList(controller.Definition.FloatControls, controllerNum); + } + + private static List ToControlNameList(List buttonList, int? controllerNum = null) + { + var buttons = new List(); + foreach (var button in buttonList) + { + if (controllerNum != null && button.Length > 2 && button.Substring(0, 2) == $"P{controllerNum}") + { + var sub = button.Substring(3); + buttons.Add(sub); + } + else if (controllerNum == null) + { + buttons.Add(button); + } + } + return buttons; + } + public static IDictionary ToDictionary(this IController controller, int? controllerNum = null) { var buttons = new Dictionary(); From 79fecef41b91ef5c866d6af035c0e0dc624d7e94 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 24 Mar 2020 19:44:11 -0400 Subject: [PATCH 15/15] GBHawk: more transformation work --- libHawk/GBHawk/GBHawk/AY_3_8910.h | 442 -------- libHawk/GBHawk/GBHawk/Core.h | 124 +-- libHawk/GBHawk/GBHawk/GBAudio.h | 1396 ++++++++++++++++++++++++++ libHawk/GBHawk/GBHawk/GBHawk.cpp | 4 +- libHawk/GBHawk/GBHawk/GBHawk.vcxproj | 2 +- libHawk/GBHawk/GBHawk/LR35902.cpp | 10 +- libHawk/GBHawk/GBHawk/LR35902.h | 745 +++----------- libHawk/GBHawk/GBHawk/Memory.cpp | 206 +--- libHawk/GBHawk/GBHawk/Memory.h | 14 +- 9 files changed, 1564 insertions(+), 1379 deletions(-) delete mode 100644 libHawk/GBHawk/GBHawk/AY_3_8910.h create mode 100644 libHawk/GBHawk/GBHawk/GBAudio.h diff --git a/libHawk/GBHawk/GBHawk/AY_3_8910.h b/libHawk/GBHawk/GBHawk/AY_3_8910.h deleted file mode 100644 index 4892c2af17..0000000000 --- a/libHawk/GBHawk/GBHawk/AY_3_8910.h +++ /dev/null @@ -1,442 +0,0 @@ -#include -#include -#include -#include - -using namespace std; - -namespace GBHawk -{ - class AY_3_8910 - { - public: - - #pragma region AY_3_8910 - - AY_3_8910() - { - Reset(); - } - - bool A_on, B_on, C_on; - bool A_up, B_up, C_up; - bool A_noise, B_noise, C_noise; - bool env_vol_A, env_vol_B, env_vol_C; - - uint8_t env_shape; - uint8_t port_sel; - uint8_t vol_A, vol_B, vol_C; - uint8_t Register[16] = {}; - - uint32_t psg_clock; - uint32_t sq_per_A, sq_per_B, sq_per_C; - uint32_t clock_A, clock_B, clock_C; - - uint32_t env_per; - uint32_t env_clock; - - int32_t env_E; - int32_t E_up_down; - - uint32_t noise_clock; - uint32_t noise_per; - uint32_t noise = 0x1; - - int32_t old_sample; - - // non stated if only on frame boundaries - bool sound_out_A; - bool sound_out_B; - bool sound_out_C; - - uint8_t Clock_Divider; - - int32_t current_sample; - uint32_t sampleclock; - uint32_t num_samples; - int32_t samples[9000] = {}; - - void Reset() - { - clock_A = clock_B = clock_C = 0x1000; - noise_clock = 0x20; - port_sel = 0; - - for (int i = 0; i < 16; i++) - { - Register[i] = 0x0; - } - sync_psg_state(); - } - - short Sample() - { - return current_sample; - } - - const uint32_t VolumeTable[16] = - { - 0x0000, 0x0055, 0x0079, 0x00AB, 0x00F1, 0x0155, 0x01E3, 0x02AA, - 0x03C5, 0x0555, 0x078B, 0x0AAB, 0x0F16, 0x1555, 0x1E2B, 0x2AAA - }; - - uint8_t ReadReg() - { - return Register[port_sel]; - } - - void sync_psg_state() - { - sq_per_A = (Register[0] & 0xFF) | (((Register[1] & 0xF) << 8)); - if (sq_per_A == 0) - { - sq_per_A = 0x1000; - } - - sq_per_B = (Register[2] & 0xFF) | (((Register[3] & 0xF) << 8)); - if (sq_per_B == 0) - { - sq_per_B = 0x1000; - } - - sq_per_C = (Register[4] & 0xFF) | (((Register[5] & 0xF) << 8)); - if (sq_per_C == 0) - { - sq_per_C = 0x1000; - } - - env_per = (Register[11] & 0xFF) | (((Register[12] & 0xFF) << 8)); - if (env_per == 0) - { - env_per = 0x10000; - } - - env_per *= 2; - - A_on = (Register[7] & 0x1) > 0; - B_on = (Register[7] & 0x2) > 0; - C_on = (Register[7] & 0x4) > 0; - A_noise = (Register[7] & 0x8) > 0; - B_noise = (Register[7] & 0x10) > 0; - C_noise = (Register[7] & 0x20) > 0; - - noise_per = Register[6] & 0x1F; - if (noise_per == 0) - { - noise_per = 0x20; - } - - uint8_t shape_select = Register[13] & 0xF; - - if (shape_select < 4) { env_shape = 0; } - else if (shape_select < 8) { env_shape = 1; } - else { env_shape = 2 + (shape_select - 8); } - - vol_A = Register[8] & 0xF; - env_vol_A = ((Register[8] >> 4) & 0x1) > 0; - - vol_B = Register[9] & 0xF; - env_vol_B = ((Register[9] >> 4) & 0x1) > 0; - - vol_C = Register[10] & 0xF; - env_vol_C = ((Register[10] >> 4) & 0x1) > 0; - } - - void WriteReg(uint8_t value) - { - value &= 0xFF; - - if (port_sel != 0xE) { Register[port_sel] = value; } - - - sync_psg_state(); - - if (port_sel == 13) - { - env_clock = env_per; - - if (env_shape == 0 || env_shape == 2 || env_shape == 3 || env_shape == 4 || env_shape == 5) - { - env_E = 15; - E_up_down = -1; - } - else - { - env_E = 0; - E_up_down = 1; - } - } - } - - void generate_sound() - { - // there are 8 cpu cycles for every psg cycle - clock_A--; - clock_B--; - clock_C--; - - noise_clock--; - env_clock--; - - // clock noise - if (noise_clock == 0) - { - noise = (noise >> 1) ^ (((noise &0x1) > 0) ? 0x10004 : 0); - noise_clock = noise_per; - } - - if (env_clock == 0) - { - env_clock = env_per; - - env_E += E_up_down; - - if (env_E == 16 || env_E == -1) - { - // we just completed a period of the envelope, determine what to do now based on the envelope shape - if (env_shape == 0 || env_shape == 1 || env_shape == 3 || env_shape == 9) - { - E_up_down = 0; - env_E = 0; - } - else if (env_shape == 5 || env_shape == 7) - { - E_up_down = 0; - env_E = 15; - } - else if (env_shape == 4 || env_shape == 8) - { - if (env_E == 16) - { - env_E = 15; - E_up_down = -1; - } - else - { - env_E = 0; - E_up_down = 1; - } - } - else if (env_shape == 2) - { - env_E = 15; - } - else - { - env_E = 0; - } - } - } - - if (clock_A == 0) - { - A_up = !A_up; - clock_A = sq_per_A; - } - - if (clock_B == 0) - { - B_up = !B_up; - clock_B = sq_per_B; - } - - if (clock_C == 0) - { - C_up = !C_up; - clock_C = sq_per_C; - } - - sound_out_A = (((noise & 0x1) > 0) | A_noise) & (A_on | A_up); - sound_out_B = (((noise & 0x1) > 0) | B_noise) & (B_on | B_up); - sound_out_C = (((noise & 0x1) > 0) | C_noise) & (C_on | C_up); - - // now calculate the volume of each channel and add them together - current_sample = 0; - - if (env_vol_A) - { - current_sample = (sound_out_A ? VolumeTable[env_E] : 0); - } - else - { - current_sample = (sound_out_A ? VolumeTable[vol_A] : 0); - } - - if (env_vol_B) - { - current_sample += (sound_out_B ? VolumeTable[env_E] : 0); - } - else - { - current_sample += (sound_out_B ? VolumeTable[vol_B] : 0); - } - - if (env_vol_C) - { - current_sample += (sound_out_C ? VolumeTable[env_E] : 0); - } - else - { - current_sample += (sound_out_C ? VolumeTable[vol_C] : 0); - } - - current_sample *= 2; - - if ((current_sample != old_sample) && (num_samples < 4500)) - { - samples[num_samples * 2] = sampleclock; - samples[num_samples * 2 + 1] = current_sample - old_sample; - num_samples++; - old_sample = current_sample; - } - } - - #pragma endregion - - #pragma region State Save / Load - - uint8_t* SaveState(uint8_t* saver) - { - *saver = (uint8_t)(A_on ? 1 : 0); saver++; - *saver = (uint8_t)(B_on ? 1 : 0); saver++; - *saver = (uint8_t)(C_on ? 1 : 0); saver++; - *saver = (uint8_t)(A_up ? 1 : 0); saver++; - *saver = (uint8_t)(B_up ? 1 : 0); saver++; - *saver = (uint8_t)(C_up ? 1 : 0); saver++; - *saver = (uint8_t)(A_noise ? 1 : 0); saver++; - *saver = (uint8_t)(B_noise ? 1 : 0); saver++; - *saver = (uint8_t)(C_noise ? 1 : 0); saver++; - *saver = (uint8_t)(env_vol_A ? 1 : 0); saver++; - *saver = (uint8_t)(env_vol_B ? 1 : 0); saver++; - *saver = (uint8_t)(env_vol_C ? 1 : 0); saver++; - - *saver = env_shape; saver++; - *saver = port_sel; saver++; - *saver = vol_A; saver++; - *saver = vol_B; saver++; - *saver = vol_C; saver++; - - for (int i = 0; i < 16; i++) { *saver = Register[i]; saver++; } - - *saver = (uint8_t)(psg_clock & 0xFF); saver++; *saver = (uint8_t)((psg_clock >> 8) & 0xFF); saver++; - *saver = (uint8_t)((psg_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((psg_clock >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(sq_per_A & 0xFF); saver++; *saver = (uint8_t)((sq_per_A >> 8) & 0xFF); saver++; - *saver = (uint8_t)((sq_per_A >> 16) & 0xFF); saver++; *saver = (uint8_t)((sq_per_A >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(sq_per_B & 0xFF); saver++; *saver = (uint8_t)((sq_per_B >> 8) & 0xFF); saver++; - *saver = (uint8_t)((sq_per_B >> 16) & 0xFF); saver++; *saver = (uint8_t)((sq_per_B >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(sq_per_C & 0xFF); saver++; *saver = (uint8_t)((sq_per_C >> 8) & 0xFF); saver++; - *saver = (uint8_t)((sq_per_C >> 16) & 0xFF); saver++; *saver = (uint8_t)((sq_per_C >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(clock_A & 0xFF); saver++; *saver = (uint8_t)((clock_A >> 8) & 0xFF); saver++; - *saver = (uint8_t)((clock_A >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_A >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(clock_B & 0xFF); saver++; *saver = (uint8_t)((clock_B >> 8) & 0xFF); saver++; - *saver = (uint8_t)((clock_B >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_B >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(clock_C & 0xFF); saver++; *saver = (uint8_t)((clock_C >> 8) & 0xFF); saver++; - *saver = (uint8_t)((clock_C >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_C >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(env_per & 0xFF); saver++; *saver = (uint8_t)((env_per >> 8) & 0xFF); saver++; - *saver = (uint8_t)((env_per >> 16) & 0xFF); saver++; *saver = (uint8_t)((env_per >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(env_clock & 0xFF); saver++; *saver = (uint8_t)((env_clock >> 8) & 0xFF); saver++; - *saver = (uint8_t)((env_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((env_clock >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(env_E & 0xFF); saver++; *saver = (uint8_t)((env_E >> 8) & 0xFF); saver++; - *saver = (uint8_t)((env_E >> 16) & 0xFF); saver++; *saver = (uint8_t)((env_E >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(E_up_down & 0xFF); saver++; *saver = (uint8_t)((E_up_down >> 8) & 0xFF); saver++; - *saver = (uint8_t)((E_up_down >> 16) & 0xFF); saver++; *saver = (uint8_t)((E_up_down >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(noise_clock & 0xFF); saver++; *saver = (uint8_t)((noise_clock >> 8) & 0xFF); saver++; - *saver = (uint8_t)((noise_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise_clock >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(noise_per & 0xFF); saver++; *saver = (uint8_t)((noise_per >> 8) & 0xFF); saver++; - *saver = (uint8_t)((noise_per >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise_per >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(noise & 0xFF); saver++; *saver = (uint8_t)((noise >> 8) & 0xFF); saver++; - *saver = (uint8_t)((noise >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(old_sample & 0xFF); saver++; *saver = (uint8_t)((old_sample >> 8) & 0xFF); saver++; - *saver = (uint8_t)((old_sample >> 16) & 0xFF); saver++; *saver = (uint8_t)((old_sample >> 24) & 0xFF); saver++; - - return saver; - } - - uint8_t* LoadState(uint8_t* loader) - { - A_on = *loader == 1; loader++; - B_on = *loader == 1; loader++; - C_on = *loader == 1; loader++; - A_up = *loader == 1; loader++; - B_up = *loader == 1; loader++; - C_up = *loader == 1; loader++; - A_noise = *loader == 1; loader++; - B_noise = *loader == 1; loader++; - C_noise = *loader == 1; loader++; - env_vol_A = *loader == 1; loader++; - env_vol_B = *loader == 1; loader++; - env_vol_C = *loader == 1; loader++; - - env_shape = *loader; loader++; - port_sel = *loader; loader++; - vol_A = *loader; loader++; - vol_B = *loader; loader++; - vol_C = *loader; loader++; - - for (int i = 0; i < 16; i++) { Register[i] = *loader; loader++; } - - psg_clock = *loader; loader++; psg_clock |= (*loader << 8); loader++; - psg_clock |= (*loader << 16); loader++; psg_clock |= (*loader << 24); loader++; - - sq_per_A = *loader; loader++; sq_per_A |= (*loader << 8); loader++; - sq_per_A |= (*loader << 16); loader++; sq_per_A |= (*loader << 24); loader++; - - sq_per_B = *loader; loader++; sq_per_B |= (*loader << 8); loader++; - sq_per_B |= (*loader << 16); loader++; sq_per_B |= (*loader << 24); loader++; - - sq_per_C = *loader; loader++; sq_per_C |= (*loader << 8); loader++; - sq_per_C |= (*loader << 16); loader++; sq_per_C |= (*loader << 24); loader++; - - clock_A = *loader; loader++; clock_A |= (*loader << 8); loader++; - clock_A |= (*loader << 16); loader++; clock_A |= (*loader << 24); loader++; - - clock_B = *loader; loader++; clock_B |= (*loader << 8); loader++; - clock_B |= (*loader << 16); loader++; clock_B |= (*loader << 24); loader++; - - clock_C = *loader; loader++; clock_C |= (*loader << 8); loader++; - clock_C |= (*loader << 16); loader++; clock_C |= (*loader << 24); loader++; - - env_per = *loader; loader++; env_per |= (*loader << 8); loader++; - env_per |= (*loader << 16); loader++; env_per |= (*loader << 24); loader++; - - env_clock = *loader; loader++; env_clock |= (*loader << 8); loader++; - env_clock |= (*loader << 16); loader++; env_clock |= (*loader << 24); loader++; - - env_E = *loader; loader++; env_E |= (*loader << 8); loader++; - env_E |= (*loader << 16); loader++; env_E |= (*loader << 24); loader++; - - E_up_down = *loader; loader++; E_up_down |= (*loader << 8); loader++; - E_up_down |= (*loader << 16); loader++; E_up_down |= (*loader << 24); loader++; - - noise_clock = *loader; loader++; noise_clock |= (*loader << 8); loader++; - noise_clock |= (*loader << 16); loader++; noise_clock |= (*loader << 24); loader++; - - noise_per = *loader; loader++; noise_per |= (*loader << 8); loader++; - noise_per |= (*loader << 16); loader++; noise_per |= (*loader << 24); loader++; - - noise = *loader; loader++; noise |= (*loader << 8); loader++; - noise |= (*loader << 16); loader++; noise |= (*loader << 24); loader++; - - old_sample = *loader; loader++; old_sample |= (*loader << 8); loader++; - old_sample |= (*loader << 16); loader++; old_sample |= (*loader << 24); loader++; - - return loader; - } - - #pragma endregion - }; -} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/Core.h b/libHawk/GBHawk/GBHawk/Core.h index d937b697cb..0988c06d54 100644 --- a/libHawk/GBHawk/GBHawk/Core.h +++ b/libHawk/GBHawk/GBHawk/Core.h @@ -4,7 +4,7 @@ #include #include "LR35902.h" -#include "AY_3_8910.h" +#include "GBAudio.h" #include "TMS9918A.h" #include "Memory.h" @@ -21,13 +21,12 @@ namespace GBHawk cpu.mem_ctrl = &MemMap; vdp.IRQ_PTR = &cpu.FlagI; vdp.SHOW_BG = vdp.SHOW_SPRITES = true; - psg.Clock_Divider = 16; sl_case = 0; }; TMS9918A vdp; - Z80A cpu; - AY_3_8910 psg; + LR35902 cpu; + GBAudio psg; MemoryManager MemMap; uint8_t sl_case = 0; @@ -44,14 +43,6 @@ namespace GBHawk bool FrameAdvance(uint8_t controller_1, uint8_t controller_2, uint8_t* kb_rows_ptr, bool render, bool rendersound) { - if ((MemMap.psg_pntr->Register[0xF] & 0x40) > 0) - { - MemMap.psg_pntr->Register[0xE] = controller_2; - } - else - { - MemMap.psg_pntr->Register[0xE] = controller_1; - } MemMap.controller_byte_1 = controller_1; MemMap.controller_byte_2 = controller_2; @@ -62,83 +53,6 @@ namespace GBHawk uint32_t scanlinesPerFrame = 262; vdp.SpriteLimit = true; - psg.num_samples = 0; - psg.sampleclock = 0; - - for (uint32_t i = 0; i < scanlinesPerFrame; i++) - { - vdp.ScanLine = i; - - vdp.RenderScanline(i); - - if (vdp.ScanLine == 192) - { - vdp.InterruptPendingSet(true); - - if (vdp.EnableInterrupts()) { cpu.FlagI = true; } - } - - switch (sl_case) - { - case 0: - for (int i = 0; i < 14; i++) - { - cpu.ExecuteOne(16); - psg.sampleclock+=16; - psg.generate_sound(); - } - cpu.ExecuteOne(4); - psg.sampleclock += 4; - sl_case = 1; - break; - - case 1: - cpu.ExecuteOne(12); - psg.sampleclock += 12; - psg.generate_sound(); - - for (int i = 0; i < 13; i++) - { - cpu.ExecuteOne(16); - psg.sampleclock += 16; - psg.generate_sound(); - } - cpu.ExecuteOne(8); - psg.sampleclock += 8; - sl_case = 2; - break; - - case 2: - cpu.ExecuteOne(8); - psg.sampleclock += 8; - psg.generate_sound(); - - for (int i = 0; i < 13; i++) - { - cpu.ExecuteOne(16); - psg.sampleclock += 16; - psg.generate_sound(); - } - cpu.ExecuteOne(12); - psg.sampleclock += 12; - sl_case = 3; - break; - case 3: - cpu.ExecuteOne(4); - psg.sampleclock += 4; - psg.generate_sound(); - - for (int i = 0; i < 14; i++) - { - cpu.ExecuteOne(16); - psg.sampleclock += 16; - psg.generate_sound(); - } - sl_case = 0; - break; - } - } - return MemMap.lagged; } @@ -150,15 +64,21 @@ namespace GBHawk std::memcpy(dst, src, sizeof uint32_t * 256 * 192); } - uint32_t GetAudio(int32_t* dest, int32_t* n_samp) + 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; - int32_t* dst = dest; + int32_t* src = psg.samples_L; + int32_t* dst = dest_L; - std::memcpy(dst, src, sizeof int32_t * psg.num_samples * 2); - n_samp[0] = psg.num_samples; + std::memcpy(dst, src, sizeof int32_t * psg.num_samples_L * 2); + n_samp_L[0] = psg.num_samples_L; - return psg.sampleclock; + 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; + + return psg.master_audio_clock; } #pragma region State Save / Load @@ -189,11 +109,7 @@ namespace GBHawk uint8_t GetSysBus(uint32_t addr) { - cpu.bank_num = cpu.bank_offset = addr & 0xFFFF; - cpu.bank_offset &= cpu.low_mask; - cpu.bank_num = (cpu.bank_num >> cpu.bank_shift)& cpu.high_mask; - - return cpu.MemoryMap[cpu.bank_num][cpu.bank_offset]; + return cpu.PeekMemory(addr); } uint8_t GetVRAM(uint32_t addr) @@ -257,11 +173,15 @@ namespace GBHawk } else if (t == 1) { - memcpy(d, cpu.NMI_event, l); + memcpy(d, cpu.Un_halt_event, l); + } + else if (t == 2) + { + memcpy(d, cpu.IRQ_event, l); } else { - memcpy(d, cpu.IRQ_event, l); + memcpy(d, cpu.Un_halt_event, l); } } diff --git a/libHawk/GBHawk/GBHawk/GBAudio.h b/libHawk/GBHawk/GBHawk/GBAudio.h new file mode 100644 index 0000000000..c0ba759563 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/GBAudio.h @@ -0,0 +1,1396 @@ +#include +#include +#include +#include + +using namespace std; + +namespace GBHawk +{ + class GBAudio + { + public: + + #pragma region GBAudio + + uint32_t num_samples_L, num_samples_R; + int32_t samples_L[9000] = {}; + int32_t samples_R[9000] = {}; + + //GBHawk Core{ get; set; } + // Core variables + bool is_GBC, double_speed; + uint32_t timer_div_reg; + + 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; + bool AUD_CTRL_vin_R_en; + bool AUD_CTRL_sq1_L_en; + bool AUD_CTRL_sq2_L_en; + bool AUD_CTRL_wave_L_en; + bool AUD_CTRL_noise_L_en; + bool AUD_CTRL_sq1_R_en; + bool AUD_CTRL_sq2_R_en; + bool AUD_CTRL_wave_R_en; + bool AUD_CTRL_noise_R_en; + bool AUD_CTRL_power; + uint8_t AUD_CTRL_vol_L; + uint8_t AUD_CTRL_vol_R; + + uint32_t sequencer_len, sequencer_vol, sequencer_swp; + bool timer_bit_old; + + 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) { 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) + { + // 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) { 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) + { + SQ1_length = (uint32_t)(64 - (value & 0x3F)); + SQ1_len_cntr = SQ1_length; + } + break; + case 0xFF16: // NR21 (sound length / wave pattern duty %) + if (!is_GBC) + { + SQ2_length = (uint32_t)(64 - (value & 0x3F)); + SQ2_len_cntr = SQ2_length; + } + break; + case 0xFF1B: // NR31 (length) + if (!is_GBC) + { + WAVE_length = (uint32_t)(256 - value); + WAVE_len_cntr = WAVE_length; + } + break; + case 0xFF20: // NR41 (length) + if (!is_GBC) + { + 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 ? ((timer_div_reg & 0x2000) > 0) : ((timer_div_reg & 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 ? ((timer_div_reg & 0x2000) > 0) : ((timer_div_reg & 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) + { + 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) + { + 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(is_GBC, saver); + saver = bool_saver(double_speed, saver); + saver = int_saver(timer_div_reg, 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(&is_GBC, loader); + loader = bool_loader(&double_speed, loader); + loader = int_loader(&timer_div_reg, 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; + } + + #pragma endregion + + 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; + } + }; +} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/GBHawk.cpp b/libHawk/GBHawk/GBHawk/GBHawk.cpp index cbdc64dbb7..8c02c37456 100644 --- a/libHawk/GBHawk/GBHawk/GBHawk.cpp +++ b/libHawk/GBHawk/GBHawk/GBHawk.cpp @@ -53,9 +53,9 @@ GBHawk_EXPORT void GB_get_video(GBCore* p, uint32_t* dest) } // send audio data to external audio provider -GBHawk_EXPORT uint32_t GB_get_audio(GBCore* p, int32_t* dest, int32_t* n_samp) +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, n_samp); + return p->GetAudio(dest_L, n_samp_L, dest_R, n_samp_R); } #pragma region State Save / Load diff --git a/libHawk/GBHawk/GBHawk/GBHawk.vcxproj b/libHawk/GBHawk/GBHawk/GBHawk.vcxproj index 547228280b..ede8ced20b 100644 --- a/libHawk/GBHawk/GBHawk/GBHawk.vcxproj +++ b/libHawk/GBHawk/GBHawk/GBHawk.vcxproj @@ -151,7 +151,7 @@ - + diff --git a/libHawk/GBHawk/GBHawk/LR35902.cpp b/libHawk/GBHawk/GBHawk/LR35902.cpp index d264e78980..0cb691e652 100644 --- a/libHawk/GBHawk/GBHawk/LR35902.cpp +++ b/libHawk/GBHawk/GBHawk/LR35902.cpp @@ -11,10 +11,7 @@ namespace GBHawk { void LR35902::WriteMemory(uint32_t addr, uint8_t value) { - if ((addr & 0xFFFF) >= 0xFFFC) - { - mem_ctrl->MemoryWrite(addr, value); - } + mem_ctrl->MemoryWrite(addr, value); } uint8_t LR35902::ReadMemory(uint32_t addr) @@ -22,6 +19,11 @@ namespace GBHawk return mem_ctrl->HardwareRead(addr); } + uint8_t LR35902::PeekMemory(uint32_t addr) + { + return mem_ctrl->HardwareRead(addr); + } + uint8_t LR35902::SpeedFunc(uint32_t addr) { return mem_ctrl->HardwareRead(addr); diff --git a/libHawk/GBHawk/GBHawk/LR35902.h b/libHawk/GBHawk/GBHawk/LR35902.h index 0f350d9b49..b409984b99 100644 --- a/libHawk/GBHawk/GBHawk/LR35902.h +++ b/libHawk/GBHawk/GBHawk/LR35902.h @@ -18,74 +18,42 @@ namespace GBHawk // pointer to controlling memory manager goes here // this will be iplementation dependent MemoryManager* mem_ctrl; - - // Memory is usually mostly static, so it is efficient to access it with a pointer and write mask - // the size of the pointer matrix and masks is system dependent. - // This also assumes a simple relationship between bank and write mask - // some systems might require more detailed mask, maybe even the same size as read - const uint32_t low_mask = 0x3FF; - const uint32_t high_mask = 0x3F; - const uint32_t bank_shift = 10; - - // these are not savestated as they are automatically adjusted from the memory map upon load - uint32_t bank_num; - uint32_t bank_offset; - uint8_t* MemoryMap[64]; - uint8_t MemoryMapMask[64]; void WriteMemory(uint32_t, uint8_t); uint8_t ReadMemory(uint32_t); + uint8_t PeekMemory(uint32_t); uint8_t SpeedFunc(uint32_t); // State variables - uint64_t TotalExecutedCycles; - - uint32_t EI_pending; bool interrupts_enabled; - - // variables for executing instructions - int instr_pntr = 0; - int opcode; bool CB_prefix; bool halted; bool stopped; bool jammed; - int LY; - - // unsaved variables - bool checker; - uint8_t Regs[14] = {}; - bool was_FlagI, FlagI; + uint8_t Regs[14] = {}; + uint8_t EI_pending; + uint8_t LY; + uint8_t opcode; - uint32_t PRE_SRC; - // variables for executing instructions - uint32_t stepper = 0; uint32_t instr_pntr = 0; - uint32_t bus_pntr = 0; - uint32_t mem_pntr = 0; - uint32_t irq_pntr = 0; - uint32_t IRQS; - uint32_t Ztemp2_saver = 0; - uint32_t IRQS_cond_offset; uint64_t TotalExecutedCycles; - - uint32_t* cur_instr_ofst = nullptr; - uint32_t* cur_bus_ofst = nullptr; - uint32_t* cur_mem_ofst = nullptr; - uint32_t* cur_irqs_ofst = nullptr; - + // non-state variables bool checker; - - - uint32_t Ztemp1, Ztemp2, Ztemp3, Ztemp4; - uint32_t Reg16_d, Reg16_s, ans, temp, carry; + 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 @@ -171,19 +139,19 @@ namespace GBHawk #pragma region LR35902 functions inline bool FlagCget() { return (Regs[5] & 0x10) != 0; }; - inline void FlagCset(bool value) { Regs[5] = (uint32_t)((Regs[5] & ~0x10) | (value ? 0x10 : 0x00)); } + 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] = (uint32_t)((Regs[5] & ~0x20) | (value ? 0x20 : 0x00)); } + 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] = (uint32_t)((Regs[5] & ~0x40) | (value ? 0x40 : 0x00)); } + 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] = (uint32_t)((Regs[5] & ~0x80) | (value ? 0x80 : 0x00)); } + 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] = (uint32_t)(value & 0xFF); Regs[1] = (uint32_t)((value >> 8) & 0xFF); } + inline void RegPCset(uint32_t value) { Regs[0] = (uint8_t)(value & 0xFF); Regs[1] = (uint8_t)((value >> 8) & 0xFF); } LR35902() { @@ -211,7 +179,7 @@ namespace GBHawk CB_prefix = false; } - inline void FetchInstruction(uint32_t op) + inline void FetchInstruction(uint8_t op) { opcode = op; @@ -368,15 +336,15 @@ namespace GBHawk case HALT: halted = true; - bool temp = false; + temp2 = false; if (instr_table[instr_pntr++] == 1) { - temp = FlagI; + temp2 = FlagI; } else { - temp = I_use; + temp2 = I_use; } if (EI_pending > 0 && !CB_prefix) @@ -389,7 +357,7 @@ namespace GBHawk } // if the I flag is asserted at the time of halt, don't halt - if (temp && interrupts_enabled && !CB_prefix && !jammed) + if (temp2 && interrupts_enabled && !CB_prefix && !jammed) { interrupts_enabled = false; @@ -418,7 +386,7 @@ namespace GBHawk Halt_bug_3 = false; } } - else if (temp) + else if (temp2) { // even if interrupt servicing is disabled, any interrupt flag raised still resumes execution if (TraceCallback) { TraceCallback(1); } @@ -560,7 +528,8 @@ namespace GBHawk // 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 - uint32_t bit_check = instr_table[instr_pntr++]; + 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 & (1 << bit_check)) > 0)) { int_src = bit_check; int_clear = (uint8_t)(1 << bit_check); } @@ -572,7 +541,8 @@ namespace GBHawk 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]; + Regs[instr_table[instr_pntr]] = INT_vectors[int_src]; + instr_pntr++; break; case HALT_CHK: I_use = FlagI; @@ -587,7 +557,7 @@ namespace GBHawk Halt_bug_2 = false; break; case IRQ_CLEAR: - if ((interrupt_src[0] & (1 << int_src)) > 0) { interrupt_src -= int_clear; } + if ((interrupt_src[0] & (1 << int_src)) > 0) { interrupt_src[0] -= int_clear; } if ((interrupt_src[0] & interrupt_enable) == 0) { FlagI = false; } @@ -2164,13 +2134,6 @@ namespace GBHawk #pragma region Operations - // local variables for operations, not stated - uint32_t Reg16_d, Reg16_s, c; - uint32_t ans, ans_l, ans_h, temp; - uint8_t a_d; - bool imm; - - 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); @@ -2185,14 +2148,14 @@ namespace GBHawk // special read for POP AF that always clears the lower 4 bits of F void Read_Func_F(uint32_t dest, uint32_t src_l, uint32_t src_h) { - Regs[dest] = (uint32_t)(ReadMemory((uint32_t)(Regs[src_l] | (Regs[src_h]) << 8)) & 0xF0); + Regs[dest] = (ReadMemory((uint32_t)(Regs[src_l] | (Regs[src_h]) << 8)) & 0xF0); } 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, (uint8_t)Regs[src]); + WriteMemory(addr, Regs[src]); } void TR_Func(uint32_t dest, uint32_t src) @@ -2221,8 +2184,8 @@ namespace GBHawk FlagHset((Reg16_d & 0x1000) > 0); FlagNset(false); - Regs[dest_l] = ans_l; - Regs[dest_h] = ans_h; + Regs[dest_l] = (uint8_t)ans_l; + Regs[dest_h] = (uint8_t)ans_h; } void ADD8_Func(uint32_t dest, uint32_t src) @@ -2243,7 +2206,7 @@ namespace GBHawk FlagNset(false); - Regs[dest] = ans; + Regs[dest] = (uint8_t)ans; } void SUB8_Func(uint32_t dest, uint32_t src) @@ -2263,35 +2226,35 @@ namespace GBHawk FlagHset((Reg16_d & 0x10) > 0); FlagNset(true); - Regs[dest] = ans; + Regs[dest] = (uint8_t)ans; } void BIT_Func(uint32_t bit, uint32_t src) { - FlagZset(!Regs[src].Bit(bit)); + FlagZset(!((Regs[src] & (1 << bit)) > 0)); FlagHset(true); FlagNset(false); } void SET_Func(uint32_t bit, uint32_t src) { - Regs[src] |= (uint32_t)(1 << bit); + Regs[src] |= (uint8_t)(1 << bit); } void RES_Func(uint32_t bit, uint32_t src) { - Regs[src] &= (uint32_t)(0xFF - (1 << bit)); + Regs[src] &= (uint8_t)(0xFF - (1 << bit)); } void ASGN_Func(uint32_t src, uint32_t val) { - Regs[src] = val; + Regs[src] = (uint8_t)val; } void SWAP_Func(uint32_t src) { temp = (uint32_t)((Regs[src] << 4) & 0xF0); - Regs[src] = (uint32_t)(temp | (Regs[src] >> 4)); + Regs[src] = (uint8_t)(temp | (Regs[src] >> 4)); FlagZset(Regs[src] == 0); FlagHset(false); @@ -2301,9 +2264,9 @@ namespace GBHawk void SLA_Func(uint32_t src) { - FlagCset(Regs[src].Bit(7)); + FlagCset((Regs[src] & 0x80) > 0); - Regs[src] = (uint32_t)((Regs[src] << 1) & 0xFF); + Regs[src] = (uint8_t)((Regs[src] << 1) & 0xFF); FlagZset(Regs[src] == 0); FlagHset(false); @@ -2312,11 +2275,11 @@ namespace GBHawk void SRA_Func(uint32_t src) { - FlagCset(Regs[src].Bit(0)); + FlagCset((Regs[src] & 1) > 0); temp = (uint32_t)(Regs[src] & 0x80); // MSB doesn't change in this operation - Regs[src] = (uint32_t)((Regs[src] >> 1) | temp); + Regs[src] = (uint8_t)((Regs[src] >> 1) | temp); FlagZset(Regs[src] == 0); FlagHset(false); @@ -2325,9 +2288,9 @@ namespace GBHawk void SRL_Func(uint32_t src) { - FlagCset(Regs[src].Bit(0)); + FlagCset((Regs[src] & 1) > 0); - Regs[src] = (uint32_t)(Regs[src] >> 1); + Regs[src] = (uint8_t)(Regs[src] >> 1); FlagZset(Regs[src] == 0); FlagHset(false); @@ -2336,7 +2299,7 @@ namespace GBHawk void CPL_Func(uint32_t src) { - Regs[src] = (uint32_t)((~Regs[src]) & 0xFF); + Regs[src] = (uint8_t)((~Regs[src]) & 0xFF); FlagHset(true); FlagNset(true); @@ -2358,7 +2321,7 @@ namespace GBHawk void AND8_Func(uint32_t dest, uint32_t src) { - Regs[dest] = (uint32_t)(Regs[dest] & Regs[src]); + Regs[dest] = (uint8_t)(Regs[dest] & Regs[src]); FlagZset(Regs[dest] == 0); FlagCset(false); @@ -2368,7 +2331,7 @@ namespace GBHawk void OR8_Func(uint32_t dest, uint32_t src) { - Regs[dest] = (uint32_t)(Regs[dest] | Regs[src]); + Regs[dest] = (uint8_t)(Regs[dest] | Regs[src]); FlagZset(Regs[dest] == 0); FlagCset(false); @@ -2378,7 +2341,7 @@ namespace GBHawk void XOR8_Func(uint32_t dest, uint32_t src) { - Regs[dest] = (uint32_t)(Regs[dest] ^ Regs[src]); + Regs[dest] = (uint8_t)(Regs[dest] ^ Regs[src]); FlagZset(Regs[dest] == 0); FlagCset(false); @@ -2408,9 +2371,9 @@ namespace GBHawk imm = src == Aim; if (imm) { src = A; } - FlagCset(Regs[src].Bit(0)); + FlagCset((Regs[src] & 1) > 0); - Regs[src] = (uint32_t)((FlagCget() ? 0x80 : 0) | (Regs[src] >> 1)); + Regs[src] = (uint8_t)((FlagCget() ? 0x80 : 0) | (Regs[src] >> 1)); FlagZset(imm ? false : (Regs[src] == 0)); FlagHset(false); @@ -2424,9 +2387,9 @@ namespace GBHawk c = FlagCget() ? 0x80 : 0; - FlagCset(Regs[src].Bit(0)); + FlagCset((Regs[src] & 1) > 0); - Regs[src] = (uint32_t)(c | (Regs[src] >> 1)); + Regs[src] = (uint8_t)(c | (Regs[src] >> 1)); FlagZset(imm ? false : (Regs[src] == 0)); FlagHset(false); @@ -2438,10 +2401,10 @@ namespace GBHawk imm = src == Aim; if (imm) { src = A; } - c = Regs[src].Bit(7) ? 1 : 0; - FlagCset(Regs[src].Bit(7)); + c = (Regs[src] & 0x80) > 0 ? 1 : 0; + FlagCset((Regs[src] & 0x80) > 0); - Regs[src] = (uint32_t)(((Regs[src] << 1) & 0xFF) | c); + Regs[src] = (uint8_t)(((Regs[src] << 1) & 0xFF) | c); FlagZset(imm ? false : (Regs[src] == 0)); FlagHset(false); @@ -2454,9 +2417,9 @@ namespace GBHawk if (imm) { src = A; } c = FlagCget() ? 1 : 0; - FlagCset(Regs[src].Bit(7)); + FlagCset((Regs[src] & 0x80) > 0); - Regs[src] = (uint32_t)(((Regs[src] << 1) & 0xFF) | c); + Regs[src] = (uint8_t)(((Regs[src] << 1) & 0xFF) | c); FlagZset(imm ? false : (Regs[src] == 0)); FlagHset(false); @@ -2479,7 +2442,7 @@ namespace GBHawk FlagHset((Reg16_d & 0x10) > 0); FlagNset(false); - Regs[src] = ans; + Regs[src] = (uint8_t)ans; } void DEC8_Func(uint32_t src) @@ -2498,7 +2461,7 @@ namespace GBHawk FlagHset((Reg16_d & 0x10) > 0); FlagNset(true); - Regs[src] = ans; + Regs[src] = (uint8_t)ans; } void INC16_Func(uint32_t src_l, uint32_t src_h) @@ -2507,8 +2470,8 @@ namespace GBHawk Reg16_d += 1; - Regs[src_l] = (uint32_t)(Reg16_d & 0xFF); - Regs[src_h] = (uint32_t)((Reg16_d & 0xFF00) >> 8); + Regs[src_l] = (uint8_t)(Reg16_d & 0xFF); + Regs[src_h] = (uint8_t)((Reg16_d & 0xFF00) >> 8); } void DEC16_Func(uint32_t src_l, uint32_t src_h) @@ -2517,8 +2480,8 @@ namespace GBHawk Reg16_d -= 1; - Regs[src_l] = (uint32_t)(Reg16_d & 0xFF); - Regs[src_h] = (uint32_t)((Reg16_d & 0xFF00) >> 8); + Regs[src_l] = (uint8_t)(Reg16_d & 0xFF); + Regs[src_h] = (uint8_t)((Reg16_d & 0xFF00) >> 8); } void ADC8_Func(uint32_t dest, uint32_t src) @@ -2540,7 +2503,7 @@ namespace GBHawk FlagHset((Reg16_d & 0x10) > 0); FlagNset(false); - Regs[dest] = ans; + Regs[dest] = (uint8_t)ans; } void SBC8_Func(uint32_t dest, uint32_t src) @@ -2562,7 +2525,7 @@ namespace GBHawk FlagHset((Reg16_d & 0x10) > 0); FlagNset(true); - Regs[dest] = ans; + Regs[dest] = (uint8_t)ans; } // DA code courtesy of AWJ: http://forums.nesdev.com/viewtopic.php?f=20&t=15944 @@ -2583,7 +2546,7 @@ namespace GBHawk a_d &= 0xFF; - Regs[src] = a_d; + Regs[src] = (uint8_t)a_d; FlagZset(a_d == 0); FlagHset(false); @@ -2632,9 +2595,9 @@ namespace GBHawk FlagZset(false); } - Regs[dest_l] = ans_l; - Regs[dest_h] += temp; - Regs[dest_h] &= 0xFF; + Regs[dest_l] = (uint8_t)ans_l; + Regs[dest_h] += (uint8_t)temp; + Regs[dest_h] &= (uint8_t)0xFF; } @@ -2646,7 +2609,7 @@ namespace GBHawk const char* TraceHeader = "Z80A: PC, machine code, mnemonic, operands, registers (AF, BC, DE, HL, IX, IY, SP, Cy), flags (CNP3H5ZS)"; const char* Un_halt_event = " ==Un-halted== "; const char* IRQ_event = " ====IRQ==== "; - const char* Un_halt_event = " ==Un-stopped== "; + const char* Un_stop_event = " ==Un-stopped== "; const char* No_Reg = " "; const char* Reg_template = "AF:AAFF BC:BBCC DE:DDEE HL:HHLL Ix:IxIx Iy:IyIy SP:SPSP Cy:FEDCBA9876543210 CNP3H5ZSE"; const char* Disasm_template = "PCPC: AA BB CC DD Di Di, XXXXX "; @@ -2689,7 +2652,7 @@ namespace GBHawk reg_state.append(val_char_1, 4); reg_state.append(" Cy:"); - reg_state.append(val_char_1, sprintf_s(val_char_1, 32, "%16u", (uint64_t)TotalExecutedCycles)); + reg_state.append(val_char_1, sprintf_s(val_char_1, 32, "%16u", (unsigned long)TotalExecutedCycles)); reg_state.append(" "); reg_state.append(FlagCget() ? "C" : "c"); @@ -2719,12 +2682,8 @@ namespace GBHawk for (i = 0; i < bytes_read; i++) { - bank_num = bank_offset = (RegPCget() + i) & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift)& high_mask; - char* val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%02X", MemoryMap[bank_num][bank_offset]); + sprintf_s(val_char_1, 5, "%02X", PeekMemory((RegPCget() + i) & 0xFFFF)); string val1(val_char_1, 2); byte_code.append(val1); @@ -2759,23 +2718,15 @@ namespace GBHawk { size_t str_loc = format.find("nn"); - bank_num = bank_offset = addr[0] & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift) & high_mask; - addr[0]++; - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%02X", MemoryMap[bank_num][bank_offset]); + sprintf_s(val_char_1, 5, "%02X", PeekMemory(addr[0] & 0xFFFF)); string val1(val_char_1, 2); - - bank_num = bank_offset = addr[0] & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift)& high_mask; addr[0]++; val_char_2 = replacer; - sprintf_s(val_char_2, 5, "%02X", MemoryMap[bank_num][bank_offset]); + sprintf_s(val_char_2, 5, "%02X", PeekMemory(addr[0] & 0xFFFF)); string val2(val_char_2, 2); + addr[0]++; format.erase(str_loc, 2); format.insert(str_loc, val1); @@ -2786,14 +2737,10 @@ namespace GBHawk { size_t str_loc = format.find("n"); - bank_num = bank_offset = addr[0] & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift)& high_mask; - addr[0]++; - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%02X", MemoryMap[bank_num][bank_offset]); + sprintf_s(val_char_1, 5, "%02X", PeekMemory(addr[0] & 0xFFFF)); string val1(val_char_1, 2); + addr[0]++; format.erase(str_loc, 1); format.insert(str_loc, val1); @@ -2803,14 +2750,10 @@ namespace GBHawk { size_t str_loc = format.find("+d"); - bank_num = bank_offset = addr[0] & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift)& high_mask; - addr[0]++; - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%+04d", (int8_t)MemoryMap[bank_num][bank_offset]); + sprintf_s(val_char_1, 5, "%+04d", (int8_t)PeekMemory(addr[0] & 0xFFFF)); string val1(val_char_1, 4); + addr[0]++; format.erase(str_loc, 2); format.insert(str_loc, val1); @@ -2819,14 +2762,10 @@ namespace GBHawk { size_t str_loc = format.find("d"); - bank_num = bank_offset = addr[0] & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift)& high_mask; - addr[0]++; - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%+04d", (int8_t)MemoryMap[bank_num][bank_offset]); + sprintf_s(val_char_1, 5, "%+04d", (int8_t)PeekMemory(addr[0] & 0xFFFF)); string val1(val_char_1, 4); + addr[0]++; format.erase(str_loc, 1); format.insert(str_loc, val1); @@ -2840,22 +2779,14 @@ namespace GBHawk uint32_t start_addr = addr; uint32_t extra_inc = 0; - bank_num = bank_offset = addr & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift) & high_mask; + uint32_t A = PeekMemory(addr & 0xFFFF); addr++; - - uint32_t A = MemoryMap[bank_num][bank_offset]; string format; switch (A) { case 0xCB: - bank_num = bank_offset = addr & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift) & high_mask; + A = PeekMemory(addr & 0xFFFF); addr++; - - A = MemoryMap[bank_num][bank_offset]; format = mnemonics[A + 256]; break; @@ -2920,262 +2851,38 @@ namespace GBHawk "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", // 00 - "RLC C", // 01 - "RLC D", // 02 - "RLC E", // 03 - "RLC H", // 04 - "RLC L", // 05 - "RLC (HL)", // 06 - "RLC A", // 07 - "RRC B", // 08 - "RRC C", // 09 - "RRC D", // 0a - "RRC E", // 0b - "RRC H", // 0c - "RRC L", // 0d - "RRC (HL)", // 0e - "RRC A", // 0f - "RL B", // 10 - "RL C", // 11 - "RL D", // 12 - "RL E", // 13 - "RL H", // 14 - "RL L", // 15 - "RL (HL)", // 16 - "RL A", // 17 - "RR B", // 18 - "RR C", // 19 - "RR D", // 1a - "RR E", // 1b - "RR H", // 1c - "RR L", // 1d - "RR (HL)", // 1e - "RR A", // 1f - "SLA B", // 20 - "SLA C", // 21 - "SLA D", // 22 - "SLA E", // 23 - "SLA H", // 24 - "SLA L", // 25 - "SLA (HL)", // 26 - "SLA A", // 27 - "SRA B", // 28 - "SRA C", // 29 - "SRA D", // 2a - "SRA E", // 2b - "SRA H", // 2c - "SRA L", // 2d - "SRA (HL)", // 2e - "SRA A", // 2f - "SWAP B", // 30 - "SWAP C", // 31 - "SWAP D", // 32 - "SWAP E", // 33 - "SWAP H", // 34 - "SWAP L", // 35 - "SWAP (HL)", // 36 - "SWAP A", // 37 - "SRL B", // 38 - "SRL C", // 39 - "SRL D", // 3a - "SRL E", // 3b - "SRL H", // 3c - "SRL L", // 3d - "SRL (HL)", // 3e - "SRL A", // 3f - "BIT 0,B", // 40 - "BIT 0,C", // 41 - "BIT 0,D", // 42 - "BIT 0,E", // 43 - "BIT 0,H", // 44 - "BIT 0,L", // 45 - "BIT 0,(HL)", // 46 - "BIT 0,A", // 47 - "BIT 1,B", // 48 - "BIT 1,C", // 49 - "BIT 1,D", // 4a - "BIT 1,E", // 4b - "BIT 1,H", // 4c - "BIT 1,L", // 4d - "BIT 1,(HL)", // 4e - "BIT 1,A", // 4f - "BIT 2,B", // 50 - "BIT 2,C", // 51 - "BIT 2,D", // 52 - "BIT 2,E", // 53 - "BIT 2,H", // 54 - "BIT 2,L", // 55 - "BIT 2,(HL)", // 56 - "BIT 2,A", // 57 - "BIT 3,B", // 58 - "BIT 3,C", // 59 - "BIT 3,D", // 5a - "BIT 3,E", // 5b - "BIT 3,H", // 5c - "BIT 3,L", // 5d - "BIT 3,(HL)", // 5e - "BIT 3,A", // 5f - "BIT 4,B", // 60 - "BIT 4,C", // 61 - "BIT 4,D", // 62 - "BIT 4,E", // 63 - "BIT 4,H", // 64 - "BIT 4,L", // 65 - "BIT 4,(HL)", // 66 - "BIT 4,A", // 67 - "BIT 5,B", // 68 - "BIT 5,C", // 69 - "BIT 5,D", // 6a - "BIT 5,E", // 6b - "BIT 5,H", // 6c - "BIT 5,L", // 6d - "BIT 5,(HL)", // 6e - "BIT 5,A", // 6f - "BIT 6,B", // 70 - "BIT 6,C", // 71 - "BIT 6,D", // 72 - "BIT 6,E", // 73 - "BIT 6,H", // 74 - "BIT 6,L", // 75 - "BIT 6,(HL)", // 76 - "BIT 6,A", // 77 - "BIT 7,B", // 78 - "BIT 7,C", // 79 - "BIT 7,D", // 7a - "BIT 7,E", // 7b - "BIT 7,H", // 7c - "BIT 7,L", // 7d - "BIT 7,(HL)", // 7e - "BIT 7,A", // 7f - "RES 0,B", // 80 - "RES 0,C", // 81 - "RES 0,D", // 82 - "RES 0,E", // 83 - "RES 0,H", // 84 - "RES 0,L", // 85 - "RES 0,(HL)", // 86 - "RES 0,A", // 87 - "RES 1,B", // 88 - "RES 1,C", // 89 - "RES 1,D", // 8a - "RES 1,E", // 8b - "RES 1,H", // 8c - "RES 1,L", // 8d - "RES 1,(HL)", // 8e - "RES 1,A", // 8f - "RES 2,B", // 90 - "RES 2,C", // 91 - "RES 2,D", // 92 - "RES 2,E", // 93 - "RES 2,H", // 94 - "RES 2,L", // 95 - "RES 2,(HL)", // 96 - "RES 2,A", // 97 - "RES 3,B", // 98 - "RES 3,C", // 99 - "RES 3,D", // 9a - "RES 3,E", // 9b - "RES 3,H", // 9c - "RES 3,L", // 9d - "RES 3,(HL)", // 9e - "RES 3,A", // 9f - "RES 4,B", // a0 - "RES 4,C", // a1 - "RES 4,D", // a2 - "RES 4,E", // a3 - "RES 4,H", // a4 - "RES 4,L", // a5 - "RES 4,(HL)", // a6 - "RES 4,A", // a7 - "RES 5,B", // a8 - "RES 5,C", // a9 - "RES 5,D", // aa - "RES 5,E", // ab - "RES 5,H", // ac - "RES 5,L", // ad - "RES 5,(HL)", // ae - "RES 5,A", // af - "RES 6,B", // b0 - "RES 6,C", // b1 - "RES 6,D", // b2 - "RES 6,E", // b3 - "RES 6,H", // b4 - "RES 6,L", // b5 - "RES 6,(HL)", // b6 - "RES 6,A", // b7 - "RES 7,B", // b8 - "RES 7,C", // b9 - "RES 7,D", // ba - "RES 7,E", // bb - "RES 7,H", // bc - "RES 7,L", // bd - "RES 7,(HL)", // be - "RES 7,A", // bf - "SET 0,B", // c0 - "SET 0,C", // c1 - "SET 0,D", // c2 - "SET 0,E", // c3 - "SET 0,H", // c4 - "SET 0,L", // c5 - "SET 0,(HL)", // c6 - "SET 0,A", // c7 - "SET 1,B", // c8 - "SET 1,C", // c9 - "SET 1,D", // ca - "SET 1,E", // cb - "SET 1,H", // cc - "SET 1,L", // cd - "SET 1,(HL)", // ce - "SET 1,A", // cf - "SET 2,B", // d0 - "SET 2,C", // d1 - "SET 2,D", // d2 - "SET 2,E", // d3 - "SET 2,H", // d4 - "SET 2,L", // d5 - "SET 2,(HL)", // d6 - "SET 2,A", // d7 - "SET 3,B", // d8 - "SET 3,C", // d9 - "SET 3,D", // da - "SET 3,E", // db - "SET 3,H", // dc - "SET 3,L", // dd - "SET 3,(HL)", // de - "SET 3,A", // df - "SET 4,B", // e0 - "SET 4,C", // e1 - "SET 4,D", // e2 - "SET 4,E", // e3 - "SET 4,H", // e4 - "SET 4,L", // e5 - "SET 4,(HL)", // e6 - "SET 4,A", // e7 - "SET 5,B", // e8 - "SET 5,C", // e9 - "SET 5,D", // ea - "SET 5,E", // eb - "SET 5,H", // ec - "SET 5,L", // ed - "SET 5,(HL)", // ee - "SET 5,A", // ef - "SET 6,B", // f0 - "SET 6,C", // f1 - "SET 6,D", // f2 - "SET 6,E", // f3 - "SET 6,H", // f4 - "SET 6,L", // f5 - "SET 6,(HL)", // f6 - "SET 6,A", // f7 - "SET 7,B", // f8 - "SET 7,C", // f9 - "SET 7,D", // fa - "SET 7,E", // fb - "SET 7,H", // fc - "SET 7,L", // fd - "SET 7,(HL)", // fe - "SET 7,A", // ff + "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 @@ -3184,57 +2891,25 @@ namespace GBHawk uint8_t* SaveState(uint8_t* saver) { - *saver = (uint8_t)(NO_prefix ? 1 : 0); saver++; + + *saver = (uint8_t)(interrupts_enabled ? 1 : 0); saver++; *saver = (uint8_t)(CB_prefix ? 1 : 0); saver++; - *saver = (uint8_t)(IX_prefix ? 1 : 0); saver++; - *saver = (uint8_t)(EXTD_prefix ? 1 : 0); saver++; - *saver = (uint8_t)(IY_prefix ? 1 : 0); saver++; - *saver = (uint8_t)(IXCB_prefix ? 1 : 0); saver++; - *saver = (uint8_t)(IYCB_prefix ? 1 : 0); saver++; *saver = (uint8_t)(halted ? 1 : 0); saver++; - *saver = (uint8_t)(I_skip ? 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 = (uint8_t)(FlagW ? 1 : 0); saver++; - *saver = (uint8_t)(IFF1 ? 1 : 0); saver++; - *saver = (uint8_t)(IFF2 ? 1 : 0); saver++; - *saver = (uint8_t)(nonMaskableInterrupt ? 1 : 0); saver++; - *saver = (uint8_t)(nonMaskableInterruptPending ? 1 : 0); saver++; - *saver = (uint8_t)(jp_cond_chk ? 1 : 0); saver++; - *saver = (uint8_t)(cond_chk_fail ? 1 : 0); saver++; + *saver = (uint8_t)(halted ? 1 : 0); saver++; *saver = opcode; saver++; - *saver = temp_R; saver++; + *saver = LY; saver++; *saver = EI_pending; saver++; - *saver = interruptMode; saver++; - *saver = ExternalDB; saver++; - *saver = instr_bank; saver++; - for (int i = 0; i < 36; i++) { *saver = Regs[i]; saver++; } - - *saver = (uint8_t)(PRE_SRC & 0xFF); saver++; *saver = (uint8_t)((PRE_SRC >> 8) & 0xFF); saver++; - *saver = (uint8_t)((PRE_SRC >> 16) & 0xFF); saver++; *saver = (uint8_t)((PRE_SRC >> 24) & 0xFF); 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)(bus_pntr & 0xFF); saver++; *saver = (uint8_t)((bus_pntr >> 8) & 0xFF); saver++; - *saver = (uint8_t)((bus_pntr >> 16) & 0xFF); saver++; *saver = (uint8_t)((bus_pntr >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(mem_pntr & 0xFF); saver++; *saver = (uint8_t)((mem_pntr >> 8) & 0xFF); saver++; - *saver = (uint8_t)((mem_pntr >> 16) & 0xFF); saver++; *saver = (uint8_t)((mem_pntr >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(irq_pntr & 0xFF); saver++; *saver = (uint8_t)((irq_pntr >> 8) & 0xFF); saver++; - *saver = (uint8_t)((irq_pntr >> 16) & 0xFF); saver++; *saver = (uint8_t)((irq_pntr >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(IRQS & 0xFF); saver++; *saver = (uint8_t)((IRQS >> 8) & 0xFF); saver++; - *saver = (uint8_t)((IRQS >> 16) & 0xFF); saver++; *saver = (uint8_t)((IRQS >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(Ztemp2_saver & 0xFF); saver++; *saver = (uint8_t)((Ztemp2_saver >> 8) & 0xFF); saver++; - *saver = (uint8_t)((Ztemp2_saver >> 16) & 0xFF); saver++; *saver = (uint8_t)((Ztemp2_saver >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(IRQS_cond_offset & 0xFF); saver++; *saver = (uint8_t)((IRQS_cond_offset >> 8) & 0xFF); saver++; - *saver = (uint8_t)((IRQS_cond_offset >> 16) & 0xFF); saver++; *saver = (uint8_t)((IRQS_cond_offset >> 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 >> 16) & 0x32); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 40) & 0xFF); saver++; @@ -3245,179 +2920,23 @@ namespace GBHawk uint8_t* LoadState(uint8_t* loader) { - NO_prefix = *loader == 1; loader++; + interrupts_enabled = *loader == 1; loader++; CB_prefix = *loader == 1; loader++; - IX_prefix = *loader == 1; loader++; - EXTD_prefix = *loader == 1; loader++; - IY_prefix = *loader == 1; loader++; - IXCB_prefix = *loader == 1; loader++; - IYCB_prefix = *loader == 1; loader++; halted = *loader == 1; loader++; - I_skip = *loader == 1; loader++; + stopped = *loader == 1; loader++; + jammed = *loader == 1; loader++; + was_FlagI = *loader == 1; loader++; FlagI = *loader == 1; loader++; - FlagW = *loader == 1; loader++; - IFF1 = *loader == 1; loader++; - IFF2 = *loader == 1; loader++; - nonMaskableInterrupt = *loader == 1; loader++; - nonMaskableInterruptPending = *loader == 1; loader++; - jp_cond_chk = *loader == 1; loader++; - cond_chk_fail = *loader == 1; loader++; opcode = *loader; loader++; - temp_R = *loader; loader++; + LY = *loader; loader++; EI_pending = *loader; loader++; - interruptMode = *loader; loader++; - ExternalDB = *loader; loader++; - instr_bank = *loader; loader++; - for (int i = 0; i < 36; i++) { Regs[i] = *loader; loader++; } - - PRE_SRC = *loader; loader++; PRE_SRC |= (*loader << 8); loader++; - PRE_SRC |= (*loader << 16); loader++; PRE_SRC |= (*loader << 24); 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++; - bus_pntr = *loader; loader++; bus_pntr |= (*loader << 8); loader++; - bus_pntr |= (*loader << 16); loader++; bus_pntr |= (*loader << 24); loader++; - - mem_pntr = *loader; loader++; mem_pntr |= (*loader << 8); loader++; - mem_pntr |= (*loader << 16); loader++; mem_pntr |= (*loader << 24); loader++; - - irq_pntr = *loader; loader++; irq_pntr |= (*loader << 8); loader++; - irq_pntr |= (*loader << 16); loader++; irq_pntr |= (*loader << 24); loader++; - - IRQS = *loader; loader++; IRQS |= (*loader << 8); loader++; - IRQS |= (*loader << 16); loader++; IRQS |= (*loader << 24); loader++; - - Ztemp2_saver = *loader; loader++; Ztemp2_saver |= (*loader << 8); loader++; - Ztemp2_saver |= (*loader << 16); loader++; Ztemp2_saver |= (*loader << 24); loader++; - - IRQS_cond_offset = *loader; loader++; IRQS_cond_offset |= (*loader << 8); loader++; - IRQS_cond_offset |= (*loader << 16); loader++; IRQS_cond_offset |= (*loader << 24); loader++; - - // load instruction pointers based on state - if (instr_bank == 0) - { - cur_instr_ofst = &NoIndex[opcode * 38]; - cur_bus_ofst = &NoIndexBUSRQ[opcode * 19]; - cur_mem_ofst = &NoIndexMEMRQ[opcode * 19]; - cur_irqs_ofst = &NoIndexIRQS[opcode]; - } - else if (instr_bank == 1) - { - cur_instr_ofst = &CBIndex[opcode * 38]; - cur_bus_ofst = &CBIndexBUSRQ[opcode * 19]; - cur_mem_ofst = &CBIndexMEMRQ[opcode * 19]; - cur_irqs_ofst = &CBIndexIRQS[opcode]; - } - else if (instr_bank == 2) - { - cur_instr_ofst = &EXTIndex[opcode * 38]; - cur_bus_ofst = &EXTIndexBUSRQ[opcode * 19]; - cur_mem_ofst = &EXTIndexMEMRQ[opcode * 19]; - cur_irqs_ofst = &EXTIndexIRQS[opcode]; - } - else if (instr_bank == 3) - { - cur_instr_ofst = &IXIndex[opcode * 38]; - cur_bus_ofst = &IXIndexBUSRQ[opcode * 19]; - cur_mem_ofst = &IXIndexMEMRQ[opcode * 19]; - cur_irqs_ofst = &IXIndexIRQS[opcode]; - } - else if (instr_bank == 4) - { - cur_instr_ofst = &IYIndex[opcode * 38]; - cur_bus_ofst = &IYIndexBUSRQ[opcode * 19]; - cur_mem_ofst = &IYIndexMEMRQ[opcode * 19]; - cur_irqs_ofst = &IYIndexIRQS[opcode]; - } - else if (instr_bank == 5) - { - cur_instr_ofst = &IXYCBIndex[opcode * 38]; - cur_bus_ofst = &IXYCBIndexBUSRQ[opcode * 19]; - cur_mem_ofst = &IXYCBIndexMEMRQ[opcode * 19]; - cur_irqs_ofst = &IXYCBIndexIRQS[opcode]; - } - else if (instr_bank == 6) - { - cur_instr_ofst = &Reset_CPU[0]; - cur_bus_ofst = &Reset_BUSRQ[0]; - cur_mem_ofst = &Reset_MEMRQ[0]; - cur_irqs_ofst = &Reset_IRQS; - } - else if (instr_bank == 7) - { - cur_instr_ofst = &LD_OP_R_INST[0]; - cur_instr_ofst[14] = Ztemp2_saver; - cur_bus_ofst = &LD_OP_R_BUSRQ[0]; - cur_mem_ofst = &LD_OP_R_MEMRQ[0]; - cur_irqs_ofst = &LD_OP_R_IRQS; - } - else if (instr_bank == 8) - { - cur_instr_ofst = &LD_CP_R_INST[0]; - cur_instr_ofst[14] = Ztemp2_saver; - cur_bus_ofst = &LD_CP_R_BUSRQ[0]; - cur_mem_ofst = &LD_CP_R_MEMRQ[0]; - cur_irqs_ofst = &LD_CP_R_IRQS; - } - else if (instr_bank == 9) - { - cur_instr_ofst = &REP_OP_I_INST[0]; - cur_instr_ofst[8] = Ztemp2_saver; - cur_bus_ofst = &REP_OP_I_BUSRQ[0]; - cur_mem_ofst = &REP_OP_I_MEMRQ[0]; - cur_irqs_ofst = &REP_OP_I_IRQS; - } - else if (instr_bank == 10) - { - cur_instr_ofst = &REP_OP_O_INST[0]; - cur_bus_ofst = &REP_OP_O_BUSRQ[0]; - cur_mem_ofst = &REP_OP_O_MEMRQ[0]; - cur_irqs_ofst = &REP_OP_O_IRQS; - } - else if (instr_bank == 11) - { - cur_instr_ofst = &NO_HALT_INST[0]; - cur_bus_ofst = &NO_HALT_BUSRQ[0]; - cur_mem_ofst = &NO_HALT_MEMRQ[0]; - cur_irqs_ofst = &NO_HALT_IRQS; - } - else if (instr_bank == 12) - { - cur_instr_ofst = &NMI_INST[0]; - cur_bus_ofst = &NMI_BUSRQ[0]; - cur_mem_ofst = &NMI_MEMRQ[0]; - cur_irqs_ofst = &NMI_IRQS; - } - else if (instr_bank == 13) - { - cur_instr_ofst = &IRQ0_INST[0]; - cur_bus_ofst = &IRQ0_BUSRQ[0]; - cur_mem_ofst = &IRQ0_MEMRQ[0]; - cur_irqs_ofst = &IRQ0_IRQS; - } - else if (instr_bank == 14) - { - cur_instr_ofst = &IRQ1_INST[0]; - cur_bus_ofst = &IRQ1_BUSRQ[0]; - cur_mem_ofst = &IRQ1_MEMRQ[0]; - cur_irqs_ofst = &IRQ1_IRQS; - } - else if (instr_bank == 15) - { - cur_instr_ofst = &IRQ2_INST[0]; - cur_bus_ofst = &IRQ2_BUSRQ[0]; - cur_mem_ofst = &IRQ2_MEMRQ[0]; - cur_irqs_ofst = &IRQ2_IRQS; - } - - if (cond_chk_fail) - { - cur_irqs_ofst = &False_IRQS[IRQS_cond_offset]; - } - 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++; diff --git a/libHawk/GBHawk/GBHawk/Memory.cpp b/libHawk/GBHawk/GBHawk/Memory.cpp index bec2e266d1..3d1e499956 100644 --- a/libHawk/GBHawk/GBHawk/Memory.cpp +++ b/libHawk/GBHawk/GBHawk/Memory.cpp @@ -6,7 +6,7 @@ #include "Memory.h" #include "LR35902.h" #include "TMS9918A.h" -#include "AY_3_8910.h" +#include "GBAudio.h" using namespace std; @@ -14,216 +14,12 @@ namespace GBHawk { uint8_t MemoryManager::HardwareRead(uint32_t port) { - port &= 0xFF; - if (port == 0x98) // VDP - { - return vdp_pntr->ReadData(); - } - else if (port == 0x99) // VDP - { - return vdp_pntr->ReadVdpStatus(); - } - else if (port == 0xA2) - { - if (psg_pntr->port_sel == 0xE) { lagged = false; } - return psg_pntr->ReadReg(); - } - else if (port == 0xA8) - { - return PortA8; - } - else if (port == 0xA9) - { - lagged = false; - return ~kb_rows[kb_rows_sel]; - } - else if (port == 0xAA) - { - // TODO: casette, caps lamp, keyboard sound click - return kb_rows_sel; - } - return 0xFF; } void MemoryManager::HardwareWrite(uint32_t port, uint8_t value) { - port &= 0xFF; - if (port == 0x98) // VDP - { - vdp_pntr->WriteVdpData(value); - } - else if(port == 0x99) // VDP - { - vdp_pntr->WriteVdpControl(value); - } - else if (port == 0xA0) - { - psg_pntr->port_sel = (value & 0xF); - } - else if (port == 0xA1) - { - psg_pntr->WriteReg(value); - - // update controller port data if port F is written to - if (psg_pntr->port_sel == 0xF) - { - if ((psg_pntr->Register[0xF] & 0x40) > 0) - { - psg_pntr->Register[0xE] = controller_byte_2; - } - else - { - psg_pntr->Register[0xE] = controller_byte_1; - } - } - } - else if (port == 0xA8) - { - PortA8 = value; - remap(); - } - else if (port == 0xAA) - { - kb_rows_sel = value & 0xF; - remap(); - } - } - - void MemoryManager::remap() - { - if ((PortA8 & 3) == 0) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i] = &bios_rom[(0x400 * i)]; - cpu_pntr->MemoryMapMask[i] = 0; - } - } - else if ((PortA8 & 3) == 1) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i] = &rom_1[(0x400 * i)]; - cpu_pntr->MemoryMapMask[i] = 0; - } - } - else if ((PortA8 & 3) == 2) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i] = &rom_2[(0x400 * i)]; - cpu_pntr->MemoryMapMask[i] = 0; - } - } - else if ((PortA8 & 3) == 3) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i] = &ram[(0x400 * i)]; - cpu_pntr->MemoryMapMask[i] = 0xFF; - } - } - - if (((PortA8 >> 2) & 3) == 0) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 16] = &basic_rom[(0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 16] = 0; - } - } - else if (((PortA8 >> 2) & 3) == 1) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 16] = &rom_1[0x4000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 16] = 0; - } - } - else if (((PortA8 >> 2) & 3) == 2) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 16] = &rom_2[0x4000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 16] = 0; - } - } - else if (((PortA8 >> 2) & 3) == 3) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 16] = &ram[0x4000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 16] = 0xFF; - } - } - - if (((PortA8 >> 4) & 3) == 0) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 32] = &unmapped[0]; - cpu_pntr->MemoryMapMask[i + 32] = 0; - } - } - else if (((PortA8 >> 4) & 3) == 1) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 32] = &rom_1[0x8000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 32] = 0; - } - } - else if (((PortA8 >> 4) & 3) == 2) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 32] = &rom_2[0x8000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 32] = 0; - } - } - else if (((PortA8 >> 4) & 3) == 3) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 32] = &ram[0x8000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 32] = 0xFF; - } - } - - if (((PortA8 >> 6) & 3) == 0) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 48] = &unmapped[0]; - cpu_pntr->MemoryMapMask[i + 48] = 0; - } - } - else if (((PortA8 >> 6) & 3) == 1) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 48] = &rom_1[0xC000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 48] = 0; - } - } - else if (((PortA8 >> 6) & 3) == 2) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 48] = &rom_2[0xC000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 48] = 0; - } - } - else if (((PortA8 >> 6) & 3) == 3) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 48] = &ram[0xC000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 48] = 0xFF; - } - } } } \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/Memory.h b/libHawk/GBHawk/GBHawk/Memory.h index 23021c9938..f58035703a 100644 --- a/libHawk/GBHawk/GBHawk/Memory.h +++ b/libHawk/GBHawk/GBHawk/Memory.h @@ -7,17 +7,17 @@ using namespace std; namespace GBHawk { - class Z80A; + class LR35902; class TMS9918A; - class AY_3_8910; + class GBAudio; class MemoryManager { public: TMS9918A* vdp_pntr = nullptr; - AY_3_8910* psg_pntr = nullptr; - Z80A* cpu_pntr = nullptr; + GBAudio* psg_pntr = nullptr; + LR35902* cpu_pntr = nullptr; uint8_t* rom_1 = nullptr; uint8_t* rom_2 = nullptr; uint8_t* bios_rom = nullptr; @@ -54,8 +54,6 @@ namespace GBHawk void HardwareWrite(uint32_t addr, uint8_t value); - void remap(); - // NOTE: only called from source when both are available and of correct size (0x4000) void Load_BIOS(uint8_t* bios, uint8_t* basic) { @@ -82,8 +80,6 @@ namespace GBHawk // default memory map setup PortA8 = 0; - - remap(); } void MemoryWrite(uint32_t addr, uint8_t value) @@ -128,8 +124,6 @@ namespace GBHawk std::memcpy(&ram, loader, 0x10000); loader += 0x10000; std::memcpy(&cart_ram, loader, 0x8000); loader += 0x8000; - remap(); - return loader; }