diff --git a/.gitignore b/.gitignore index 155da55558..2b540361b5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ /snes9xgit svnrev.cs - +.vs/** **/bin/** **/obj/** /output/** diff --git a/Assets/NES/Palettes/FCEUX.pal b/Assets/NES/Palettes/FCEUX (2.2.0).pal similarity index 66% rename from Assets/NES/Palettes/FCEUX.pal rename to Assets/NES/Palettes/FCEUX (2.2.0).pal index 2b8ea5d63e..7bf9128fb5 100644 Binary files a/Assets/NES/Palettes/FCEUX.pal and b/Assets/NES/Palettes/FCEUX (2.2.0).pal differ diff --git a/Assets/defctrl.json b/Assets/defctrl.json index 65c84b7fdb..e213cfae5f 100644 --- a/Assets/defctrl.json +++ b/Assets/defctrl.json @@ -743,6 +743,34 @@ "P2 B1": "", "P2 B2": "" }, + "SMS Paddle Controller": { + "P1 Left": "LeftArrow, J1 POV1L", + "P1 Right": "RightArrow, J1 POV1R", + "P1 B1": "Z, J1 B1, X1 X", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start" + }, + "SMS Light Phaser Controller": { + "P1 Trigger": "Z, J1 B1, X1 X, WMouse L", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start" + }, + "SMS Sports Pad Controller": { + "P1 Up": "UpArrow, J1 POV1U", + "P1 Down": "DownArrow, J1 POV1D", + "P1 Left": "LeftArrow, J1 POV1L", + "P1 Right": "RightArrow, J1 POV1R", + "P1 B1": "Z, J1 B1, X1 X", + "P1 B2": "X, J1 B2, X1 A", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 B1": "", + "P2 B2": "" + }, "GG Controller": { "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", @@ -1567,6 +1595,47 @@ "Mult": 1.0, "Deadzone": 0.1 } + }, + "SMS Paddle Controller": { + "P1 Paddle": { + "Value": "X1 LeftThumbX", + "Mult": 1.0, + "Deadzone": 0.1 + } + }, + "SMS Light Phaser Controller": { + "P1 X": { + "Value": "WMouse X", + "Mult": 1.0, + "Deadzone": 0.0 + }, + "P1 Y": { + "Value": "WMouse Y", + "Mult": 1.0, + "Deadzone": 0.0 + } + }, + "SMS Sports Pad Controller": { + "P1 X": { + "Value": "X1 LeftThumbX", + "Mult": 1.0, + "Deadzone": 0.1 + }, + "P1 Y": { + "Value": "X1 LeftThumbY", + "Mult": -1.0, + "Deadzone": 0.1 + }, + "P2 X": { + "Value": "X2 LeftThumbX", + "Mult": 1.0, + "Deadzone": 0.1 + }, + "P2 Y": { + "Value": "X2 LeftThumbY", + "Mult": -1.0, + "Deadzone": 0.1 + } } } } \ No newline at end of file diff --git a/Assets/gamedb/gamedb_nes.txt b/Assets/gamedb/gamedb_nes.txt index 3f453f100d..d53e90e7f9 100644 --- a/Assets/gamedb/gamedb_nes.txt +++ b/Assets/gamedb/gamedb_nes.txt @@ -298,6 +298,8 @@ sha1:CEFEBA536DB507DBDEF8A538F9C332D7A75BF613 You Ling Xing Dong (Ch) NES boar sha1:DBFCC70CC2DEC7A889429ED542267F0F1BD967BF Ying Xiong Chuan Qi (Ch) NES board=MAPPER224 sha1:FFB4706E49B826C6CDD12E502E8AE94FC9810B7F Monty no Doki Doki Daisassou (FDS Conversion) (Unl) [U][!] NES board=UNIF_UNL-LH32;WRAM=8;VRAM=8;PAD_H=1 sha1:17473C223453D2D80FCB9DCFA317947287DC5C52 Xing He Zhan Shi (China) (Unl) NES board=WAIXINGMAPPER176 +sha1:B1C74236FD17FAB4AB9AA6AB28E38864C66D6255 Pocahontus (UNL) NES board=MAPPER182;PRG=256;CHR=256;WRAM=8;PAD_H=1 +sha1:5FA23F88432006DCF6874EA36E9E7DA8934427BE Super Donkey Kong (Unl) NES board=MAPPER182;PRG=128;CHR=128;WRAM=8;PAD_H=1 ;wrong vram info sha1:32D71DD6C5A8D78A918FE1B9D6D6C4A570D9652D Oeka Kids Anpanman no Hiragana Daisuki (J) NES board=MAPPER096;VRAM=32 diff --git a/Assets/gamedb/gamedb_sega_gg.txt b/Assets/gamedb/gamedb_sega_gg.txt index 82224fb10d..a8a1d105bb 100644 --- a/Assets/gamedb/gamedb_sega_gg.txt +++ b/Assets/gamedb/gamedb_sega_gg.txt @@ -231,7 +231,7 @@ B19256C6716147A9744F5BD528F14450 Magic Knight Rayearth 2 - Making of Magic Knig 846D48D0F4024C8094117599D0E1EEF1 Magic Knight Rayearth (J) GG SRAM=8192 Japan E496FF2196C372F4D6111538950D25CA Magical Puzzle Popils (W) (En,Ja) GG Puzzle SRAM=8192 World 3AF0C6DDF5F00A493E1F159FCEDC0933 Magical Taruruuto-kun (J) GG Japan -B0C35BC53AB7C184D34E5624F69AAD24 The Majors Pro Baseball (U) GG Sports;Baseball SRAM=128;GGLink USA +B0C35BC53AB7C184D34E5624F69AAD24 The Majors Pro Baseball (U) GG Sports;Baseball SRAM=128;GGLink;EEPROM USA A15C5219F766D516D1B8D9A09B9A2BB4 Mappy (J) GG Japan B83F36FD113A8F75F1A29652ACB641FC Marble Madness (UE) GG Arcade USA;Europe BA846684A66E90372C3C234955EE28BC Marko's Magic Football (E) (En,Fr,De,Es) GG Europe @@ -461,9 +461,9 @@ A23E89266DDAD3C856E7401D04A49C6C Woody Pop (W) (Rev 1) GG World 13F72ACFEA47587F9AA9F655BF98653C World Class Leader Board Golf (UE) GG Sports;Golf USA;Europe D95D381C6AFFB8345EE5457655E393D1 World Cup USA 94 (UE) (En,Fr,De,Es,It,Nl,Pt,Sv) GG Sports;Soccer USA;Europe D8939B64458FAF174CDC1241F777CB59 World Derby (J) GG GGLink Japan -E7EABBFC7A1F1339C4720249AEA92A32 World Series Baseball '95 (U) GG Sports;Baseball SRAM=128;GGLink USA -59359FC38865CFF00C90D6EB148DDC2F World Series Baseball (U) GG Sports;Baseball SRAM=128;GGLink USA -05CAC33029F0CAAC27774504C1AA8597 World Series Baseball (U) (Rev 1) GG Sports;Baseball SRAM=128;GGLink USA +E7EABBFC7A1F1339C4720249AEA92A32 World Series Baseball '95 (U) GG Sports;Baseball SRAM=128;GGLink;EEPROM USA +59359FC38865CFF00C90D6EB148DDC2F World Series Baseball (U) GG Sports;Baseball SRAM=128;GGLink;EEPROM USA +05CAC33029F0CAAC27774504C1AA8597 World Series Baseball (U) (Rev 1) GG Sports;Baseball SRAM=128;GGLink;EEPROM USA D810E851AD60ED5BA50B6246C2CE12F2 WWF Raw (UE) GG Sports;Wrestling USA;Europe 571AC03B80E3075C699CD583BF8651FD X-Men - Gamemaster's Legacy (UE) GG Marvel USA;Europe CA15F2BA2507EBD836C42D9D10231EB1 X-Men - Mojo World (UE) GG Marvel USA;Europe diff --git a/Assets/gamedb/gamedb_sega_sms.txt b/Assets/gamedb/gamedb_sega_sms.txt index 1f16380c3b..b3a7102c79 100644 --- a/Assets/gamedb/gamedb_sega_sms.txt +++ b/Assets/gamedb/gamedb_sega_sms.txt @@ -106,7 +106,7 @@ F2535DF9BDC3A84221303FA62D61AD6E Back to the Future Part II (E) SMS Europe 3D24A52E98E6C85D7C059386451CE749 Back to the Future Part III (E) SMS PAL Europe 8A94DED3D95AA46DAE8800B92E66D3EE Baku Baku (B) SMS Brazil 7A5D3B9963E316CB7F73BBDC2A7311C6 Bank Panic (E) SMS Europe -26DF4404950CB8DA47235833C0C101C6 Bart vs. the Space Mutants (E) SMS Europe +26DF4404950CB8DA47235833C0C101C6 Bart vs. the Space Mutants (E) SMS PAL Europe CBA2EC2940619956359801618E7AAB17 Bart vs. the World (E) SMS Europe 0069B1BD9C5B6B88ACE6324D7E61539F Basketball Nightmare (E) SMS Sports;Basketball Europe 215876A62D3CA48D28E98CD8A2C70A15 Batman Returns (E) SMS Europe diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs index 6de9d9cdc3..d20e74a845 100644 --- a/BizHawk.Client.Common/RomLoader.cs +++ b/BizHawk.Client.Common/RomLoader.cs @@ -470,7 +470,7 @@ namespace BizHawk.Client.Common System = "PSX" }; } - else if (ext == ".iso" || ext == ".cue" || ext == ".ccd") + else if (ext == ".iso" || ext == ".cue" || ext == ".ccd" || ext == ".mds") { if (file.IsArchive) { @@ -494,7 +494,7 @@ namespace BizHawk.Client.Common throw new InvalidOperationException("\r\n" + discMountJob.OUT_Log); } - var disc = discMountJob.OUT_Disc; + var disc = discMountJob.OUT_Disc; // ----------- // TODO - use more sophisticated IDer @@ -514,7 +514,9 @@ namespace BizHawk.Client.Common // try to use our wizard methods game = new GameInfo { Name = Path.GetFileNameWithoutExtension(file.Name), Hash = discHash }; - switch (new DiscIdentifier(disc).DetectDiscType()) + var dt = new DiscIdentifier(disc).DetectDiscType(); + + switch (dt) { case DiscType.SegaSaturn: game.System = "SAT"; @@ -532,9 +534,23 @@ namespace BizHawk.Client.Common case DiscType.PCFX: game.System = "PCFX"; break; + case DiscType.TurboCD: + game.System = "PCECD"; + break; + + case DiscType.Amiga: + case DiscType.CDi: + case DiscType.Dreamcast: + case DiscType.GameCube: + case DiscType.NeoGeoCD: + case DiscType.Panasonic3DO: + case DiscType.Playdia: + case DiscType.Wii: + // no supported emulator core for these (yet) + game.System = dt.ToString(); + throw new NoAvailableCoreException(dt.ToString()); case DiscType.AudioDisc: - case DiscType.TurboCD: case DiscType.UnknownCDFS: case DiscType.UnknownFormat: if (PreferredPlatformIsDefined(ext)) @@ -543,7 +559,7 @@ namespace BizHawk.Client.Common } else { - game.System = "PCECD"; + game.System = "NULL"; // "PCECD"; } break; @@ -552,6 +568,9 @@ namespace BizHawk.Client.Common switch (game.System) { + case "NULL": + nextEmulator = null; + break; case "GEN": var genesis = new GPGX(nextComm, null, new[] { disc }, GetCoreSettings(), GetCoreSyncSettings()); nextEmulator = genesis; @@ -1029,7 +1048,14 @@ namespace BizHawk.Client.Common DoMessageCallback("Failed to load a GB rom in SGB mode. Disabling SGB Mode."); return LoadRom(path, nextComm, false, recursiveCount + 1); } - else + + // handle exceptions thrown by the new detected systems that bizhawk does not have cores for + else if (ex is NoAvailableCoreException) + { + DoLoadErrorCallback(ex.Message + "\n\n" + ex, system); + } + + else { DoLoadErrorCallback("A core accepted the rom, but threw an exception while loading it:\n\n" + ex, system); } diff --git a/BizHawk.Client.Common/lua/EmuLuaLibrary.Events.cs b/BizHawk.Client.Common/lua/EmuLuaLibrary.Events.cs index 135939054a..b9e5695128 100644 --- a/BizHawk.Client.Common/lua/EmuLuaLibrary.Events.cs +++ b/BizHawk.Client.Common/lua/EmuLuaLibrary.Events.cs @@ -22,6 +22,9 @@ namespace BizHawk.Client.Common [RequiredService] private IEmulator Emulator { get; set; } + [OptionalService] + private IMemoryDomains Domains { get; set; } + private readonly LuaFunctionList _luaFunctions = new LuaFunctionList(); public EventLuaLibrary(Lua lua) @@ -210,7 +213,7 @@ namespace BizHawk.Client.Common } [LuaMethod("onmemoryexecute", "Fires after the given address is executed by the core")] - public string OnMemoryExecute(LuaFunction luaf, uint address, string name = null) + public string OnMemoryExecute(LuaFunction luaf, uint address, string name = null, string domain = null) { try { @@ -225,8 +228,16 @@ namespace BizHawk.Client.Common var nlf = new NamedLuaFunction(luaf, "OnMemoryExecute", LogOutputCallback, CurrentThread, name); _luaFunctions.Add(nlf); + if (string.IsNullOrWhiteSpace(domain)) + { + if (Domains != null && Domains.HasSystemBus) + { + domain = Domains.SystemBus.Name; + } + } + DebuggableCore.MemoryCallbacks.Add( - new MemoryCallback(MemoryCallbackType.Execute, "Lua Hook", nlf.Callback, address, null)); + new MemoryCallback(domain, MemoryCallbackType.Execute, "Lua Hook", nlf.Callback, address, null)); return nlf.Guid.ToString(); } } @@ -241,7 +252,7 @@ namespace BizHawk.Client.Common } [LuaMethod("onmemoryread", "Fires after the given address is read by the core. If no address is given, it will attach to every memory read")] - public string OnMemoryRead(LuaFunction luaf, uint? address = null, string name = null) + public string OnMemoryRead(LuaFunction luaf, uint? address = null, string name = null, string domain = null) { try { @@ -255,8 +266,16 @@ namespace BizHawk.Client.Common var nlf = new NamedLuaFunction(luaf, "OnMemoryRead", LogOutputCallback, CurrentThread, name); _luaFunctions.Add(nlf); + if (string.IsNullOrWhiteSpace(domain)) + { + if (Domains != null && Domains.HasSystemBus) + { + domain = Domains.SystemBus.Name; + } + } + DebuggableCore.MemoryCallbacks.Add( - new MemoryCallback(MemoryCallbackType.Read, "Lua Hook", nlf.Callback, address, null)); + new MemoryCallback(domain, MemoryCallbackType.Read, "Lua Hook", nlf.Callback, address, null)); return nlf.Guid.ToString(); } } @@ -271,7 +290,7 @@ namespace BizHawk.Client.Common } [LuaMethod("onmemorywrite", "Fires after the given address is written by the core. If no address is given, it will attach to every memory write")] - public string OnMemoryWrite(LuaFunction luaf, uint? address = null, string name = null) + public string OnMemoryWrite(LuaFunction luaf, uint? address = null, string name = null, string domain = null) { try { @@ -285,8 +304,16 @@ namespace BizHawk.Client.Common var nlf = new NamedLuaFunction(luaf, "OnMemoryWrite", LogOutputCallback, CurrentThread, name); _luaFunctions.Add(nlf); + if (string.IsNullOrWhiteSpace(domain)) + { + if (Domains != null && Domains.HasSystemBus) + { + domain = Domains.SystemBus.Name; + } + } + DebuggableCore.MemoryCallbacks.Add( - new MemoryCallback(MemoryCallbackType.Write, "Lua Hook", nlf.Callback, address, null)); + new MemoryCallback(domain, MemoryCallbackType.Write, "Lua Hook", nlf.Callback, address, null)); return nlf.Guid.ToString(); } } diff --git a/BizHawk.Client.Common/lua/EmuLuaLibrary.Memory.cs b/BizHawk.Client.Common/lua/EmuLuaLibrary.Memory.cs index 1b9670dafc..69a04d4028 100644 --- a/BizHawk.Client.Common/lua/EmuLuaLibrary.Memory.cs +++ b/BizHawk.Client.Common/lua/EmuLuaLibrary.Memory.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using NLua; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; +using BizHawk.Common.BufferExtensions; namespace BizHawk.Client.Common { @@ -108,6 +109,37 @@ namespace BizHawk.Client.Common return false; } + [LuaMethod("hash_region", "Returns a hash as a string of a region of memory, starting from addr, through count bytes. If the domain is unspecified, it uses the current region.")] + public string HashRegion(int addr, int count, string domain = null) + { + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + + // checks + if (addr < 0 || addr >= d.Size) + { + string error = $"Address {addr} is outside the bounds of domain {d.Name}"; + Log(error); + throw new ArgumentOutOfRangeException(error); + } + if (addr + count > d.Size) + { + string error = $"Address {addr} + count {count} is outside the bounds of domain {d.Name}"; + Log(error); + throw new ArgumentOutOfRangeException(error); + } + + byte[] data = new byte[count]; + for (int i = 0; i < count; i++) + { + data[i] = d.PeekByte(addr + i); + } + + using (var hasher = System.Security.Cryptography.SHA256.Create()) + { + return hasher.ComputeHash(data).BytesToHexString(); + } + } + #endregion #region Common Special and Legacy Methods diff --git a/BizHawk.Client.Common/movie/MovieSession.cs b/BizHawk.Client.Common/movie/MovieSession.cs index a8b82e741a..1a4a5940e7 100644 --- a/BizHawk.Client.Common/movie/MovieSession.cs +++ b/BizHawk.Client.Common/movie/MovieSession.cs @@ -318,7 +318,7 @@ namespace BizHawk.Client.Common if (Movie is TasMovie) { (Movie as TasMovie).GreenzoneCurrentFrame(); - if (Movie.IsPlaying && Global.Emulator.Frame > Movie.InputLogLength) + if (Movie.IsPlaying && Global.Emulator.Frame >= Movie.InputLogLength) { HandleFrameLoopForRecordMode(); } diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs index ed41d86b61..4b5c27aa04 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs @@ -514,14 +514,14 @@ namespace BizHawk.Client.Common Log?.Dispose(); Log = branch.InputLog.Clone(); - ////_changes = true; + + _lagLog.FromLagLog(branch.LagLog); // if there are branch states, they will be loaded anyway // but if there's none, or only *after* divergent point, don't invalidate the entire movie anymore if (divergentPoint.HasValue) { _stateManager.Invalidate(divergentPoint.Value); - _lagLog.FromLagLog(branch.LagLog); // don't truncate LagLog if the branch's one is shorter, but input is the same } else { @@ -530,8 +530,7 @@ namespace BizHawk.Client.Common _stateManager.LoadBranch(Branches.IndexOf(branch)); _stateManager.SetState(branch.Frame, branch.CoreData); - - ////ChangeLog = branch.ChangeLog; + if (BindMarkersToInput) // pretty critical not to erase them { Markers = branch.Markers; diff --git a/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs b/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs index b4fe3b0138..af3006e4e4 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs @@ -44,14 +44,16 @@ namespace BizHawk.Client.Common private readonly TasMovie _movie; private ulong _expectedStateSize; - private readonly int _minFrequency = VersionInfo.DeveloperBuild ? 2 : 1; + private readonly int _minFrequency = 1; private const int MaxFrequency = 16; + private int MaxStates => (int)(Settings.Cap / _expectedStateSize) + (int)((ulong)Settings.DiskCapacitymb * 1024 * 1024 / _expectedStateSize); + private int FileStateGap => 1 << Settings.FileStateGap; private int StateFrequency { get { - int freq = (int)(_expectedStateSize / 65536); + int freq = (int)_expectedStateSize / Settings.MemStateGapDivider / 1024; if (freq < _minFrequency) { @@ -66,11 +68,7 @@ namespace BizHawk.Client.Common return freq; } } - - private int MaxStates => (int)(Settings.Cap / _expectedStateSize) + (int)((ulong)Settings.DiskCapacitymb * 1024 * 1024 / _expectedStateSize); - - private int StateGap => 1 << Settings.StateGap; - + public TasStateManager(TasMovie movie) { _movie = movie; @@ -585,7 +583,7 @@ namespace BizHawk.Client.Common for (int i = 1; i < _states.Count; i++) { if (_movie.Markers.IsMarker(_states.ElementAt(i).Key + 1) - || _states.ElementAt(i).Key % StateGap == 0) + || _states.ElementAt(i).Key % FileStateGap == 0) { continue; } diff --git a/BizHawk.Client.Common/movie/tasproj/TasStateManagerSettings.cs b/BizHawk.Client.Common/movie/tasproj/TasStateManagerSettings.cs index e834d62666..24aff44e13 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasStateManagerSettings.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasStateManagerSettings.cs @@ -11,8 +11,9 @@ namespace BizHawk.Client.Common { DiskSaveCapacitymb = 512; Capacitymb = 512; - DiskCapacitymb = 512; - StateGap = 4; + DiskCapacitymb = 1; // not working yet + MemStateGapDivider = 64; + FileStateGap = 4; BranchStatesInTasproj = false; EraseBranchStatesFirst = true; } @@ -22,7 +23,8 @@ namespace BizHawk.Client.Common DiskSaveCapacitymb = settings.DiskSaveCapacitymb; Capacitymb = settings.Capacitymb; DiskCapacitymb = settings.DiskCapacitymb; - StateGap = settings.StateGap; + MemStateGapDivider = settings.MemStateGapDivider; + FileStateGap = settings.FileStateGap; BranchStatesInTasproj = settings.BranchStatesInTasproj; EraseBranchStatesFirst = settings.EraseBranchStatesFirst; } @@ -55,12 +57,19 @@ namespace BizHawk.Client.Common [Description("The size limit of the state history buffer on the disk. When this limit is reached it will start removing previous savestates")] public int DiskCapacitymb { get; set; } + /// + /// Gets or sets the divider that determines memory state gap + /// + [DisplayName("Divider for memory state interval")] + [Description("The actual state gap in frames is calculated as ExpectedStateSize / div / 1024")] + public int MemStateGapDivider { get; set; } + /// /// Gets or sets the amount of states to skip during project saving /// [DisplayName("State interval for .tasproj")] [Description("The actual state gap in frames is calculated as Nth power on 2")] - public int StateGap { get; set; } + public int FileStateGap { get; set; } /// /// Gets or sets a value indicating whether or not to save branch states into the movie file @@ -99,7 +108,8 @@ namespace BizHawk.Client.Common sb.AppendLine(DiskCapacitymb.ToString()); sb.AppendLine(BranchStatesInTasproj.ToString()); sb.AppendLine(EraseBranchStatesFirst.ToString()); - sb.AppendLine(StateGap.ToString()); + sb.AppendLine(FileStateGap.ToString()); + sb.AppendLine(MemStateGapDivider.ToString()); return sb.ToString(); } @@ -123,13 +133,13 @@ namespace BizHawk.Client.Common DiskSaveCapacitymb = refCapacity; } - DiskCapacitymb = lines.Length > 2 ? int.Parse(lines[2]) : 512; + int i = 2; - BranchStatesInTasproj = lines.Length > 3 && bool.Parse(lines[3]); - - EraseBranchStatesFirst = lines.Length <= 4 || bool.Parse(lines[4]); - - StateGap = lines.Length > 5 ? int.Parse(lines[5]) : 4; + DiskCapacitymb = lines.Length > i ? int.Parse(lines[i++]) : 1; + BranchStatesInTasproj = lines.Length > i && bool.Parse(lines[i++]); + EraseBranchStatesFirst = lines.Length <= i || bool.Parse(lines[i++]); + FileStateGap = lines.Length > i ? int.Parse(lines[i++]) : 4; + FileStateGap = lines.Length > i ? int.Parse(lines[i++]) : 64; } catch (Exception) // TODO: this is bad { diff --git a/BizHawk.Client.Common/tools/Cheat.cs b/BizHawk.Client.Common/tools/Cheat.cs index 15ec5fb62a..4680168276 100644 --- a/BizHawk.Client.Common/tools/Cheat.cs +++ b/BizHawk.Client.Common/tools/Cheat.cs @@ -284,29 +284,61 @@ namespace BizHawk.Client.Common case WatchSize.Byte: return (byte?)_val; case WatchSize.Word: - if (addr == _watch.Address) + if (_watch.BigEndian) { + if (addr == _watch.Address) + { + return (byte)(_val & 0xFF); + } return (byte)(_val >> 8); } - - return (byte)(_val & 0xFF); - case WatchSize.DWord: - if (addr == _watch.Address) + else { + if (addr == _watch.Address) + { + return (byte)(_val >> 8); + } + return (byte)(_val & 0xFF); + } + case WatchSize.DWord: + if (_watch.BigEndian) + { + if (addr == _watch.Address) + { + return (byte)((_val >> 24) & 0xFF); + } + + if (addr == _watch.Address + 1) + { + return (byte)((_val >> 16) & 0xFF); + } + + if (addr == _watch.Address + 2) + { + return (byte)((_val >> 8) & 0xFF); + } + + return (byte)(_val & 0xFF); + } + else + { + if (addr == _watch.Address) + { + return (byte)(_val & 0xFF); + } + + if (addr == _watch.Address + 1) + { + return (byte)((_val >> 8) & 0xFF); + } + + if (addr == _watch.Address + 2) + { + return (byte)((_val >> 16) & 0xFF); + } + return (byte)((_val >> 24) & 0xFF); } - - if (addr == _watch.Address + 1) - { - return (byte)((_val >> 16) & 0xFF); - } - - if (addr == _watch.Address + 2) - { - return (byte)((_val >> 8) & 0xFF); - } - - return (byte)(_val & 0xFF); } } diff --git a/BizHawk.Client.DiscoHawk/MainDiscoForm.cs b/BizHawk.Client.DiscoHawk/MainDiscoForm.cs index f74b095c74..cdd2c1a0f7 100644 --- a/BizHawk.Client.DiscoHawk/MainDiscoForm.cs +++ b/BizHawk.Client.DiscoHawk/MainDiscoForm.cs @@ -111,7 +111,7 @@ namespace BizHawk.Client.DiscoHawk foreach (string str in files) { string ext = Path.GetExtension(str).ToUpper(); - if(!ext.In(new string[]{".CUE",".ISO",".CCD"})) + if(!ext.In(new string[]{".CUE",".ISO",".CCD", ".MDS"})) { return new List(); } diff --git a/BizHawk.Client.EmuHawk/ArgParser.cs b/BizHawk.Client.EmuHawk/ArgParser.cs index 939ca94b29..9e4c5ab1b9 100644 --- a/BizHawk.Client.EmuHawk/ArgParser.cs +++ b/BizHawk.Client.EmuHawk/ArgParser.cs @@ -112,7 +112,7 @@ namespace BizHawk.Client.EmuHawk } else { - cmdRom = arg; + cmdRom = args[i]; } } } diff --git a/BizHawk.Client.EmuHawk/BizBox.Designer.cs b/BizHawk.Client.EmuHawk/BizBox.Designer.cs index 2ba66f2637..630b994d1e 100644 --- a/BizHawk.Client.EmuHawk/BizBox.Designer.cs +++ b/BizHawk.Client.EmuHawk/BizBox.Designer.cs @@ -35,7 +35,6 @@ this.label3 = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); this.CoreInfoPanel = new System.Windows.Forms.Panel(); - //this.textBox1 = new System.Windows.Forms.TextBox(); this.VersionLabel = new System.Windows.Forms.Label(); this.btnCopyHash = new System.Windows.Forms.Button(); this.linkLabel2 = new System.Windows.Forms.LinkLabel(); @@ -146,7 +145,6 @@ // // linkLabel3 // - this.linkLabel3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.linkLabel3.AutoSize = true; this.linkLabel3.Location = new System.Drawing.Point(198, 112); this.linkLabel3.Name = "linkLabel3"; @@ -176,7 +174,6 @@ this.Controls.Add(this.linkLabel3); this.Controls.Add(this.linkLabel2); this.Controls.Add(this.btnCopyHash); - //this.Controls.Add(this.textBox1); this.Controls.Add(this.CoreInfoPanel); this.Controls.Add(this.VersionLabel); this.Controls.Add(this.label4); diff --git a/BizHawk.Client.EmuHawk/FileLoader.cs b/BizHawk.Client.EmuHawk/FileLoader.cs index 1e6d123c78..0009646fb4 100644 --- a/BizHawk.Client.EmuHawk/FileLoader.cs +++ b/BizHawk.Client.EmuHawk/FileLoader.cs @@ -51,11 +51,11 @@ namespace BizHawk.Client.EmuHawk return new[] { ".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF", - ".EXE", ".PRG", ".D64", "*G64", ".CRT", ".TAP", ".32X" + ".EXE", ".PRG", ".D64", "*G64", ".CRT", ".TAP", ".32X", ".MDS" }; } - return new[] { ".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF", ".32X" }; + return new[] { ".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF", ".32X", ".MDS" }; } } diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index aef505d11b..9d6774638e 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -442,7 +442,12 @@ this.ShowMenuContextMenuSeparator = new System.Windows.Forms.ToolStripSeparator(); this.ShowMenuContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.timerMouseIdle = new System.Windows.Forms.Timer(this.components); - this.MainformMenu.SuspendLayout(); + this.SMSControllerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SMSControllerStandardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SMSControllerPaddleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SMSControllerLightPhaserToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SMSControllerSportsPadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.MainformMenu.SuspendLayout(); this.MainStatusBar.SuspendLayout(); this.MainFormContextMenu.SuspendLayout(); this.SuspendLayout(); @@ -2475,7 +2480,8 @@ this.SMSSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.SMSregionToolStripMenuItem, this.SMSdisplayToolStripMenuItem, - this.SMStoolStripMenuItem2, + this.SMSControllerToolStripMenuItem, + this.SMStoolStripMenuItem2, this.SMSenableBIOSToolStripMenuItem, this.SMSEnableFMChipMenuItem, this.SMSOverclockMenuItem, @@ -2542,9 +2548,44 @@ this.SMSdisplayNtscToolStripMenuItem.Text = "NTSC"; this.SMSdisplayNtscToolStripMenuItem.Click += new System.EventHandler(this.SMS_DisplayNTSC_Click); // - // SMSdisplayPalToolStripMenuItem + // SMSControllerToolStripMenuItem // - this.SMSdisplayPalToolStripMenuItem.Name = "SMSdisplayPalToolStripMenuItem"; + this.SMSControllerToolStripMenuItem.Name = "SMSControllerToolStripMenuItem"; + this.SMSControllerToolStripMenuItem.Text = "&Controller Type"; + this.SMSControllerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.SMSControllerStandardToolStripMenuItem, + this.SMSControllerPaddleToolStripMenuItem, + this.SMSControllerLightPhaserToolStripMenuItem, + this.SMSControllerSportsPadToolStripMenuItem}); + // + // SMSControllerStandardToolStripMenuItem + // + this.SMSControllerStandardToolStripMenuItem.Name = "SMSControllerStandardToolStripMenuItem"; + this.SMSControllerStandardToolStripMenuItem.Text = "Standard"; + this.SMSControllerStandardToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerStandardToolStripMenuItem_Click); + // + // SMSControllerPaddleToolStripMenuItem + // + this.SMSControllerPaddleToolStripMenuItem.Name = "SMSControllerPaddleToolStripMenuItem"; + this.SMSControllerPaddleToolStripMenuItem.Text = "Paddle"; + this.SMSControllerPaddleToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerPaddleToolStripMenuItem_Click); + // + // SMSControllerLightPhaserToolStripMenuItem + // + this.SMSControllerLightPhaserToolStripMenuItem.Name = "SMSControllerLightPhaserToolStripMenuItem"; + this.SMSControllerLightPhaserToolStripMenuItem.Text = "Light Phaser"; + this.SMSControllerLightPhaserToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerLightPhaserToolStripMenuItem_Click); + // + // SMSControllerSportsPadToolStripMenuItem + // + this.SMSControllerSportsPadToolStripMenuItem.Name = "SMSControllerSportsPadToolStripMenuItem"; + this.SMSControllerSportsPadToolStripMenuItem.Text = "Sports Pad"; + this.SMSControllerSportsPadToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerSportsPadToolStripMenuItem_Click); + + // + // SMSdisplayPalToolStripMenuItem + // + this.SMSdisplayPalToolStripMenuItem.Name = "SMSdisplayPalToolStripMenuItem"; this.SMSdisplayPalToolStripMenuItem.Size = new System.Drawing.Size(104, 22); this.SMSdisplayPalToolStripMenuItem.Text = "PAL"; this.SMSdisplayPalToolStripMenuItem.Click += new System.EventHandler(this.SMS_DisplayPAL_Click); @@ -4368,5 +4409,10 @@ private System.Windows.Forms.ToolStripMenuItem SgbSameBoyMenuItem; private System.Windows.Forms.ToolStripMenuItem pCFXToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem preferencesToolStripMenuItem3; + private System.Windows.Forms.ToolStripMenuItem SMSControllerToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSControllerStandardToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSControllerPaddleToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSControllerLightPhaserToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSControllerSportsPadToolStripMenuItem; } } diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 9cd33d7a3d..fd1d42f241 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -1745,6 +1745,10 @@ namespace BizHawk.Client.EmuHawk SMSdisplayNtscToolStripMenuItem.Checked = ss.DisplayType == "NTSC"; SMSdisplayPalToolStripMenuItem.Checked = ss.DisplayType == "PAL"; SMSdisplayAutoToolStripMenuItem.Checked = ss.DisplayType == "Auto"; + SMSControllerStandardToolStripMenuItem.Checked = ss.ControllerType == "Standard"; + SMSControllerPaddleToolStripMenuItem.Checked = ss.ControllerType == "Paddle"; + SMSControllerLightPhaserToolStripMenuItem.Checked = ss.ControllerType == "Light Phaser"; + SMSControllerSportsPadToolStripMenuItem.Checked = ss.ControllerType == "Sports Pad"; SMSenableBIOSToolStripMenuItem.Checked = ss.UseBIOS; SMSEnableFMChipMenuItem.Checked = ss.EnableFM; SMSOverclockMenuItem.Checked = ss.AllowOverlock; @@ -1899,6 +1903,34 @@ namespace BizHawk.Client.EmuHawk GlobalWin.Tools.Load(); } + private void SMSControllerStandardToolStripMenuItem_Click(object sender, EventArgs e) + { + var s = ((SMS)Emulator).GetSyncSettings(); + s.ControllerType = "Standard"; + PutCoreSyncSettings(s); + } + + private void SMSControllerPaddleToolStripMenuItem_Click(object sender, EventArgs e) + { + var s = ((SMS)Emulator).GetSyncSettings(); + s.ControllerType = "Paddle"; + PutCoreSyncSettings(s); + } + + private void SMSControllerLightPhaserToolStripMenuItem_Click(object sender, EventArgs e) + { + var s = ((SMS)Emulator).GetSyncSettings(); + s.ControllerType = "Light Phaser"; + PutCoreSyncSettings(s); + } + + private void SMSControllerSportsPadToolStripMenuItem_Click(object sender, EventArgs e) + { + var s = ((SMS)Emulator).GetSyncSettings(); + s.ControllerType = "Sports Pad"; + PutCoreSyncSettings(s); + } + #endregion #region TI83 diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 930474edc4..170dbb2322 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -274,7 +274,8 @@ namespace BizHawk.Client.EmuHawk if (argParse.cmdRom != null) { // Commandline should always override auto-load - LoadRom(argParse.cmdRom, new LoadRomArgs { OpenAdvanced = new OpenAdvanced_OpenRom() }); + var ioa = OpenAdvancedSerializer.ParseWithLegacy(argParse.cmdRom); + LoadRom(argParse.cmdRom, new LoadRomArgs { OpenAdvanced = ioa }); if (Global.Game == null) { MessageBox.Show("Failed to load " + argParse.cmdRom + " specified on commandline"); @@ -2076,13 +2077,13 @@ namespace BizHawk.Client.EmuHawk if (VersionInfo.DeveloperBuild) { return FormatFilter( - "Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.32x;*.col;*.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.vb;*.ngp;*.ngc;*.psf;*.minipsf;*.nsf;%ARCH%", + "Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.mds;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.32x;*.col;*.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.vb;*.ngp;*.ngc;*.psf;*.minipsf;*.nsf;%ARCH%", "Music Files", "*.psf;*.minipsf;*.sid;*.nsf", - "Disc Images", "*.cue;*.ccd;*.m3u", + "Disc Images", "*.cue;*.ccd;*.mds;*.m3u", "NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%", "Super NES", "*.smc;*.sfc;*.xml;%ARCH%", "Master System", "*.sms;*.gg;*.sg;%ARCH%", - "PC Engine", "*.pce;*.sgx;*.cue;*.ccd;%ARCH%", + "PC Engine", "*.pce;*.sgx;*.cue;*.ccd;*.mds;%ARCH%", "TI-83", "*.rom;%ARCH%", "Archive Files", "%ARCH%", "Savestate", "*.state", @@ -2094,7 +2095,7 @@ namespace BizHawk.Client.EmuHawk "Gameboy Advance", "*.gba;%ARCH%", "Colecovision", "*.col;%ARCH%", "Intellivision", "*.int;*.bin;*.rom;%ARCH%", - "PlayStation", "*.cue;*.ccd;*.m3u", + "PlayStation", "*.cue;*.ccd;*.mds;*.m3u", "PSX Executables (experimental)", "*.exe", "PSF Playstation Sound File", "*.psf;*.minipsf", "Commodore 64", "*.prg; *.d64, *.g64; *.crt; *.tap;%ARCH%", @@ -2108,17 +2109,17 @@ namespace BizHawk.Client.EmuHawk } return FormatFilter( - "Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.gb;*.gbc;*.gba;*.pce;*.sgx;*.bin;*.smd;*.gen;*.md;*.32x;*.smc;*.sfc;*.a26;*.a78;*.lnx;*.col;*.int;*.rom;*.m3u;*.cue;*.ccd;*.sgb;*.z64;*.v64;*.n64;*.ws;*.wsc;*.xml;*.dsk;*.do;*.po;*.psf;*.ngp;*.ngc;*.prg;*.d64;*.g64;*.minipsf;*.nsf;%ARCH%", - "Disc Images", "*.cue;*.ccd;*.m3u", + "Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.gb;*.gbc;*.gba;*.pce;*.sgx;*.bin;*.smd;*.gen;*.md;*.32x;*.smc;*.sfc;*.a26;*.a78;*.lnx;*.col;*.int;*.rom;*.m3u;*.cue;*.ccd;*.mds;*.sgb;*.z64;*.v64;*.n64;*.ws;*.wsc;*.xml;*.dsk;*.do;*.po;*.psf;*.ngp;*.ngc;*.prg;*.d64;*.g64;*.minipsf;*.nsf;%ARCH%", + "Disc Images", "*.cue;*.ccd;*.mds;*.m3u", "NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%", "Super NES", "*.smc;*.sfc;*.xml;%ARCH%", - "PlayStation", "*.cue;*.ccd;*.m3u", + "PlayStation", "*.cue;*.ccd;*.mds;*.m3u", "PSF Playstation Sound File", "*.psf;*.minipsf", "Nintendo 64", "*.z64;*.v64;*.n64", "Gameboy", "*.gb;*.gbc;*.sgb;%ARCH%", "Gameboy Advance", "*.gba;%ARCH%", "Master System", "*.sms;*.gg;*.sg;%ARCH%", - "PC Engine", "*.pce;*.sgx;*.cue;*.ccd;%ARCH%", + "PC Engine", "*.pce;*.sgx;*.cue;*.ccd;*.mds;%ARCH%", "Atari 2600", "*.a26;%ARCH%", "Atari 7800", "*.a78;%ARCH%", "Atari Lynx", "*.lnx;%ARCH%", @@ -3582,6 +3583,12 @@ namespace BizHawk.Client.EmuHawk } } + if (ioa is OpenAdvanced_OpenRom) + { + var ioa_openrom = (OpenAdvanced_OpenRom)ioa; + path = ioa_openrom.Path; + } + CoreFileProvider.SyncCoreCommInputSignals(nextComm); var result = loader.LoadRom(path, nextComm); diff --git a/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.Designer.cs b/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.Designer.cs index 3eeacc6191..22e5372ca6 100644 --- a/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.Designer.cs @@ -28,220 +28,87 @@ /// private void InitializeComponent() { - this.OK = new System.Windows.Forms.Button(); - this.Cancel = new System.Windows.Forms.Button(); - this.trackBar1 = new System.Windows.Forms.TrackBar(); - this.trackBar2 = new System.Windows.Forms.TrackBar(); - this.trackBar3 = new System.Windows.Forms.TrackBar(); - this.trackBar4 = new System.Windows.Forms.TrackBar(); - this.trackBar5 = new System.Windows.Forms.TrackBar(); - this.label1 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.label3 = new System.Windows.Forms.Label(); - this.label4 = new System.Windows.Forms.Label(); - this.label5 = new System.Windows.Forms.Label(); - this.label6 = new System.Windows.Forms.Label(); - this.label7 = new System.Windows.Forms.Label(); - this.label8 = new System.Windows.Forms.Label(); - this.label9 = new System.Windows.Forms.Label(); - this.label10 = new System.Windows.Forms.Label(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar2)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar3)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar4)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar5)).BeginInit(); - this.SuspendLayout(); - // - // OK - // - this.OK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.OK.Location = new System.Drawing.Point(41, 262); - this.OK.Name = "OK"; - this.OK.Size = new System.Drawing.Size(75, 23); - this.OK.TabIndex = 0; - this.OK.Text = "&OK"; - this.OK.UseVisualStyleBackColor = true; - this.OK.Click += new System.EventHandler(this.Ok_Click); - // - // Cancel - // - this.Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.Cancel.Location = new System.Drawing.Point(122, 262); - this.Cancel.Name = "Cancel"; - this.Cancel.Size = new System.Drawing.Size(75, 23); - this.Cancel.TabIndex = 1; - this.Cancel.Text = "&Cancel"; - this.Cancel.UseVisualStyleBackColor = true; - this.Cancel.Click += new System.EventHandler(this.Cancel_Click); - // - // trackBar1 - // - this.trackBar1.Location = new System.Drawing.Point(12, 12); - this.trackBar1.Name = "trackBar1"; - this.trackBar1.Size = new System.Drawing.Size(104, 45); - this.trackBar1.TabIndex = 2; - this.trackBar1.ValueChanged += new System.EventHandler(this.TrackBar1_ValueChanged); - // - // trackBar2 - // - this.trackBar2.Location = new System.Drawing.Point(12, 60); - this.trackBar2.Name = "trackBar2"; - this.trackBar2.Size = new System.Drawing.Size(104, 45); - this.trackBar2.TabIndex = 3; - this.trackBar2.ValueChanged += new System.EventHandler(this.TrackBar2_ValueChanged); - // - // trackBar3 - // - this.trackBar3.Location = new System.Drawing.Point(12, 108); - this.trackBar3.Name = "trackBar3"; - this.trackBar3.Size = new System.Drawing.Size(104, 45); - this.trackBar3.TabIndex = 4; - this.trackBar3.ValueChanged += new System.EventHandler(this.TrackBar3_ValueChanged); - // - // trackBar4 - // - this.trackBar4.Location = new System.Drawing.Point(12, 156); - this.trackBar4.Name = "trackBar4"; - this.trackBar4.Size = new System.Drawing.Size(104, 45); - this.trackBar4.TabIndex = 5; - this.trackBar4.ValueChanged += new System.EventHandler(this.TrackBar4_ValueChanged); - // - // trackBar5 - // - this.trackBar5.Location = new System.Drawing.Point(12, 204); - this.trackBar5.Name = "trackBar5"; - this.trackBar5.Size = new System.Drawing.Size(104, 45); - this.trackBar5.TabIndex = 6; - this.trackBar5.ValueChanged += new System.EventHandler(this.TrackBar5_ValueChanged); - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(122, 12); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(50, 13); - this.label1.TabIndex = 7; - this.label1.Text = "Square 1"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(122, 60); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(50, 13); - this.label2.TabIndex = 8; - this.label2.Text = "Square 2"; - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(122, 108); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(45, 13); - this.label3.TabIndex = 9; - this.label3.Text = "Triangle"; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(122, 156); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(34, 13); - this.label4.TabIndex = 10; - this.label4.Text = "Noise"; - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(122, 204); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(31, 13); - this.label5.TabIndex = 11; - this.label5.Text = "DMC"; - // - // label6 - // - this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(122, 25); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(13, 13); - this.label6.TabIndex = 12; - this.label6.Text = "0"; - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(122, 73); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(13, 13); - this.label7.TabIndex = 13; - this.label7.Text = "0"; - // - // label8 - // - this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(122, 121); - this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(13, 13); - this.label8.TabIndex = 14; - this.label8.Text = "0"; - // - // label9 - // - this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(122, 169); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(13, 13); - this.label9.TabIndex = 15; - this.label9.Text = "0"; - // - // label10 - // - this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(122, 217); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(13, 13); - this.label10.TabIndex = 16; - this.label10.Text = "0"; - // - // NESSoundConfig - // - this.AcceptButton = this.OK; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.CancelButton = this.Cancel; - this.ClientSize = new System.Drawing.Size(209, 297); - this.Controls.Add(this.label10); - this.Controls.Add(this.label9); - this.Controls.Add(this.label8); - this.Controls.Add(this.label7); - this.Controls.Add(this.label6); - this.Controls.Add(this.label5); - this.Controls.Add(this.label4); - this.Controls.Add(this.label3); - this.Controls.Add(this.label2); - this.Controls.Add(this.label1); - this.Controls.Add(this.trackBar5); - this.Controls.Add(this.trackBar4); - this.Controls.Add(this.trackBar3); - this.Controls.Add(this.trackBar2); - this.Controls.Add(this.trackBar1); - this.Controls.Add(this.Cancel); - this.Controls.Add(this.OK); - this.MaximizeBox = false; - this.Name = "NESSoundConfig"; - this.ShowIcon = false; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "NES Sound Channels"; - this.Load += new System.EventHandler(this.NESSoundConfig_Load); - ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar2)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar3)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar4)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar5)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); + this.OK = new System.Windows.Forms.Button(); + this.Cancel = new System.Windows.Forms.Button(); + this.trackBar1 = new System.Windows.Forms.TrackBar(); + this.label1 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit(); + this.SuspendLayout(); + // + // OK + // + this.OK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OK.Location = new System.Drawing.Point(41, 117); + this.OK.Name = "OK"; + this.OK.Size = new System.Drawing.Size(75, 23); + this.OK.TabIndex = 0; + this.OK.Text = "&OK"; + this.OK.UseVisualStyleBackColor = true; + this.OK.Click += new System.EventHandler(this.Ok_Click); + // + // Cancel + // + this.Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.Cancel.Location = new System.Drawing.Point(122, 117); + this.Cancel.Name = "Cancel"; + this.Cancel.Size = new System.Drawing.Size(75, 23); + this.Cancel.TabIndex = 1; + this.Cancel.Text = "&Cancel"; + this.Cancel.UseVisualStyleBackColor = true; + this.Cancel.Click += new System.EventHandler(this.Cancel_Click); + // + // trackBar1 + // + this.trackBar1.LargeChange = 1; + this.trackBar1.Location = new System.Drawing.Point(12, 12); + this.trackBar1.Minimum = 1; + this.trackBar1.Name = "trackBar1"; + this.trackBar1.Size = new System.Drawing.Size(104, 45); + this.trackBar1.TabIndex = 2; + this.trackBar1.Value = 1; + this.trackBar1.ValueChanged += new System.EventHandler(this.TrackBar1_ValueChanged); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(122, 12); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(67, 13); + this.label1.TabIndex = 7; + this.label1.Text = "APU Volume"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(122, 25); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(13, 13); + this.label6.TabIndex = 12; + this.label6.Text = "0"; + // + // NESSoundConfig + // + this.AcceptButton = this.OK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.Cancel; + this.ClientSize = new System.Drawing.Size(209, 152); + this.Controls.Add(this.label6); + this.Controls.Add(this.label1); + this.Controls.Add(this.trackBar1); + this.Controls.Add(this.Cancel); + this.Controls.Add(this.OK); + this.MaximizeBox = false; + this.Name = "NESSoundConfig"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "NES Sound Channels"; + this.Load += new System.EventHandler(this.NESSoundConfig_Load); + ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); } @@ -250,19 +117,7 @@ private System.Windows.Forms.Button OK; private System.Windows.Forms.Button Cancel; private System.Windows.Forms.TrackBar trackBar1; - private System.Windows.Forms.TrackBar trackBar2; - private System.Windows.Forms.TrackBar trackBar3; - private System.Windows.Forms.TrackBar trackBar4; - private System.Windows.Forms.TrackBar trackBar5; private System.Windows.Forms.Label label1; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.Label label5; private System.Windows.Forms.Label label6; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.Label label8; - private System.Windows.Forms.Label label9; - private System.Windows.Forms.Label label10; } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.cs b/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.cs index 725f4ba2c4..ac3a8f198f 100644 --- a/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.cs +++ b/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.cs @@ -38,11 +38,7 @@ namespace BizHawk.Client.EmuHawk // get baseline maxes from a default config object var d = new NES.NESSettings(); - trackBar1.Maximum = d.Square1; - trackBar2.Maximum = d.Square2; - trackBar3.Maximum = d.Triangle; - trackBar4.Maximum = d.Noise; - trackBar5.Maximum = d.DMC; + trackBar1.Minimum = d.APU_vol; } private void NESSoundConfig_Load(object sender, EventArgs e) @@ -50,11 +46,7 @@ namespace BizHawk.Client.EmuHawk _oldSettings = NES.GetSettings(); _settings = _oldSettings.Clone(); - trackBar1.Value = _settings.Square1; - trackBar2.Value = _settings.Square2; - trackBar3.Value = _settings.Triangle; - trackBar4.Value = _settings.Noise; - trackBar5.Value = _settings.DMC; + trackBar1.Value = _settings.APU_vol; } private void Ok_Click(object sender, EventArgs e) @@ -72,35 +64,7 @@ namespace BizHawk.Client.EmuHawk private void TrackBar1_ValueChanged(object sender, EventArgs e) { label6.Text = trackBar1.Value.ToString(); - _settings.Square1 = trackBar1.Value; - NES.PutSettings(_settings); - } - - private void TrackBar2_ValueChanged(object sender, EventArgs e) - { - label7.Text = trackBar2.Value.ToString(); - _settings.Square2 = trackBar2.Value; - NES.PutSettings(_settings); - } - - private void TrackBar3_ValueChanged(object sender, EventArgs e) - { - label8.Text = trackBar3.Value.ToString(); - _settings.Triangle = trackBar3.Value; - NES.PutSettings(_settings); - } - - private void TrackBar4_ValueChanged(object sender, EventArgs e) - { - label9.Text = trackBar4.Value.ToString(); - _settings.Noise = trackBar4.Value; - NES.PutSettings(_settings); - } - - private void TrackBar5_ValueChanged(object sender, EventArgs e) - { - label10.Text = trackBar5.Value.ToString(); - _settings.DMC = trackBar5.Value; + _settings.APU_vol = trackBar1.Value; NES.PutSettings(_settings); } } diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/Breakpoint.cs b/BizHawk.Client.EmuHawk/tools/Debugger/Breakpoint.cs index cd0fd84795..3f4aca4106 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/Breakpoint.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/Breakpoint.cs @@ -9,9 +9,9 @@ namespace BizHawk.Client.EmuHawk { public Action Callback { get; set; } - public void Add(IDebuggable core, uint address, uint mask, MemoryCallbackType type) + public void Add(IDebuggable core, string scope, uint address, uint mask, MemoryCallbackType type) { - Add(new Breakpoint(core, Callback, address, mask, type)); + Add(new Breakpoint(core, scope, Callback, address, mask, type)); } public new void Clear() @@ -69,8 +69,9 @@ namespace BizHawk.Client.EmuHawk private bool _active; private readonly IDebuggable _core; - public Breakpoint(bool readOnly, IDebuggable core, Action callBack, uint address, uint mask, MemoryCallbackType type, bool enabled = true) + public Breakpoint(bool readOnly, IDebuggable core, string scope, Action callBack, uint address, uint mask, MemoryCallbackType type, bool enabled = true) { + Scope = scope; _core = core; Type = type; Callback = callBack; @@ -82,8 +83,9 @@ namespace BizHawk.Client.EmuHawk ReadOnly = readOnly; } - public Breakpoint(IDebuggable core, Action callBack, uint address, uint mask, MemoryCallbackType type, bool enabled = true) + public Breakpoint(IDebuggable core, string scope, Action callBack, uint address, uint mask, MemoryCallbackType type, bool enabled = true) { + Scope = scope; _core = core; Type = type; Callback = callBack; @@ -94,8 +96,9 @@ namespace BizHawk.Client.EmuHawk Active = enabled; } - public Breakpoint(string name, bool readOnly, IDebuggable core, Action callBack, uint address, uint mask, MemoryCallbackType type, bool enabled = true) + public Breakpoint(string name, bool readOnly, IDebuggable core, string scope, Action callBack, uint address, uint mask, MemoryCallbackType type, bool enabled = true) { + Scope = scope; _core = core; Type = type; Callback = callBack; @@ -107,6 +110,7 @@ namespace BizHawk.Client.EmuHawk ReadOnly = readOnly; } + public string Scope { get; } public Action Callback { get; } public uint? Address { get; set; } public uint? AddressMask { get; set; } @@ -159,7 +163,7 @@ namespace BizHawk.Client.EmuHawk private void AddCallback() { - _core.MemoryCallbacks.Add(new MemoryCallback(Type, Name, Callback, Address, AddressMask)); + _core.MemoryCallbacks.Add(new MemoryCallback(Scope, Type, Name, Callback, Address, AddressMask)); } private void RemoveCallback() diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs index 0142a6e579..17428ebc77 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs @@ -144,7 +144,7 @@ namespace BizHawk.Client.EmuHawk public void AddBreakpoint(uint address, uint mask, MemoryCallbackType type) { - _breakpoints.Add(Core, address, mask, type); + _breakpoints.Add(Core, MemoryDomains.SystemBus.Name, address, mask, type); BreakpointView.ItemCount = _breakpoints.Count; UpdateBreakpointRemoveButton(); @@ -157,7 +157,7 @@ namespace BizHawk.Client.EmuHawk if (b.ShowHawkDialog() == DialogResult.OK) { - _breakpoints.Add(Core, b.Address, b.AddressMask, b.BreakType); + _breakpoints.Add(Core, MemoryDomains.SystemBus.Name, b.Address, b.AddressMask, b.BreakType); } BreakpointView.ItemCount = _breakpoints.Count; @@ -170,7 +170,7 @@ namespace BizHawk.Client.EmuHawk public void AddSeekBreakpoint(uint pcVal, int pcBitSize) { var name = SeekName + pcVal.ToHexString(pcBitSize / 4); - _breakpoints.Add(new Breakpoint(name, true, Core, SeekCallback, pcVal, 0xFFFFFFFF, MemoryCallbackType.Execute)); + _breakpoints.Add(new Breakpoint(name, true, Core, MemoryDomains.SystemBus.Name, SeekCallback, pcVal, 0xFFFFFFFF, MemoryCallbackType.Execute)); } public void RemoveCurrentSeek() @@ -284,7 +284,7 @@ namespace BizHawk.Client.EmuHawk if (b.ShowHawkDialog() == DialogResult.OK) { - _breakpoints.Add(new Breakpoint(Core, breakpoint.Callback, b.Address, b.AddressMask, b.BreakType, breakpoint.Active)); + _breakpoints.Add(new Breakpoint(Core, MemoryDomains.SystemBus.Name, breakpoint.Callback, b.Address, b.AddressMask, b.BreakType, breakpoint.Active)); } } diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.IToolForm.cs b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.IToolForm.cs index c43ea2c392..ff1d792881 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.IToolForm.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.IToolForm.cs @@ -15,7 +15,7 @@ namespace BizHawk.Client.EmuHawk [OptionalService] private IDisassemblable Disassembler { get; set; } - [OptionalService] + [RequiredService] private IMemoryDomains MemoryDomains { get; set; } private IMemoryCallbackSystem MemoryCallbacks { get { return Debuggable.MemoryCallbacks; } } diff --git a/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.Designer.cs b/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.Designer.cs index dfe62e01f1..72856225d8 100644 --- a/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.Designer.cs @@ -92,6 +92,7 @@ this.AddressLabel = new System.Windows.Forms.Label(); this.AddressesLabel = new System.Windows.Forms.Label(); this.Header = new System.Windows.Forms.Label(); + this.swapBytesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.HexMenuStrip.SuspendLayout(); this.ViewerContextMenuStrip.SuspendLayout(); this.MemoryViewerBox.SuspendLayout(); @@ -126,7 +127,7 @@ this.toolStripSeparator1, this.ExitMenuItem}); this.FileSubMenu.Name = "FileSubMenu"; - this.FileSubMenu.Size = new System.Drawing.Size(35, 20); + this.FileSubMenu.Size = new System.Drawing.Size(37, 20); this.FileSubMenu.Text = "&File"; this.FileSubMenu.DropDownOpened += new System.EventHandler(this.FileSubMenu_DropDownOpened); // @@ -135,7 +136,7 @@ this.SaveMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.SaveAs; this.SaveMenuItem.Name = "SaveMenuItem"; this.SaveMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); - this.SaveMenuItem.Size = new System.Drawing.Size(225, 22); + this.SaveMenuItem.Size = new System.Drawing.Size(229, 22); this.SaveMenuItem.Text = "Save"; this.SaveMenuItem.Click += new System.EventHandler(this.SaveMenuItem_Click); // @@ -144,14 +145,14 @@ this.SaveAsBinaryMenuItem.Name = "SaveAsBinaryMenuItem"; this.SaveAsBinaryMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) | System.Windows.Forms.Keys.S))); - this.SaveAsBinaryMenuItem.Size = new System.Drawing.Size(225, 22); + this.SaveAsBinaryMenuItem.Size = new System.Drawing.Size(229, 22); this.SaveAsBinaryMenuItem.Text = "Save as binary..."; this.SaveAsBinaryMenuItem.Click += new System.EventHandler(this.SaveAsBinaryMenuItem_Click); // // SaveAsTextMenuItem // this.SaveAsTextMenuItem.Name = "SaveAsTextMenuItem"; - this.SaveAsTextMenuItem.Size = new System.Drawing.Size(225, 22); + this.SaveAsTextMenuItem.Size = new System.Drawing.Size(229, 22); this.SaveAsTextMenuItem.Text = "Save as text..."; this.SaveAsTextMenuItem.Click += new System.EventHandler(this.SaveAsTextMenuItem_Click); // @@ -159,26 +160,26 @@ // this.importAsBinaryToolStripMenuItem.Name = "importAsBinaryToolStripMenuItem"; this.importAsBinaryToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.I))); - this.importAsBinaryToolStripMenuItem.Size = new System.Drawing.Size(225, 22); + this.importAsBinaryToolStripMenuItem.Size = new System.Drawing.Size(229, 22); this.importAsBinaryToolStripMenuItem.Text = "Import as binary..."; this.importAsBinaryToolStripMenuItem.Click += new System.EventHandler(this.importAsBinaryToolStripMenuItem_Click); // // toolStripSeparator4 // this.toolStripSeparator4.Name = "toolStripSeparator4"; - this.toolStripSeparator4.Size = new System.Drawing.Size(222, 6); + this.toolStripSeparator4.Size = new System.Drawing.Size(226, 6); // // LoadTableFileMenuItem // this.LoadTableFileMenuItem.Name = "LoadTableFileMenuItem"; - this.LoadTableFileMenuItem.Size = new System.Drawing.Size(225, 22); + this.LoadTableFileMenuItem.Size = new System.Drawing.Size(229, 22); this.LoadTableFileMenuItem.Text = "&Load .tbl file"; this.LoadTableFileMenuItem.Click += new System.EventHandler(this.LoadTableFileMenuItem_Click); // // CloseTableFileMenuItem // this.CloseTableFileMenuItem.Name = "CloseTableFileMenuItem"; - this.CloseTableFileMenuItem.Size = new System.Drawing.Size(225, 22); + this.CloseTableFileMenuItem.Size = new System.Drawing.Size(229, 22); this.CloseTableFileMenuItem.Text = "Close .tbl file"; this.CloseTableFileMenuItem.Click += new System.EventHandler(this.CloseTableFileMenuItem_Click); // @@ -187,26 +188,26 @@ this.RecentTablesSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.noneToolStripMenuItem}); this.RecentTablesSubMenu.Name = "RecentTablesSubMenu"; - this.RecentTablesSubMenu.Size = new System.Drawing.Size(225, 22); + this.RecentTablesSubMenu.Size = new System.Drawing.Size(229, 22); this.RecentTablesSubMenu.Text = "Recent"; this.RecentTablesSubMenu.DropDownOpened += new System.EventHandler(this.RecentTablesSubMenu_DropDownOpened); // // noneToolStripMenuItem // this.noneToolStripMenuItem.Name = "noneToolStripMenuItem"; - this.noneToolStripMenuItem.Size = new System.Drawing.Size(99, 22); + this.noneToolStripMenuItem.Size = new System.Drawing.Size(103, 22); this.noneToolStripMenuItem.Text = "None"; // // toolStripSeparator1 // this.toolStripSeparator1.Name = "toolStripSeparator1"; - this.toolStripSeparator1.Size = new System.Drawing.Size(222, 6); + this.toolStripSeparator1.Size = new System.Drawing.Size(226, 6); // // ExitMenuItem // this.ExitMenuItem.Name = "ExitMenuItem"; this.ExitMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F4))); - this.ExitMenuItem.Size = new System.Drawing.Size(225, 22); + this.ExitMenuItem.Size = new System.Drawing.Size(229, 22); this.ExitMenuItem.Text = "E&xit"; this.ExitMenuItem.Click += new System.EventHandler(this.ExitMenuItem_Click); // @@ -221,7 +222,7 @@ this.FindNextMenuItem, this.FindPrevMenuItem}); this.EditMenuItem.Name = "EditMenuItem"; - this.EditMenuItem.Size = new System.Drawing.Size(37, 20); + this.EditMenuItem.Size = new System.Drawing.Size(39, 20); this.EditMenuItem.Text = "&Edit"; this.EditMenuItem.DropDownOpened += new System.EventHandler(this.EditMenuItem_DropDownOpened); // @@ -230,7 +231,7 @@ this.CopyMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Duplicate; this.CopyMenuItem.Name = "CopyMenuItem"; this.CopyMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C))); - this.CopyMenuItem.Size = new System.Drawing.Size(144, 22); + this.CopyMenuItem.Size = new System.Drawing.Size(147, 22); this.CopyMenuItem.Text = "&Copy"; this.CopyMenuItem.Click += new System.EventHandler(this.CopyMenuItem_Click); // @@ -238,7 +239,7 @@ // this.ExportMenuItem.Name = "ExportMenuItem"; this.ExportMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.E))); - this.ExportMenuItem.Size = new System.Drawing.Size(144, 22); + this.ExportMenuItem.Size = new System.Drawing.Size(147, 22); this.ExportMenuItem.Text = "&Export"; this.ExportMenuItem.Click += new System.EventHandler(this.ExportMenuItem_Click); // @@ -247,20 +248,20 @@ this.PasteMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Paste; this.PasteMenuItem.Name = "PasteMenuItem"; this.PasteMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.V))); - this.PasteMenuItem.Size = new System.Drawing.Size(144, 22); + this.PasteMenuItem.Size = new System.Drawing.Size(147, 22); this.PasteMenuItem.Text = "&Paste"; this.PasteMenuItem.Click += new System.EventHandler(this.PasteMenuItem_Click); // // toolStripSeparator6 // this.toolStripSeparator6.Name = "toolStripSeparator6"; - this.toolStripSeparator6.Size = new System.Drawing.Size(141, 6); + this.toolStripSeparator6.Size = new System.Drawing.Size(144, 6); // // FindMenuItem // this.FindMenuItem.Name = "FindMenuItem"; this.FindMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F))); - this.FindMenuItem.Size = new System.Drawing.Size(144, 22); + this.FindMenuItem.Size = new System.Drawing.Size(147, 22); this.FindMenuItem.Text = "&Find..."; this.FindMenuItem.Click += new System.EventHandler(this.FindMenuItem_Click); // @@ -268,7 +269,7 @@ // this.FindNextMenuItem.Name = "FindNextMenuItem"; this.FindNextMenuItem.ShortcutKeys = System.Windows.Forms.Keys.F3; - this.FindNextMenuItem.Size = new System.Drawing.Size(144, 22); + this.FindNextMenuItem.Size = new System.Drawing.Size(147, 22); this.FindNextMenuItem.Text = "Find Next"; this.FindNextMenuItem.Click += new System.EventHandler(this.FindNextMenuItem_Click); // @@ -276,7 +277,7 @@ // this.FindPrevMenuItem.Name = "FindPrevMenuItem"; this.FindPrevMenuItem.ShortcutKeys = System.Windows.Forms.Keys.F2; - this.FindPrevMenuItem.Size = new System.Drawing.Size(144, 22); + this.FindPrevMenuItem.Size = new System.Drawing.Size(147, 22); this.FindPrevMenuItem.Text = "Find Prev"; this.FindPrevMenuItem.Click += new System.EventHandler(this.FindPrevMenuItem_Click); // @@ -285,6 +286,7 @@ this.OptionsSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.MemoryDomainsMenuItem, this.DataSizeSubMenu, + this.swapBytesToolStripMenuItem, this.BigEndianMenuItem, this.toolStripSeparator2, this.GoToAddressMenuItem, @@ -293,7 +295,7 @@ this.UnfreezeAllMenuItem, this.PokeAddressMenuItem}); this.OptionsSubMenu.Name = "OptionsSubMenu"; - this.OptionsSubMenu.Size = new System.Drawing.Size(56, 20); + this.OptionsSubMenu.Size = new System.Drawing.Size(61, 20); this.OptionsSubMenu.Text = "&Options"; this.OptionsSubMenu.DropDownOpened += new System.EventHandler(this.OptionsSubMenu_DropDownOpened); // @@ -302,7 +304,7 @@ this.MemoryDomainsMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripSeparator3}); this.MemoryDomainsMenuItem.Name = "MemoryDomainsMenuItem"; - this.MemoryDomainsMenuItem.Size = new System.Drawing.Size(207, 22); + this.MemoryDomainsMenuItem.Size = new System.Drawing.Size(221, 22); this.MemoryDomainsMenuItem.Text = "&Memory Domains"; this.MemoryDomainsMenuItem.DropDownOpened += new System.EventHandler(this.MemoryDomainsMenuItem_DropDownOpened); // @@ -318,47 +320,47 @@ this.DataSizeWordMenuItem, this.DataSizeDWordMenuItem}); this.DataSizeSubMenu.Name = "DataSizeSubMenu"; - this.DataSizeSubMenu.Size = new System.Drawing.Size(207, 22); + this.DataSizeSubMenu.Size = new System.Drawing.Size(221, 22); this.DataSizeSubMenu.Text = "Data Size"; // // DataSizeByteMenuItem // this.DataSizeByteMenuItem.Name = "DataSizeByteMenuItem"; - this.DataSizeByteMenuItem.Size = new System.Drawing.Size(105, 22); + this.DataSizeByteMenuItem.Size = new System.Drawing.Size(106, 22); this.DataSizeByteMenuItem.Text = "1 Byte"; this.DataSizeByteMenuItem.Click += new System.EventHandler(this.DataSizeByteMenuItem_Click); // // DataSizeWordMenuItem // this.DataSizeWordMenuItem.Name = "DataSizeWordMenuItem"; - this.DataSizeWordMenuItem.Size = new System.Drawing.Size(105, 22); + this.DataSizeWordMenuItem.Size = new System.Drawing.Size(106, 22); this.DataSizeWordMenuItem.Text = "2 Byte"; this.DataSizeWordMenuItem.Click += new System.EventHandler(this.DataSizeWordMenuItem_Click); // // DataSizeDWordMenuItem // this.DataSizeDWordMenuItem.Name = "DataSizeDWordMenuItem"; - this.DataSizeDWordMenuItem.Size = new System.Drawing.Size(105, 22); + this.DataSizeDWordMenuItem.Size = new System.Drawing.Size(106, 22); this.DataSizeDWordMenuItem.Text = "4 Byte"; this.DataSizeDWordMenuItem.Click += new System.EventHandler(this.DataSizeDWordMenuItem_Click); // // BigEndianMenuItem // this.BigEndianMenuItem.Name = "BigEndianMenuItem"; - this.BigEndianMenuItem.Size = new System.Drawing.Size(207, 22); + this.BigEndianMenuItem.Size = new System.Drawing.Size(221, 22); this.BigEndianMenuItem.Text = "Big Endian"; this.BigEndianMenuItem.Click += new System.EventHandler(this.BigEndianMenuItem_Click); // // toolStripSeparator2 // this.toolStripSeparator2.Name = "toolStripSeparator2"; - this.toolStripSeparator2.Size = new System.Drawing.Size(204, 6); + this.toolStripSeparator2.Size = new System.Drawing.Size(218, 6); // // GoToAddressMenuItem // this.GoToAddressMenuItem.Name = "GoToAddressMenuItem"; this.GoToAddressMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.G))); - this.GoToAddressMenuItem.Size = new System.Drawing.Size(207, 22); + this.GoToAddressMenuItem.Size = new System.Drawing.Size(221, 22); this.GoToAddressMenuItem.Text = "&Go to Address..."; this.GoToAddressMenuItem.Click += new System.EventHandler(this.GoToAddressMenuItem_Click); // @@ -367,7 +369,7 @@ this.AddToRamWatchMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.FindHS; this.AddToRamWatchMenuItem.Name = "AddToRamWatchMenuItem"; this.AddToRamWatchMenuItem.ShortcutKeyDisplayString = "Ctrl+W"; - this.AddToRamWatchMenuItem.Size = new System.Drawing.Size(207, 22); + this.AddToRamWatchMenuItem.Size = new System.Drawing.Size(221, 22); this.AddToRamWatchMenuItem.Text = "Add to RAM Watch"; this.AddToRamWatchMenuItem.Click += new System.EventHandler(this.AddToRamWatchMenuItem_Click); // @@ -376,7 +378,7 @@ this.FreezeAddressMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Freeze; this.FreezeAddressMenuItem.Name = "FreezeAddressMenuItem"; this.FreezeAddressMenuItem.ShortcutKeyDisplayString = "Space"; - this.FreezeAddressMenuItem.Size = new System.Drawing.Size(207, 22); + this.FreezeAddressMenuItem.Size = new System.Drawing.Size(221, 22); this.FreezeAddressMenuItem.Text = "&Freeze Address"; this.FreezeAddressMenuItem.Click += new System.EventHandler(this.FreezeAddressMenuItem_Click); // @@ -385,7 +387,7 @@ this.UnfreezeAllMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Unfreeze; this.UnfreezeAllMenuItem.Name = "UnfreezeAllMenuItem"; this.UnfreezeAllMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Shift | System.Windows.Forms.Keys.Delete))); - this.UnfreezeAllMenuItem.Size = new System.Drawing.Size(207, 22); + this.UnfreezeAllMenuItem.Size = new System.Drawing.Size(221, 22); this.UnfreezeAllMenuItem.Text = "Unfreeze All"; this.UnfreezeAllMenuItem.Click += new System.EventHandler(this.UnfreezeAllMenuItem_Click); // @@ -394,7 +396,7 @@ this.PokeAddressMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.poke; this.PokeAddressMenuItem.Name = "PokeAddressMenuItem"; this.PokeAddressMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.P))); - this.PokeAddressMenuItem.Size = new System.Drawing.Size(207, 22); + this.PokeAddressMenuItem.Size = new System.Drawing.Size(221, 22); this.PokeAddressMenuItem.Text = "&Poke Address"; this.PokeAddressMenuItem.Click += new System.EventHandler(this.PokeAddressMenuItem_Click); // @@ -403,7 +405,7 @@ this.SettingsSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.CustomColorsSubMenu}); this.SettingsSubMenu.Name = "SettingsSubMenu"; - this.SettingsSubMenu.Size = new System.Drawing.Size(58, 20); + this.SettingsSubMenu.Size = new System.Drawing.Size(61, 20); this.SettingsSubMenu.Text = "&Settings"; // // CustomColorsSubMenu @@ -413,25 +415,25 @@ this.toolStripSeparator8, this.ResetColorsToDefaultMenuItem}); this.CustomColorsSubMenu.Name = "CustomColorsSubMenu"; - this.CustomColorsSubMenu.Size = new System.Drawing.Size(143, 22); + this.CustomColorsSubMenu.Size = new System.Drawing.Size(153, 22); this.CustomColorsSubMenu.Text = "Custom Colors"; // // SetColorsMenuItem // this.SetColorsMenuItem.Name = "SetColorsMenuItem"; - this.SetColorsMenuItem.Size = new System.Drawing.Size(153, 22); + this.SetColorsMenuItem.Size = new System.Drawing.Size(157, 22); this.SetColorsMenuItem.Text = "Set Colors"; this.SetColorsMenuItem.Click += new System.EventHandler(this.SetColorsMenuItem_Click); // // toolStripSeparator8 // this.toolStripSeparator8.Name = "toolStripSeparator8"; - this.toolStripSeparator8.Size = new System.Drawing.Size(150, 6); + this.toolStripSeparator8.Size = new System.Drawing.Size(154, 6); // // ResetColorsToDefaultMenuItem // this.ResetColorsToDefaultMenuItem.Name = "ResetColorsToDefaultMenuItem"; - this.ResetColorsToDefaultMenuItem.Size = new System.Drawing.Size(153, 22); + this.ResetColorsToDefaultMenuItem.Size = new System.Drawing.Size(157, 22); this.ResetColorsToDefaultMenuItem.Text = "Reset to Default"; this.ResetColorsToDefaultMenuItem.Click += new System.EventHandler(this.ResetColorsToDefaultMenuItem_Click); // @@ -464,7 +466,7 @@ this.toolStripMenuItem1, this.viewN64MatrixToolStripMenuItem}); this.ViewerContextMenuStrip.Name = "ViewerContextMenuStrip"; - this.ViewerContextMenuStrip.Size = new System.Drawing.Size(208, 264); + this.ViewerContextMenuStrip.Size = new System.Drawing.Size(222, 264); this.ViewerContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.ViewerContextMenuStrip_Opening); // // CopyContextItem @@ -472,7 +474,7 @@ this.CopyContextItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Duplicate; this.CopyContextItem.Name = "CopyContextItem"; this.CopyContextItem.ShortcutKeyDisplayString = "Ctrl+C"; - this.CopyContextItem.Size = new System.Drawing.Size(207, 22); + this.CopyContextItem.Size = new System.Drawing.Size(221, 22); this.CopyContextItem.Text = "&Copy"; this.CopyContextItem.Click += new System.EventHandler(this.CopyMenuItem_Click); // @@ -480,7 +482,7 @@ // this.ExportContextItem.Name = "ExportContextItem"; this.ExportContextItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.E))); - this.ExportContextItem.Size = new System.Drawing.Size(207, 22); + this.ExportContextItem.Size = new System.Drawing.Size(221, 22); this.ExportContextItem.Text = "&Export"; // // PasteContextItem @@ -488,7 +490,7 @@ this.PasteContextItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Paste; this.PasteContextItem.Name = "PasteContextItem"; this.PasteContextItem.ShortcutKeyDisplayString = "Ctrl+V"; - this.PasteContextItem.Size = new System.Drawing.Size(207, 22); + this.PasteContextItem.Size = new System.Drawing.Size(221, 22); this.PasteContextItem.Text = "&Paste"; this.PasteContextItem.Click += new System.EventHandler(this.PasteMenuItem_Click); // @@ -497,7 +499,7 @@ this.FreezeContextItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Freeze; this.FreezeContextItem.Name = "FreezeContextItem"; this.FreezeContextItem.ShortcutKeyDisplayString = "Space"; - this.FreezeContextItem.Size = new System.Drawing.Size(207, 22); + this.FreezeContextItem.Size = new System.Drawing.Size(221, 22); this.FreezeContextItem.Text = "&Freeze"; this.FreezeContextItem.Click += new System.EventHandler(this.FreezeAddressMenuItem_Click); // @@ -506,7 +508,7 @@ this.AddToRamWatchContextItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.FindHS; this.AddToRamWatchContextItem.Name = "AddToRamWatchContextItem"; this.AddToRamWatchContextItem.ShortcutKeyDisplayString = "Ctrl+W"; - this.AddToRamWatchContextItem.Size = new System.Drawing.Size(207, 22); + this.AddToRamWatchContextItem.Size = new System.Drawing.Size(221, 22); this.AddToRamWatchContextItem.Text = "&Add to RAM Watch"; this.AddToRamWatchContextItem.Click += new System.EventHandler(this.AddToRamWatchMenuItem_Click); // @@ -515,7 +517,7 @@ this.UnfreezeAllContextItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Unfreeze; this.UnfreezeAllContextItem.Name = "UnfreezeAllContextItem"; this.UnfreezeAllContextItem.ShortcutKeyDisplayString = "Shift+Del"; - this.UnfreezeAllContextItem.Size = new System.Drawing.Size(207, 22); + this.UnfreezeAllContextItem.Size = new System.Drawing.Size(221, 22); this.UnfreezeAllContextItem.Text = "&Unfreeze All"; this.UnfreezeAllContextItem.Click += new System.EventHandler(this.UnfreezeAllMenuItem_Click); // @@ -524,20 +526,20 @@ this.PokeContextItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.poke; this.PokeContextItem.Name = "PokeContextItem"; this.PokeContextItem.ShortcutKeyDisplayString = "Ctrl+P"; - this.PokeContextItem.Size = new System.Drawing.Size(207, 22); + this.PokeContextItem.Size = new System.Drawing.Size(221, 22); this.PokeContextItem.Text = "&Poke Address"; this.PokeContextItem.Click += new System.EventHandler(this.PokeAddressMenuItem_Click); // // ContextSeparator1 // this.ContextSeparator1.Name = "ContextSeparator1"; - this.ContextSeparator1.Size = new System.Drawing.Size(204, 6); + this.ContextSeparator1.Size = new System.Drawing.Size(218, 6); // // IncrementContextItem // this.IncrementContextItem.Name = "IncrementContextItem"; this.IncrementContextItem.ShortcutKeyDisplayString = "+"; - this.IncrementContextItem.Size = new System.Drawing.Size(207, 22); + this.IncrementContextItem.Size = new System.Drawing.Size(221, 22); this.IncrementContextItem.Text = "&Increment"; this.IncrementContextItem.Click += new System.EventHandler(this.IncrementContextItem_Click); // @@ -545,32 +547,32 @@ // this.DecrementContextItem.Name = "DecrementContextItem"; this.DecrementContextItem.ShortcutKeyDisplayString = "-"; - this.DecrementContextItem.Size = new System.Drawing.Size(207, 22); + this.DecrementContextItem.Size = new System.Drawing.Size(221, 22); this.DecrementContextItem.Text = "&Decrement"; this.DecrementContextItem.Click += new System.EventHandler(this.DecrementContextItem_Click); // // ContextSeparator2 // this.ContextSeparator2.Name = "ContextSeparator2"; - this.ContextSeparator2.Size = new System.Drawing.Size(204, 6); + this.ContextSeparator2.Size = new System.Drawing.Size(218, 6); // // GoToContextItem // this.GoToContextItem.Name = "GoToContextItem"; this.GoToContextItem.ShortcutKeyDisplayString = "Ctrl+G"; - this.GoToContextItem.Size = new System.Drawing.Size(207, 22); + this.GoToContextItem.Size = new System.Drawing.Size(221, 22); this.GoToContextItem.Text = "&Go to Address..."; this.GoToContextItem.Click += new System.EventHandler(this.GoToAddressMenuItem_Click); // // toolStripMenuItem1 // this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - this.toolStripMenuItem1.Size = new System.Drawing.Size(204, 6); + this.toolStripMenuItem1.Size = new System.Drawing.Size(218, 6); // // viewN64MatrixToolStripMenuItem // this.viewN64MatrixToolStripMenuItem.Name = "viewN64MatrixToolStripMenuItem"; - this.viewN64MatrixToolStripMenuItem.Size = new System.Drawing.Size(207, 22); + this.viewN64MatrixToolStripMenuItem.Size = new System.Drawing.Size(221, 22); this.viewN64MatrixToolStripMenuItem.Text = "View N64 Matrix"; this.viewN64MatrixToolStripMenuItem.Click += new System.EventHandler(this.viewN64MatrixToolStripMenuItem_Click); // @@ -638,6 +640,14 @@ this.Header.TabIndex = 2; this.Header.Text = "label1"; // + // swapBytesToolStripMenuItem + // + this.swapBytesToolStripMenuItem.CheckOnClick = true; + this.swapBytesToolStripMenuItem.Name = "swapBytesToolStripMenuItem"; + this.swapBytesToolStripMenuItem.Size = new System.Drawing.Size(221, 22); + this.swapBytesToolStripMenuItem.Text = "Swap Bytes"; + this.swapBytesToolStripMenuItem.Click += new System.EventHandler(this.SwapBytesMenuItem_Click); + // // HexEditor // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -732,5 +742,6 @@ private System.Windows.Forms.ToolStripMenuItem ExportContextItem; private System.Windows.Forms.ToolStripMenuItem ExportMenuItem; private System.Windows.Forms.ToolStripMenuItem importAsBinaryToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem swapBytesToolStripMenuItem; } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.cs b/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.cs index 02752e22b6..a509b57639 100644 --- a/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.cs +++ b/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.cs @@ -79,6 +79,9 @@ namespace BizHawk.Client.EmuHawk private MemoryDomain _romDomain; private HexFind _hexFind = new HexFind(); + [ConfigPersist] + private bool SwapBytes { get; set; } + [ConfigPersist] private bool BigEndian { get; set; } @@ -179,7 +182,9 @@ namespace BizHawk.Client.EmuHawk _domain = MemoryDomains.MainMemory; } + SwapBytes = false; BigEndian = _domain.EndianType == MemoryDomain.Endian.Big; + _maxRow = _domain.Size / 2; // Don't reset scroll bar if restarting the same rom @@ -526,7 +531,24 @@ namespace BizHawk.Client.EmuHawk { if (_addr + j + DataSize <= _domain.Size) { - rowStr.AppendFormat(_digitFormatString, MakeValue(_addr + j)); + int t_val = 0; + int t_next = 0; + bool is_cht; + for (int k = 0; k < DataSize; k++) + { + t_next = MakeValue(1, _addr + j + k, out is_cht); + + if (SwapBytes) + { + t_val += (t_next << (k * 8)); + } + else + { + t_val += (t_next << ((DataSize - k - 1) * 8)); + } + } + + rowStr.AppendFormat(_digitFormatString, t_val); } else { @@ -565,28 +587,31 @@ namespace BizHawk.Client.EmuHawk : _domain.PeekByte(address); } - private int MakeValue(int dataSize, long address) + private int MakeValue(int dataSize, long address, out bool is_cheat) { if (Global.CheatList.IsActive(_domain, address)) { - return Global.CheatList.GetCheatValue(_domain, address, (WatchSize)DataSize ).Value; + is_cheat = true; + return Global.CheatList.GetCheatValue(_domain, address, (WatchSize)dataSize ).Value; } + is_cheat = false; switch (dataSize) { default: case 1: return _domain.PeekByte(address); case 2: - return _domain.PeekUshort(address, BigEndian); + return _domain.PeekUshort(address, SwapBytes); case 4: - return (int)_domain.PeekUint(address, BigEndian); + return (int)_domain.PeekUint(address, SwapBytes); } } private int MakeValue(long address) { - return MakeValue(DataSize, address); + bool temp; + return MakeValue(DataSize, address, out temp); } private void SetMemoryDomain(string name) @@ -600,6 +625,7 @@ namespace BizHawk.Client.EmuHawk _domain = MemoryDomains[name]; } + SwapBytes = false; BigEndian = _domain.EndianType == MemoryDomain.Endian.Big; _maxRow = _domain.Size / 2; SetUpScrollBar(); @@ -1444,8 +1470,9 @@ namespace BizHawk.Client.EmuHawk { long start = addresses[i]; long end = addresses[i] + DataSize -1 ; + bool temp; for(long a = start;a<=end;a++) - sb.AppendFormat("{0:X2}", MakeValue(1,a)); + sb.AppendFormat("{0:X2}", MakeValue(1,a, out temp)); } } @@ -1598,7 +1625,13 @@ namespace BizHawk.Client.EmuHawk private void BigEndianMenuItem_Click(object sender, EventArgs e) { - BigEndian ^= true; + //BigEndian ^= true; + //UpdateValues(); + } + + private void SwapBytesMenuItem_Click(object sender, EventArgs e) + { + SwapBytes ^= true; UpdateValues(); } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.cs index e3df562925..96497bced7 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.cs @@ -610,9 +610,9 @@ namespace BizHawk.Client.EmuHawk { TasBranch branch = GetBranch(BranchView.CurrentCell.RowIndex.Value); Point location = Location; - location.Offset(-Screenshot.Width, 0); - int width = Tastudio.VideoProvider.BufferWidth; - int height = Tastudio.VideoProvider.BufferHeight; + int width = branch.OSDFrameBuffer.Width; + int height = branch.OSDFrameBuffer.Height; + location.Offset(-width, 0); Screenshot.UpdateValues(branch, PointToScreen(location), width, height, (int)Graphics.FromHwnd(this.Handle).MeasureString( diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.Designer.cs index 783645dcce..9a15b7e7e3 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.Designer.cs @@ -48,28 +48,38 @@ namespace BizHawk.Client.EmuHawk this.DiskCapacityNumeric = new System.Windows.Forms.NumericUpDown(); this.label5 = new System.Windows.Forms.Label(); this.label6 = new System.Windows.Forms.Label(); - this.SaveCapacityNumeric = new System.Windows.Forms.NumericUpDown(); + this.FileCapacityNumeric = new System.Windows.Forms.NumericUpDown(); this.label7 = new System.Windows.Forms.Label(); this.label8 = new System.Windows.Forms.Label(); this.label9 = new System.Windows.Forms.Label(); this.NumSaveStatesLabel = new System.Windows.Forms.Label(); this.BranchStatesInTasproj = new System.Windows.Forms.CheckBox(); this.EraseBranchStatesFirst = new System.Windows.Forms.CheckBox(); - this.StateGap = new System.Windows.Forms.NumericUpDown(); + this.FileStateGapNumeric = new System.Windows.Forms.NumericUpDown(); this.label10 = new System.Windows.Forms.Label(); this.label11 = new System.Windows.Forms.Label(); - this.NumFramesLabel = new System.Windows.Forms.Label(); + this.FileNumFramesLabel = new System.Windows.Forms.Label(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label14 = new System.Windows.Forms.Label(); + this.MemFramesLabel = new System.Windows.Forms.Label(); + this.label13 = new System.Windows.Forms.Label(); + this.MemStateGapDividerNumeric = new System.Windows.Forms.NumericUpDown(); + this.label12 = new System.Windows.Forms.Label(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); ((System.ComponentModel.ISupportInitialize)(this.MemCapacityNumeric)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.DiskCapacityNumeric)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.SaveCapacityNumeric)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.StateGap)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.FileCapacityNumeric)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.FileStateGapNumeric)).BeginInit(); + this.groupBox1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.MemStateGapDividerNumeric)).BeginInit(); + this.groupBox2.SuspendLayout(); this.SuspendLayout(); // // CancelBtn // this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.CancelBtn.Location = new System.Drawing.Point(217, 220); + this.CancelBtn.Location = new System.Drawing.Point(242, 259); this.CancelBtn.Name = "CancelBtn"; this.CancelBtn.Size = new System.Drawing.Size(60, 23); this.CancelBtn.TabIndex = 0; @@ -80,7 +90,7 @@ namespace BizHawk.Client.EmuHawk // OkBtn // this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.OkBtn.Location = new System.Drawing.Point(151, 220); + this.OkBtn.Location = new System.Drawing.Point(176, 259); this.OkBtn.Name = "OkBtn"; this.OkBtn.Size = new System.Drawing.Size(60, 23); this.OkBtn.TabIndex = 1; @@ -90,7 +100,7 @@ namespace BizHawk.Client.EmuHawk // // MemCapacityNumeric // - this.MemCapacityNumeric.Location = new System.Drawing.Point(15, 49); + this.MemCapacityNumeric.Location = new System.Drawing.Point(12, 36); this.MemCapacityNumeric.Maximum = new decimal(new int[] { 1024, 0, @@ -114,20 +124,20 @@ namespace BizHawk.Client.EmuHawk // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(70, 52); + this.label1.Location = new System.Drawing.Point(73, 39); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(21, 13); + this.label1.Size = new System.Drawing.Size(23, 13); this.label1.TabIndex = 4; - this.label1.Text = "mb"; + this.label1.Text = "MB"; // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(12, 32); + this.label2.Location = new System.Drawing.Point(9, 19); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(88, 13); + this.label2.Size = new System.Drawing.Size(48, 13); this.label2.TabIndex = 5; - this.label2.Text = "Memory Capacity"; + this.label2.Text = "Capacity"; // // label3 // @@ -150,7 +160,7 @@ namespace BizHawk.Client.EmuHawk // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(12, 136); + this.label4.Location = new System.Drawing.Point(160, 9); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(84, 13); this.label4.TabIndex = 8; @@ -159,17 +169,18 @@ namespace BizHawk.Client.EmuHawk // NumStatesLabel // this.NumStatesLabel.AutoSize = true; - this.NumStatesLabel.Location = new System.Drawing.Point(99, 136); + this.NumStatesLabel.Location = new System.Drawing.Point(250, 9); this.NumStatesLabel.Name = "NumStatesLabel"; - this.NumStatesLabel.Size = new System.Drawing.Size(25, 13); + this.NumStatesLabel.Size = new System.Drawing.Size(13, 13); this.NumStatesLabel.TabIndex = 9; - this.NumStatesLabel.Text = "1kb"; + this.NumStatesLabel.Text = "1"; // // DiskCapacityNumeric // - this.DiskCapacityNumeric.Location = new System.Drawing.Point(15, 113); + this.DiskCapacityNumeric.Enabled = false; + this.DiskCapacityNumeric.Location = new System.Drawing.Point(24, 241); this.DiskCapacityNumeric.Maximum = new decimal(new int[] { - 65536, + 1, 0, 0, 0}); @@ -182,7 +193,7 @@ namespace BizHawk.Client.EmuHawk this.DiskCapacityNumeric.Size = new System.Drawing.Size(55, 20); this.DiskCapacityNumeric.TabIndex = 3; this.DiskCapacityNumeric.Value = new decimal(new int[] { - 512, + 1, 0, 0, 0}); @@ -191,61 +202,63 @@ namespace BizHawk.Client.EmuHawk // label5 // this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(70, 116); + this.label5.Enabled = false; + this.label5.Location = new System.Drawing.Point(79, 244); this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(21, 13); + this.label5.Size = new System.Drawing.Size(23, 13); this.label5.TabIndex = 4; - this.label5.Text = "mb"; + this.label5.Text = "MB"; // // label6 // this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(12, 96); + this.label6.Enabled = false; + this.label6.Location = new System.Drawing.Point(21, 224); this.label6.Name = "label6"; this.label6.Size = new System.Drawing.Size(72, 13); this.label6.TabIndex = 5; this.label6.Text = "Disk Capacity"; // - // SaveCapacityNumeric + // FileCapacityNumeric // - this.SaveCapacityNumeric.Location = new System.Drawing.Point(150, 49); - this.SaveCapacityNumeric.Maximum = new decimal(new int[] { + this.FileCapacityNumeric.Location = new System.Drawing.Point(12, 36); + this.FileCapacityNumeric.Maximum = new decimal(new int[] { 65536, 0, 0, 0}); - this.SaveCapacityNumeric.Name = "SaveCapacityNumeric"; - this.SaveCapacityNumeric.Size = new System.Drawing.Size(55, 20); - this.SaveCapacityNumeric.TabIndex = 3; - this.SaveCapacityNumeric.Value = new decimal(new int[] { + this.FileCapacityNumeric.Name = "FileCapacityNumeric"; + this.FileCapacityNumeric.Size = new System.Drawing.Size(55, 20); + this.FileCapacityNumeric.TabIndex = 3; + this.FileCapacityNumeric.Value = new decimal(new int[] { 512, 0, 0, 0}); - this.SaveCapacityNumeric.ValueChanged += new System.EventHandler(this.SaveCapacityNumeric_ValueChanged); + this.FileCapacityNumeric.ValueChanged += new System.EventHandler(this.SaveCapacityNumeric_ValueChanged); // // label7 // this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(205, 52); + this.label7.Location = new System.Drawing.Point(73, 39); this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(21, 13); + this.label7.Size = new System.Drawing.Size(23, 13); this.label7.TabIndex = 4; - this.label7.Text = "mb"; + this.label7.Text = "MB"; // // label8 // this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(147, 32); + this.label8.Location = new System.Drawing.Point(9, 19); this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(112, 13); + this.label8.Size = new System.Drawing.Size(48, 13); this.label8.TabIndex = 5; - this.label8.Text = "Project Save Capacity"; + this.label8.Text = "Capacity"; // // label9 // this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(147, 72); + this.label9.Location = new System.Drawing.Point(9, 59); this.label9.Name = "label9"; this.label9.Size = new System.Drawing.Size(84, 13); this.label9.TabIndex = 8; @@ -254,21 +267,21 @@ namespace BizHawk.Client.EmuHawk // NumSaveStatesLabel // this.NumSaveStatesLabel.AutoSize = true; - this.NumSaveStatesLabel.Location = new System.Drawing.Point(234, 72); + this.NumSaveStatesLabel.Location = new System.Drawing.Point(96, 59); this.NumSaveStatesLabel.Name = "NumSaveStatesLabel"; - this.NumSaveStatesLabel.Size = new System.Drawing.Size(25, 13); + this.NumSaveStatesLabel.Size = new System.Drawing.Size(13, 13); this.NumSaveStatesLabel.TabIndex = 9; - this.NumSaveStatesLabel.Text = "1kb"; + this.NumSaveStatesLabel.Text = "1"; // // BranchStatesInTasproj // this.BranchStatesInTasproj.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.BranchStatesInTasproj.AutoSize = true; - this.BranchStatesInTasproj.Location = new System.Drawing.Point(15, 165); + this.BranchStatesInTasproj.Location = new System.Drawing.Point(12, 153); this.BranchStatesInTasproj.Name = "BranchStatesInTasproj"; - this.BranchStatesInTasproj.Size = new System.Drawing.Size(158, 17); + this.BranchStatesInTasproj.Size = new System.Drawing.Size(118, 17); this.BranchStatesInTasproj.TabIndex = 10; - this.BranchStatesInTasproj.Text = "Put branch states to .tasproj"; + this.BranchStatesInTasproj.Text = "Save branch states"; this.BranchStatesInTasproj.UseVisualStyleBackColor = true; this.BranchStatesInTasproj.CheckedChanged += new System.EventHandler(this.BranchStatesInTasproj_CheckedChanged); // @@ -278,7 +291,7 @@ namespace BizHawk.Client.EmuHawk this.EraseBranchStatesFirst.AutoSize = true; this.EraseBranchStatesFirst.Checked = true; this.EraseBranchStatesFirst.CheckState = System.Windows.Forms.CheckState.Checked; - this.EraseBranchStatesFirst.Location = new System.Drawing.Point(15, 190); + this.EraseBranchStatesFirst.Location = new System.Drawing.Point(6, 153); this.EraseBranchStatesFirst.Name = "EraseBranchStatesFirst"; this.EraseBranchStatesFirst.Size = new System.Drawing.Size(139, 17); this.EraseBranchStatesFirst.TabIndex = 11; @@ -286,50 +299,146 @@ namespace BizHawk.Client.EmuHawk this.EraseBranchStatesFirst.UseVisualStyleBackColor = true; this.EraseBranchStatesFirst.CheckedChanged += new System.EventHandler(this.EraseBranchStatesFIrst_CheckedChanged); // - // StateGap + // FileStateGapNumeric // - this.StateGap.Location = new System.Drawing.Point(151, 112); - this.StateGap.Maximum = new decimal(new int[] { + this.FileStateGapNumeric.Location = new System.Drawing.Point(12, 100); + this.FileStateGapNumeric.Maximum = new decimal(new int[] { 8, 0, 0, 0}); - this.StateGap.Name = "StateGap"; - this.StateGap.Size = new System.Drawing.Size(55, 20); - this.StateGap.TabIndex = 12; - this.StateGap.Value = new decimal(new int[] { + this.FileStateGapNumeric.Name = "FileStateGapNumeric"; + this.FileStateGapNumeric.Size = new System.Drawing.Size(55, 20); + this.FileStateGapNumeric.TabIndex = 12; + this.FileStateGapNumeric.Value = new decimal(new int[] { 1, 0, 0, 0}); - this.StateGap.ValueChanged += new System.EventHandler(this.StateGap_ValueChanged); + this.FileStateGapNumeric.ValueChanged += new System.EventHandler(this.FileStateGap_ValueChanged); // // label10 // this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(148, 96); + this.label10.Location = new System.Drawing.Point(9, 84); this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(91, 13); + this.label10.Size = new System.Drawing.Size(55, 13); this.label10.TabIndex = 13; - this.label10.Text = "Project State Gap"; + this.label10.Text = "State Gap"; // // label11 // this.label11.AutoSize = true; - this.label11.Location = new System.Drawing.Point(147, 135); + this.label11.Location = new System.Drawing.Point(8, 123); this.label11.Name = "label11"; this.label11.Size = new System.Drawing.Size(61, 13); this.label11.TabIndex = 14; this.label11.Text = "State every"; // - // NumFramesLabel + // FileNumFramesLabel // - this.NumFramesLabel.AutoSize = true; - this.NumFramesLabel.Location = new System.Drawing.Point(204, 135); - this.NumFramesLabel.Name = "NumFramesLabel"; - this.NumFramesLabel.Size = new System.Drawing.Size(47, 13); - this.NumFramesLabel.TabIndex = 15; - this.NumFramesLabel.Text = "0 frames"; + this.FileNumFramesLabel.AutoSize = true; + this.FileNumFramesLabel.Location = new System.Drawing.Point(65, 123); + this.FileNumFramesLabel.Name = "FileNumFramesLabel"; + this.FileNumFramesLabel.Size = new System.Drawing.Size(47, 13); + this.FileNumFramesLabel.TabIndex = 15; + this.FileNumFramesLabel.Text = "0 frames"; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label14); + this.groupBox1.Controls.Add(this.MemFramesLabel); + this.groupBox1.Controls.Add(this.label13); + this.groupBox1.Controls.Add(this.MemStateGapDividerNumeric); + this.groupBox1.Controls.Add(this.label12); + this.groupBox1.Controls.Add(this.EraseBranchStatesFirst); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.MemCapacityNumeric); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Location = new System.Drawing.Point(12, 34); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(143, 176); + this.groupBox1.TabIndex = 16; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Memory Usage"; + // + // label14 + // + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(73, 102); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(21, 13); + this.label14.TabIndex = 17; + this.label14.Text = "KB"; + // + // MemFramesLabel + // + this.MemFramesLabel.AutoSize = true; + this.MemFramesLabel.Location = new System.Drawing.Point(66, 123); + this.MemFramesLabel.Name = "MemFramesLabel"; + this.MemFramesLabel.Size = new System.Drawing.Size(47, 13); + this.MemFramesLabel.TabIndex = 16; + this.MemFramesLabel.Text = "0 frames"; + // + // label13 + // + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(9, 123); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(61, 13); + this.label13.TabIndex = 15; + this.label13.Text = "State every"; + // + // MemStateGapDividerNumeric + // + this.MemStateGapDividerNumeric.Location = new System.Drawing.Point(12, 100); + this.MemStateGapDividerNumeric.Maximum = new decimal(new int[] { + 1024, + 0, + 0, + 0}); + this.MemStateGapDividerNumeric.Minimum = new decimal(new int[] { + 64, + 0, + 0, + 0}); + this.MemStateGapDividerNumeric.Name = "MemStateGapDividerNumeric"; + this.MemStateGapDividerNumeric.Size = new System.Drawing.Size(55, 20); + this.MemStateGapDividerNumeric.TabIndex = 7; + this.MemStateGapDividerNumeric.Value = new decimal(new int[] { + 65, + 0, + 0, + 0}); + this.MemStateGapDividerNumeric.ValueChanged += new System.EventHandler(this.MemStateGapDivider_ValueChanged); + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(9, 84); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(91, 13); + this.label12.TabIndex = 6; + this.label12.Text = "State Gap Divider"; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.label8); + this.groupBox2.Controls.Add(this.FileCapacityNumeric); + this.groupBox2.Controls.Add(this.FileNumFramesLabel); + this.groupBox2.Controls.Add(this.label7); + this.groupBox2.Controls.Add(this.BranchStatesInTasproj); + this.groupBox2.Controls.Add(this.label11); + this.groupBox2.Controls.Add(this.label9); + this.groupBox2.Controls.Add(this.label10); + this.groupBox2.Controls.Add(this.NumSaveStatesLabel); + this.groupBox2.Controls.Add(this.FileStateGapNumeric); + this.groupBox2.Location = new System.Drawing.Point(163, 34); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(138, 176); + this.groupBox2.TabIndex = 17; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Project File"; // // StateHistorySettingsForm // @@ -337,28 +446,16 @@ namespace BizHawk.Client.EmuHawk this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.CancelBtn; - this.ClientSize = new System.Drawing.Size(289, 255); - this.Controls.Add(this.NumFramesLabel); - this.Controls.Add(this.label11); - this.Controls.Add(this.label10); - this.Controls.Add(this.StateGap); - this.Controls.Add(this.EraseBranchStatesFirst); - this.Controls.Add(this.BranchStatesInTasproj); - this.Controls.Add(this.NumSaveStatesLabel); - this.Controls.Add(this.NumStatesLabel); - this.Controls.Add(this.label9); - this.Controls.Add(this.label4); - this.Controls.Add(this.SavestateSizeLabel); - this.Controls.Add(this.label3); - this.Controls.Add(this.label8); - this.Controls.Add(this.label7); - this.Controls.Add(this.label6); - this.Controls.Add(this.label5); - this.Controls.Add(this.SaveCapacityNumeric); - this.Controls.Add(this.label2); + this.ClientSize = new System.Drawing.Size(315, 294); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); this.Controls.Add(this.DiskCapacityNumeric); - this.Controls.Add(this.label1); - this.Controls.Add(this.MemCapacityNumeric); + this.Controls.Add(this.label5); + this.Controls.Add(this.SavestateSizeLabel); + this.Controls.Add(this.label6); + this.Controls.Add(this.label4); + this.Controls.Add(this.label3); + this.Controls.Add(this.NumStatesLabel); this.Controls.Add(this.OkBtn); this.Controls.Add(this.CancelBtn); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); @@ -369,8 +466,13 @@ namespace BizHawk.Client.EmuHawk this.Load += new System.EventHandler(this.StateHistorySettings_Load); ((System.ComponentModel.ISupportInitialize)(this.MemCapacityNumeric)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.DiskCapacityNumeric)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.SaveCapacityNumeric)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.StateGap)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.FileCapacityNumeric)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.FileStateGapNumeric)).EndInit(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.MemStateGapDividerNumeric)).EndInit(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -388,16 +490,23 @@ namespace BizHawk.Client.EmuHawk private NumericUpDown DiskCapacityNumeric; private Label label5; private Label label6; - private NumericUpDown SaveCapacityNumeric; + private NumericUpDown FileCapacityNumeric; private Label label7; private Label label8; private Label label9; private Label NumSaveStatesLabel; private CheckBox BranchStatesInTasproj; private CheckBox EraseBranchStatesFirst; - private NumericUpDown StateGap; + private NumericUpDown FileStateGapNumeric; private Label label10; private Label label11; - private Label NumFramesLabel; + private Label FileNumFramesLabel; + private GroupBox groupBox1; + private NumericUpDown MemStateGapDividerNumeric; + private Label label12; + private GroupBox groupBox2; + private Label MemFramesLabel; + private Label label13; + private Label label14; } } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.cs index e62bb0321d..e45a2a6f3f 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.cs @@ -29,11 +29,16 @@ namespace BizHawk.Client.EmuHawk _settings.Capacitymb : MemCapacityNumeric.Maximum; DiskCapacityNumeric.Value = _settings.DiskCapacitymb < MemCapacityNumeric.Maximum ? _settings.DiskCapacitymb : MemCapacityNumeric.Maximum; - SaveCapacityNumeric.Value = _settings.DiskSaveCapacitymb < MemCapacityNumeric.Maximum ? + FileCapacityNumeric.Value = _settings.DiskSaveCapacitymb < MemCapacityNumeric.Maximum ? _settings.DiskSaveCapacitymb : MemCapacityNumeric.Maximum; - StateGap.Value = _settings.StateGap; - SavestateSizeLabel.Text = Math.Round(_stateSizeMb, 2).ToString() + " mb"; + MemStateGapDividerNumeric.Maximum = Statable.SaveStateBinary().Length / 1024 / 2 + 1; + MemStateGapDividerNumeric.Minimum = Statable.SaveStateBinary().Length / 1024 / 16; + MemStateGapDividerNumeric.Value = _settings.MemStateGapDivider < MemStateGapDividerNumeric.Minimum ? + MemStateGapDividerNumeric.Minimum : _settings.MemStateGapDivider; + + FileStateGapNumeric.Value = _settings.FileStateGap; + SavestateSizeLabel.Text = Math.Round(_stateSizeMb, 2).ToString() + " MB"; CapacityNumeric_ValueChanged(null, null); SaveCapacityNumeric_ValueChanged(null, null); BranchStatesInTasproj.Checked = _settings.BranchStatesInTasproj; @@ -47,8 +52,9 @@ namespace BizHawk.Client.EmuHawk { _settings.Capacitymb = (int)MemCapacityNumeric.Value; _settings.DiskCapacitymb = (int)DiskCapacityNumeric.Value; - _settings.DiskSaveCapacitymb = (int)SaveCapacityNumeric.Value; - _settings.StateGap = (int)StateGap.Value; + _settings.DiskSaveCapacitymb = (int)FileCapacityNumeric.Value; + _settings.MemStateGapDivider = (int)MemStateGapDividerNumeric.Value; + _settings.FileStateGap = (int)FileStateGapNumeric.Value; DialogResult = DialogResult.OK; Close(); } @@ -68,7 +74,7 @@ namespace BizHawk.Client.EmuHawk private void SaveCapacityNumeric_ValueChanged(object sender, EventArgs e) { - NumSaveStatesLabel.Text = ((int)Math.Floor(SaveCapacityNumeric.Value / _stateSizeMb)).ToString(); + NumSaveStatesLabel.Text = ((int)Math.Floor(FileCapacityNumeric.Value / _stateSizeMb)).ToString(); } private void BranchStatesInTasproj_CheckedChanged(object sender, EventArgs e) @@ -81,11 +87,23 @@ namespace BizHawk.Client.EmuHawk _settings.EraseBranchStatesFirst = EraseBranchStatesFirst.Checked; } - private void StateGap_ValueChanged(object sender, EventArgs e) + private void FileStateGap_ValueChanged(object sender, EventArgs e) { - NumFramesLabel.Text = StateGap.Value == 0 + FileNumFramesLabel.Text = FileStateGapNumeric.Value == 0 ? "frame" - : $"{1 << (int)StateGap.Value} frames"; + : $"{1 << (int)FileStateGapNumeric.Value} frames"; + } + + private void MemStateGapDivider_ValueChanged(object sender, EventArgs e) + { + int val = (int)(Statable.SaveStateBinary().Length / MemStateGapDividerNumeric.Value / 1024); + + if (val <= 1) + MemStateGapDividerNumeric.Maximum = MemStateGapDividerNumeric.Value; + + MemFramesLabel.Text = val <= 1 + ? "frame" + : $"{val} frames"; } } } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/ScreenshotForm.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/ScreenshotForm.cs index 4b86d7ee8b..65e407eb5f 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/ScreenshotForm.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/ScreenshotForm.cs @@ -11,11 +11,8 @@ namespace BizHawk.Client.EmuHawk { public partial class ScreenshotForm : Form { - // but still appear topmost private const int WS_EX_TOPMOST = 0x00000008; - - private const int WidthCap = 320; - private const int HeightCap = 240; + private const int Interval = 40; private const double AlphaStep = 0.125; @@ -32,9 +29,7 @@ namespace BizHawk.Client.EmuHawk public ScreenshotForm() { InitializeComponent(); - - Width = WidthCap; - Height = HeightCap; + var fontSize = 10; var fontStyle = FontStyle.Regular; Font = new Font(FontFamily.GenericMonospace, fontSize, fontStyle); @@ -71,15 +66,6 @@ namespace BizHawk.Client.EmuHawk Text = _branch.UserText; Location = location; - // Set the screenshot to "1x" resolution of the core - // cores like n64 and psx are going to still have sizes too big for the control, so cap them - if (Width > WidthCap) - { - double ratio = WidthCap / (double)Width; - Width = WidthCap; - _drawingHeight = (int)((double)(_drawingHeight) * ratio); - } - if (Padding > 0) { Padding += 2; diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs index 295976bb22..bb3d0089d8 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs @@ -55,7 +55,7 @@ namespace BizHawk.Client.EmuHawk private bool _triggerAutoRestore; // If true, autorestore will be called on mouse up private bool? _autoRestorePaused = null; private int? _seekStartFrame = null; - private bool _shouldUnpauseFromRewind = false; + private bool _unpauseAfterSeeking = false; private ControllerDefinition ControllerType => Global.MovieSession.MovieControllerAdapter.Definition; @@ -111,10 +111,10 @@ namespace BizHawk.Client.EmuHawk } Mainform.PauseOnFrame = null; - if (_shouldUnpauseFromRewind) + if (_unpauseAfterSeeking) { Mainform.UnpauseEmulator(); - _shouldUnpauseFromRewind = false; + _unpauseAfterSeeking = false; } if (CurrentTasMovie != null) @@ -762,7 +762,8 @@ namespace BizHawk.Client.EmuHawk private void TasView_MouseUp(object sender, MouseEventArgs e) { - if (e.Button == MouseButtons.Right && !TasView.IsPointingAtColumnHeader && !_supressContextMenu && TasView.SelectedRows.Any()) + if (e.Button == MouseButtons.Right && !TasView.IsPointingAtColumnHeader && + !_supressContextMenu && TasView.SelectedRows.Any() && !_leftButtonHeld) { if (Global.MovieSession.Movie.FrameCount < TasView.SelectedRows.Max()) { diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index 30c4349282..63be9aa051 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -72,11 +72,10 @@ namespace BizHawk.Client.EmuHawk } else if (ofd.FileName.EndsWith(".bkm") || ofd.FileName.EndsWith(".bk2")) // todo: proper extention iteration { - Mainform.StartNewMovie(MovieService.Get(ofd.FileName), false); - var result1 = MessageBox.Show("This is a regular movie, a new project must be created from it, in order to use in TAStudio\nProceed?", "Convert movie", MessageBoxButtons.OKCancel, MessageBoxIcon.Question); if (result1 == DialogResult.OK) { + Mainform.StartNewMovie(MovieService.Get(ofd.FileName), false); ConvertCurrentMovieToTasproj(); StartNewMovieWrapper(false); SetUpColumns(); diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index d2d48907b7..84405c107b 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -829,7 +829,7 @@ namespace BizHawk.Client.EmuHawk if (frame == Emulator.Frame) return; - _shouldUnpauseFromRewind = fromRewinding && !Mainform.EmulatorPaused; + _unpauseAfterSeeking = (fromRewinding || WasRecording) && !Mainform.EmulatorPaused; TastudioPlayMode(); KeyValuePair closestState = CurrentTasMovie.TasStateManager.GetStateClosestToFrame(frame); if (closestState.Value != null && (frame < Emulator.Frame || closestState.Key > Emulator.Frame)) @@ -871,7 +871,8 @@ namespace BizHawk.Client.EmuHawk // frame == Emulator.Frame when frame == 0 if (frame > Emulator.Frame) { - if (Mainform.EmulatorPaused || Mainform.IsSeeking || fromRewinding) // make seek frame keep up with emulation on fast scrolls + // make seek frame keep up with emulation on fast scrolls + if (Mainform.EmulatorPaused || Mainform.IsSeeking || fromRewinding || WasRecording) { StartSeeking(frame); } diff --git a/BizHawk.Emulation.Common/Base Implementations/CallbackBasedTraceBuffer.cs b/BizHawk.Emulation.Common/Base Implementations/CallbackBasedTraceBuffer.cs index f87e4bcb73..4a93abc213 100644 --- a/BizHawk.Emulation.Common/Base Implementations/CallbackBasedTraceBuffer.cs +++ b/BizHawk.Emulation.Common/Base Implementations/CallbackBasedTraceBuffer.cs @@ -94,6 +94,8 @@ namespace BizHawk.Emulation.Common public uint? Address => null; public uint? AddressMask => null; + + public string Scope => ""; // This will be relevant if/when the trace logger can trace anything other than the system bus } } } diff --git a/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs b/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs index 0ec6dfc56e..084a110174 100644 --- a/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs +++ b/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs @@ -14,8 +14,14 @@ namespace BizHawk.Emulation.Common /// public class MemoryCallbackSystem : IMemoryCallbackSystem { - public MemoryCallbackSystem() + public MemoryCallbackSystem(string[] availableScopes) { + if (availableScopes == null) + { + availableScopes = new[] { "System Bus" }; + } + + AvailableScopes = availableScopes; ExecuteCallbacksAvailable = true; _reads.CollectionChanged += OnCollectionChanged; @@ -35,8 +41,15 @@ namespace BizHawk.Emulation.Common public bool ExecuteCallbacksAvailable { get; } + public string[] AvailableScopes { get; } + public void Add(IMemoryCallback callback) { + if (!AvailableScopes.Contains(callback.Scope)) + { + throw new InvalidOperationException($"{callback.Scope} is not currently supported for callbacks"); + } + switch (callback.Type) { case MemoryCallbackType.Execute: @@ -61,38 +74,38 @@ namespace BizHawk.Emulation.Common _empty = false; } - private static void Call(ObservableCollection cbs, uint addr) + private static void Call(ObservableCollection cbs, uint addr, string scope) { for (int i = 0; i < cbs.Count; i++) { - if (!cbs[i].Address.HasValue || cbs[i].Address == (addr & cbs[i].AddressMask)) + if (!cbs[i].Address.HasValue || (cbs[i].Scope == scope && cbs[i].Address == (addr & cbs[i].AddressMask))) { cbs[i].Callback(); } } } - public void CallReads(uint addr) + public void CallReads(uint addr, string scope) { if (_hasReads) { - Call(_reads, addr); + Call(_reads, addr, scope); } } - public void CallWrites(uint addr) + public void CallWrites(uint addr, string scope) { if (_hasWrites) { - Call(_writes, addr); + Call(_writes, addr, scope); } } - public void CallExecutes(uint addr) + public void CallExecutes(uint addr, string scope) { if (_hasExecutes) { - Call(_execs, addr); + Call(_execs, addr, scope); } } @@ -102,6 +115,21 @@ namespace BizHawk.Emulation.Common public bool HasExecutes => _hasExecutes; + public bool HasReadsForScope(string scope) + { + return _reads.Where(e => e.Scope == scope).Any(); + } + + public bool HasWritesForScope(string scope) + { + return _writes.Where(e => e.Scope == scope).Any(); + } + + public bool HasExecutesForScope(string scope) + { + return _execs.Where(e => e.Scope == scope).Any(); + } + private void UpdateHasVariables() { _hasReads = _reads.Count > 0; @@ -273,7 +301,7 @@ namespace BizHawk.Emulation.Common public class MemoryCallback : IMemoryCallback { - public MemoryCallback(MemoryCallbackType type, string name, Action callback, uint? address, uint? mask) + public MemoryCallback(string scope, MemoryCallbackType type, string name, Action callback, uint? address, uint? mask) { if (type == MemoryCallbackType.Execute && !address.HasValue) { @@ -285,6 +313,7 @@ namespace BizHawk.Emulation.Common Callback = callback; Address = address; AddressMask = mask ?? 0xFFFFFFFF; + Scope = scope; } public MemoryCallbackType Type { get; } @@ -292,5 +321,6 @@ namespace BizHawk.Emulation.Common public Action Callback { get; } public uint? Address { get; } public uint? AddressMask { get; } + public string Scope { get; } } } diff --git a/BizHawk.Emulation.Common/EmulationExceptions.cs b/BizHawk.Emulation.Common/EmulationExceptions.cs index f0bc2a5860..ea85be6924 100644 --- a/BizHawk.Emulation.Common/EmulationExceptions.cs +++ b/BizHawk.Emulation.Common/EmulationExceptions.cs @@ -20,6 +20,20 @@ namespace BizHawk.Emulation.Common } } + public class NoAvailableCoreException : Exception + { + public NoAvailableCoreException() + : base("System is currently NOT emulated") + { + } + + public NoAvailableCoreException(string message) + : base ("System is currently NOT emulated: " + message) + { + + } + } + public class CGBNotSupportedException : Exception { public CGBNotSupportedException() diff --git a/BizHawk.Emulation.Common/Interfaces/IMemoryCallbackSystem.cs b/BizHawk.Emulation.Common/Interfaces/IMemoryCallbackSystem.cs index 029a1c9320..f87a8e492d 100644 --- a/BizHawk.Emulation.Common/Interfaces/IMemoryCallbackSystem.cs +++ b/BizHawk.Emulation.Common/Interfaces/IMemoryCallbackSystem.cs @@ -37,27 +37,49 @@ namespace BizHawk.Emulation.Common /// bool HasExecutes { get; } + /// + /// Gets a value indicating whether or not there are currently any read hooks + /// + bool HasReadsForScope(string scope); + + /// + /// Gets a value indicating whether or not there are currently any write hooks + /// + bool HasWritesForScope(string scope); + + /// + /// Gets a value indicating whether or not there are currently any execute hooks + /// + bool HasExecutesForScope(string scope); + /// /// Adds a callback for the given type to the given address /// If no address is specified the callback will be hooked to all addresses /// Note: an execute callback can not be added without an address, else an InvalidOperationException will occur /// + /// Thrown when the property of the is not in the void Add(IMemoryCallback callback); /// - /// Executes all Read callbacks for the given address + /// Executes all Read callbacks for the given address and domain /// - void CallReads(uint addr); + /// The address to check for callbacks + /// The scope that the address pertains to. Must be a value in + void CallReads(uint addr, string scope); /// - /// Executes all Write callbacks for the given address + /// Executes all Write callbacks for the given address and domain /// - void CallWrites(uint addr); + /// The address to check for callbacks + /// The scope that the address pertains to. Must be a value in + void CallWrites(uint addr, string scope); /// - /// Executes all Execute callbacks for the given address + /// Executes all Execute callbacks for the given address and domain /// - void CallExecutes(uint addr); + /// The address to check for callbacks + /// The scope that the address pertains to. Must be a value in + void CallExecutes(uint addr, string scope); /// /// Removes the given callback from the list @@ -73,6 +95,12 @@ namespace BizHawk.Emulation.Common /// Removes all read,write, and execute callbacks /// void Clear(); + + /// + /// A list of available "scopes" (memory domains, cpus, etc) that a the property of the can have + /// Passing a into the method that is not in this list will result in an + /// + string[] AvailableScopes { get; } } /// @@ -86,6 +114,7 @@ namespace BizHawk.Emulation.Common Action Callback { get; } uint? Address { get; } uint? AddressMask { get; } + string Scope { get; } } public enum MemoryCallbackType diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 2c4cc573ce..0acda8f08e 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -365,7 +365,7 @@ - + @@ -463,6 +463,9 @@ Gambatte.cs + + Gambatte.cs + Gambatte.cs @@ -749,6 +752,7 @@ + @@ -877,6 +881,9 @@ NES.cs + + NES.cs + NES.cs @@ -1068,6 +1075,8 @@ + + SMS.cs @@ -1183,12 +1192,14 @@ - - - - - - + + + + + + + + True True diff --git a/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.Execute.cs b/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.Execute.cs index cffb04037c..c4f3db942d 100644 --- a/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.Execute.cs +++ b/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.Execute.cs @@ -192,7 +192,7 @@ namespace BizHawk.Emulation.Cores.Components.CP1610 if (MemoryCallbacks != null) { - MemoryCallbacks.CallExecutes(RegisterPC); + MemoryCallbacks.CallExecutes(RegisterPC, "System Bus"); } switch (opcode) diff --git a/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.cs b/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.cs index 29c2ea6524..8a4ced6fa0 100644 --- a/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.cs +++ b/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.cs @@ -31,7 +31,7 @@ namespace BizHawk.Emulation.Cores.Components.CP1610 { if (MemoryCallbacks != null && !peek) { - MemoryCallbacks.CallReads(addr); + MemoryCallbacks.CallReads(addr, "System Bus"); } return ReadMemory(addr, peek); @@ -41,7 +41,7 @@ namespace BizHawk.Emulation.Cores.Components.CP1610 { if (MemoryCallbacks != null && !poke) { - MemoryCallbacks.CallWrites(addr); + MemoryCallbacks.CallWrites(addr, "System Bus"); } WriteMemory(addr, value, poke); diff --git a/BizHawk.Emulation.Cores/CPUs/HuC6280/Execute.cs b/BizHawk.Emulation.Cores/CPUs/HuC6280/Execute.cs index d151dd15a8..e86edcc297 100644 --- a/BizHawk.Emulation.Cores/CPUs/HuC6280/Execute.cs +++ b/BizHawk.Emulation.Cores/CPUs/HuC6280/Execute.cs @@ -60,7 +60,7 @@ namespace BizHawk.Emulation.Cores.Components.H6280 LagIFlag = FlagI; if (Debug) Logger(State()); - MemoryCallbacks.CallExecutes(PC); + MemoryCallbacks.CallExecutes(PC, "System Bus"); if (CDL != null && CDL.Active) CDLOpcode(); diff --git a/BizHawk.Emulation.Cores/CPUs/HuC6280/HuC6280.cs b/BizHawk.Emulation.Cores/CPUs/HuC6280/HuC6280.cs index a6e0c63b47..9e2e8ad470 100644 --- a/BizHawk.Emulation.Cores/CPUs/HuC6280/HuC6280.cs +++ b/BizHawk.Emulation.Cores/CPUs/HuC6280/HuC6280.cs @@ -230,7 +230,7 @@ namespace BizHawk.Emulation.Cores.Components.H6280 { byte page = MPR[address >> 13]; var result = ReadMemory21((page << 13) | (address & 0x1FFF)); - MemoryCallbacks.CallReads(address); + MemoryCallbacks.CallReads(address, "System Bus"); return result; } @@ -238,7 +238,7 @@ namespace BizHawk.Emulation.Cores.Components.H6280 { byte page = MPR[address >> 13]; WriteMemory21((page << 13) | (address & 0x1FFF), value); - MemoryCallbacks.CallWrites(address); + MemoryCallbacks.CallWrites(address, "System Bus"); } private ushort ReadWord(ushort address) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Z80/Execute.cs deleted file mode 100644 index ee77ddde91..0000000000 --- a/BizHawk.Emulation.Cores/CPUs/Z80/Execute.cs +++ /dev/null @@ -1,12491 +0,0 @@ -using BizHawk.Common.NumberExtensions; -using BizHawk.Emulation.Common; -using System; - -namespace BizHawk.Emulation.Cores.Components.Z80 -{ - public partial class Z80A - { - private int totalExecutedCycles; - public int TotalExecutedCycles { get { return totalExecutedCycles; } set { totalExecutedCycles = value; } } - - private int expectedExecutedCycles; - public int ExpectedExecutedCycles { get { return expectedExecutedCycles; } set { expectedExecutedCycles = value; } } - - private int pendingCycles; - public int PendingCycles { get { return pendingCycles; } set { pendingCycles = value; } } - - private int EI_pending; - - private ushort temp_WZ; - - public bool Debug; - public Action Logger; - - /// - /// Runs the CPU for a particular number of clock cycles. - /// - /// The number of cycles to run the CPU emulator for. Specify -1 to run for a single instruction. - public void ExecuteCycles(int cycles) - { - expectedExecutedCycles += cycles; - pendingCycles += cycles; - - sbyte Displacement; - - byte TB; byte TBH; byte TBL; byte TB1; byte TB2; sbyte TSB; ushort TUS; int TI1; int TI2; int TIR; - - bool Interruptable; - - while (pendingCycles > 0) - { - Interruptable = true; - - if (halted) - { - ++RegR; - totalExecutedCycles += 4; pendingCycles -= 4; - } - else - { - if (Debug) - { - Logger(State()); - } - - if (MemoryCallbacks != null) - { - MemoryCallbacks.CallExecutes(RegPC.Word); - } - - ++RegR; - switch (FetchFirstMemoryWrapper(RegPC.Word++)) - { - case 0x00: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x01: // LD BC, nn - RegBC.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x02: // LD (BC), A - RegWZ.Low = (byte)((RegBC.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegBC.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x03: // INC BC - ++RegBC.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x04: // INC B - RegAF.Low = (byte)(TableInc[++RegBC.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x05: // DEC B - RegAF.Low = (byte)(TableDec[--RegBC.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x06: // LD B, n - RegBC.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x07: // RLCA - RegAF.Word = TableRotShift[0, 0, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x08: // EX AF, AF' - TUS = RegAF.Word; RegAF.Word = RegAltAF.Word; RegAltAF.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x09: // ADD HL, BC - RegWZ = (ushort)(RegHL + 1); - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x0A: // LD A, (BC) - RegAF.High = ReadMemoryWrapper(RegBC.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegBC.Word + 1); - break; - case 0x0B: // DEC BC - --RegBC.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x0C: // INC C - RegAF.Low = (byte)(TableInc[++RegBC.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0D: // DEC C - RegAF.Low = (byte)(TableDec[--RegBC.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0E: // LD C, n - RegBC.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x0F: // RRCA - RegAF.Word = TableRotShift[0, 1, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x10: // DJNZ d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (--RegBC.High != 0) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 13; pendingCycles -= 13; - } - else - { - totalExecutedCycles += 8; pendingCycles -= 8; - } - break; - case 0x11: // LD DE, nn - RegDE.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x12: // LD (DE), A - RegWZ.Low = (byte)((RegDE.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegDE.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x13: // INC DE - ++RegDE.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x14: // INC D - RegAF.Low = (byte)(TableInc[++RegDE.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x15: // DEC D - RegAF.Low = (byte)(TableDec[--RegDE.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x16: // LD D, n - RegDE.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x17: // RLA - RegAF.Word = TableRotShift[0, 2, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x18: // JR d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x19: // ADD HL, DE - RegWZ = (ushort)(RegHL + 1); - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x1A: // LD A, (DE) - RegAF.High = ReadMemoryWrapper(RegDE.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegDE.Word + 1); - break; - case 0x1B: // DEC DE - --RegDE.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x1C: // INC E - RegAF.Low = (byte)(TableInc[++RegDE.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1D: // DEC E - RegAF.Low = (byte)(TableDec[--RegDE.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1E: // LD E, n - RegDE.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x1F: // RRA - RegAF.Word = TableRotShift[0, 3, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x20: // JR NZ, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (!RegFlagZ) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x21: // LD HL, nn - RegHL.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x22: // LD (nn), HL - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegHL.Low); - WriteMemoryWrapper(TUS, RegHL.High); - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0x23: // INC HL - ++RegHL.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x24: // INC H - RegAF.Low = (byte)(TableInc[++RegHL.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x25: // DEC H - RegAF.Low = (byte)(TableDec[--RegHL.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x26: // LD H, n - RegHL.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x27: // DAA - RegAF.Word = TableDaa[RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x28: // JR Z, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (RegFlagZ) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x29: // ADD HL, HL - RegWZ = (ushort)(RegHL + 1); - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x2A: // LD HL, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegHL.Low = ReadMemoryWrapper(TUS++); RegHL.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0x2B: // DEC HL - --RegHL.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x2C: // INC L - RegAF.Low = (byte)(TableInc[++RegHL.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2D: // DEC L - RegAF.Low = (byte)(TableDec[--RegHL.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2E: // LD L, n - RegHL.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x2F: // CPL - RegAF.High ^= 0xFF; RegFlagH = true; RegFlagN = true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x30: // JR NC, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (!RegFlagC) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x31: // LD SP, nn - RegSP.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x32: // LD (nn), A - temp_WZ = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ.Low = (byte)((temp_WZ + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(temp_WZ, RegAF.High); - totalExecutedCycles += 13; pendingCycles -= 13; - break; - case 0x33: // INC SP - ++RegSP.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x34: // INC (HL) - TB = ReadMemoryWrapper(RegHL.Word); RegAF.Low = (byte)(TableInc[++TB] | (RegAF.Low & 1)); WriteMemoryWrapper(RegHL.Word, TB); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x35: // DEC (HL) - TB = ReadMemoryWrapper(RegHL.Word); RegAF.Low = (byte)(TableDec[--TB] | (RegAF.Low & 1)); WriteMemoryWrapper(RegHL.Word, TB); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x36: // LD (HL), n - WriteMemoryWrapper(RegHL.Word, FetchMemoryWrapper(RegPC.Word++)); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x37: // SCF - RegFlagH = false; RegFlagN = false; RegFlagC = true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x38: // JR C, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (RegFlagC) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x39: // ADD HL, SP - RegWZ = (ushort)(RegHL + 1); - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x3A: // LD A, (nn) - temp_WZ = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegAF.High = ReadMemoryWrapper(temp_WZ); - totalExecutedCycles += 13; pendingCycles -= 13; - RegWZ.Word = (ushort)(temp_WZ + 1); - break; - case 0x3B: // DEC SP - --RegSP.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x3C: // INC A - RegAF.Low = (byte)(TableInc[++RegAF.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3D: // DEC A - RegAF.Low = (byte)(TableDec[--RegAF.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3E: // LD A, n - RegAF.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x3F: // CCF - RegFlagH = RegFlagC; RegFlagN = false; RegFlagC ^= true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x40: // LD B, B - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x41: // LD B, C - RegBC.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x42: // LD B, D - RegBC.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x43: // LD B, E - RegBC.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x44: // LD B, H - RegBC.High = RegHL.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x45: // LD B, L - RegBC.High = RegHL.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x46: // LD B, (HL) - RegBC.High = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x47: // LD B, A - RegBC.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x48: // LD C, B - RegBC.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x49: // LD C, C - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4A: // LD C, D - RegBC.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4B: // LD C, E - RegBC.Low = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4C: // LD C, H - RegBC.Low = RegHL.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4D: // LD C, L - RegBC.Low = RegHL.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4E: // LD C, (HL) - RegBC.Low = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x4F: // LD C, A - RegBC.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x50: // LD D, B - RegDE.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x51: // LD D, C - RegDE.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x52: // LD D, D - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x53: // LD D, E - RegDE.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x54: // LD D, H - RegDE.High = RegHL.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x55: // LD D, L - RegDE.High = RegHL.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x56: // LD D, (HL) - RegDE.High = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x57: // LD D, A - RegDE.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x58: // LD E, B - RegDE.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x59: // LD E, C - RegDE.Low = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5A: // LD E, D - RegDE.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5B: // LD E, E - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5C: // LD E, H - RegDE.Low = RegHL.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5D: // LD E, L - RegDE.Low = RegHL.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5E: // LD E, (HL) - RegDE.Low = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x5F: // LD E, A - RegDE.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x60: // LD H, B - RegHL.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x61: // LD H, C - RegHL.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x62: // LD H, D - RegHL.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x63: // LD H, E - RegHL.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x64: // LD H, H - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x65: // LD H, L - RegHL.High = RegHL.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x66: // LD H, (HL) - RegHL.High = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x67: // LD H, A - RegHL.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x68: // LD L, B - RegHL.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x69: // LD L, C - RegHL.Low = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x6A: // LD L, D - RegHL.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x6B: // LD L, E - RegHL.Low = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x6C: // LD L, H - RegHL.Low = RegHL.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x6D: // LD L, L - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x6E: // LD L, (HL) - RegHL.Low = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x6F: // LD L, A - RegHL.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x70: // LD (HL), B - WriteMemoryWrapper(RegHL.Word, RegBC.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x71: // LD (HL), C - WriteMemoryWrapper(RegHL.Word, RegBC.Low); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x72: // LD (HL), D - WriteMemoryWrapper(RegHL.Word, RegDE.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x73: // LD (HL), E - WriteMemoryWrapper(RegHL.Word, RegDE.Low); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x74: // LD (HL), H - WriteMemoryWrapper(RegHL.Word, RegHL.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x75: // LD (HL), L - WriteMemoryWrapper(RegHL.Word, RegHL.Low); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x76: // HALT - Halt(); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x77: // LD (HL), A - RegWZ.Low = (byte)((RegHL.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegHL.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x78: // LD A, B - RegAF.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x79: // LD A, C - RegAF.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7A: // LD A, D - RegAF.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7B: // LD A, E - RegAF.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7C: // LD A, H - RegAF.High = RegHL.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7D: // LD A, L - RegAF.High = RegHL.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7E: // LD A, (HL) - RegAF.High = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegHL.Word + 1); - break; - case 0x7F: // LD A, A - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x80: // ADD A, B - RegAF.Word = TableALU[0, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x81: // ADD A, C - RegAF.Word = TableALU[0, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x82: // ADD A, D - RegAF.Word = TableALU[0, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x83: // ADD A, E - RegAF.Word = TableALU[0, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x84: // ADD A, H - RegAF.Word = TableALU[0, RegAF.High, RegHL.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x85: // ADD A, L - RegAF.Word = TableALU[0, RegAF.High, RegHL.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x86: // ADD A, (HL) - RegWZ = (ushort)(RegHL + 1); - RegAF.Word = TableALU[0, RegAF.High, ReadMemoryWrapper(RegHL.Word), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x87: // ADD A, A - RegAF.Word = TableALU[0, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x88: // ADC A, B - RegAF.Word = TableALU[1, RegAF.High, RegBC.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x89: // ADC A, C - RegAF.Word = TableALU[1, RegAF.High, RegBC.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8A: // ADC A, D - RegAF.Word = TableALU[1, RegAF.High, RegDE.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8B: // ADC A, E - RegAF.Word = TableALU[1, RegAF.High, RegDE.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8C: // ADC A, H - RegAF.Word = TableALU[1, RegAF.High, RegHL.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8D: // ADC A, L - RegAF.Word = TableALU[1, RegAF.High, RegHL.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8E: // ADC A, (HL) - RegAF.Word = TableALU[1, RegAF.High, ReadMemoryWrapper(RegHL.Word), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x8F: // ADC A, A - RegAF.Word = TableALU[1, RegAF.High, RegAF.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x90: // SUB B - RegAF.Word = TableALU[2, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x91: // SUB C - RegAF.Word = TableALU[2, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x92: // SUB D - RegAF.Word = TableALU[2, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x93: // SUB E - RegAF.Word = TableALU[2, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x94: // SUB H - RegAF.Word = TableALU[2, RegAF.High, RegHL.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x95: // SUB L - RegAF.Word = TableALU[2, RegAF.High, RegHL.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x96: // SUB (HL) - RegAF.Word = TableALU[2, RegAF.High, ReadMemoryWrapper(RegHL.Word), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x97: // SUB A, A - RegAF.Word = TableALU[2, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x98: // SBC A, B - RegAF.Word = TableALU[3, RegAF.High, RegBC.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x99: // SBC A, C - RegAF.Word = TableALU[3, RegAF.High, RegBC.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9A: // SBC A, D - RegAF.Word = TableALU[3, RegAF.High, RegDE.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9B: // SBC A, E - RegAF.Word = TableALU[3, RegAF.High, RegDE.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9C: // SBC A, H - RegAF.Word = TableALU[3, RegAF.High, RegHL.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9D: // SBC A, L - RegAF.Word = TableALU[3, RegAF.High, RegHL.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9E: // SBC A, (HL) - RegAF.Word = TableALU[3, RegAF.High, ReadMemoryWrapper(RegHL.Word), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x9F: // SBC A, A - RegAF.Word = TableALU[3, RegAF.High, RegAF.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA0: // AND B - RegAF.Word = TableALU[4, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA1: // AND C - RegAF.Word = TableALU[4, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA2: // AND D - RegAF.Word = TableALU[4, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA3: // AND E - RegAF.Word = TableALU[4, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA4: // AND H - RegAF.Word = TableALU[4, RegAF.High, RegHL.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA5: // AND L - RegAF.Word = TableALU[4, RegAF.High, RegHL.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA6: // AND (HL) - RegAF.Word = TableALU[4, RegAF.High, ReadMemoryWrapper(RegHL.Word), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xA7: // AND A - RegAF.Word = TableALU[4, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA8: // XOR B - RegAF.Word = TableALU[5, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA9: // XOR C - RegAF.Word = TableALU[5, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAA: // XOR D - RegAF.Word = TableALU[5, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAB: // XOR E - RegAF.Word = TableALU[5, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAC: // XOR H - RegAF.Word = TableALU[5, RegAF.High, RegHL.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAD: // XOR L - RegAF.Word = TableALU[5, RegAF.High, RegHL.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAE: // XOR (HL) - RegAF.Word = TableALU[5, RegAF.High, ReadMemoryWrapper(RegHL.Word), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xAF: // XOR A - RegAF.Word = TableALU[5, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB0: // OR B - RegAF.Word = TableALU[6, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB1: // OR C - RegAF.Word = TableALU[6, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB2: // OR D - RegAF.Word = TableALU[6, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB3: // OR E - RegAF.Word = TableALU[6, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB4: // OR H - RegAF.Word = TableALU[6, RegAF.High, RegHL.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB5: // OR L - RegAF.Word = TableALU[6, RegAF.High, RegHL.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB6: // OR (HL) - RegAF.Word = TableALU[6, RegAF.High, ReadMemoryWrapper(RegHL.Word), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xB7: // OR A - RegAF.Word = TableALU[6, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB8: // CP B - RegAF.Word = TableALU[7, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB9: // CP C - RegAF.Word = TableALU[7, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBA: // CP D - RegAF.Word = TableALU[7, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBB: // CP E - RegAF.Word = TableALU[7, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBC: // CP H - RegAF.Word = TableALU[7, RegAF.High, RegHL.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBD: // CP L - RegAF.Word = TableALU[7, RegAF.High, RegHL.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBE: // CP (HL) - RegAF.Word = TableALU[7, RegAF.High, ReadMemoryWrapper(RegHL.Word), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xBF: // CP A - RegAF.Word = TableALU[7, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC0: // RET NZ - if (!RegFlagZ) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xC1: // POP BC - RegBC.Low = ReadMemoryWrapper(RegSP.Word++); RegBC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC2: // JP NZ, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagZ) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC3: // JP nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - RegPC.Word = TUS; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC4: // CALL NZ, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagZ) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xC5: // PUSH BC - WriteMemoryWrapper(--RegSP.Word, RegBC.High); WriteMemoryWrapper(--RegSP.Word, RegBC.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xC6: // ADD A, n - RegAF.Word = TableALU[0, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xC7: // RST $00 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x00; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xC8: // RET Z - if (RegFlagZ) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xC9: // RET - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xCA: // JP Z, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagZ) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xCB: // (Prefix) - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // RLC B - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x01: // RLC C - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x02: // RLC D - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x03: // RLC E - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x04: // RLC H - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x05: // RLC L - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x06: // RLC (HL) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x07: // RLC A - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x08: // RRC B - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x09: // RRC C - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x0A: // RRC D - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x0B: // RRC E - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x0C: // RRC H - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x0D: // RRC L - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x0E: // RRC (HL) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x0F: // RRC A - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x10: // RL B - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x11: // RL C - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x12: // RL D - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x13: // RL E - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x14: // RL H - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x15: // RL L - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x16: // RL (HL) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x17: // RL A - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x18: // RR B - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x19: // RR C - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x1A: // RR D - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x1B: // RR E - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x1C: // RR H - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x1D: // RR L - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x1E: // RR (HL) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x1F: // RR A - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x20: // SLA B - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x21: // SLA C - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x22: // SLA D - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x23: // SLA E - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x24: // SLA H - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x25: // SLA L - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x26: // SLA (HL) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x27: // SLA A - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x28: // SRA B - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x29: // SRA C - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2A: // SRA D - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2B: // SRA E - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2C: // SRA H - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2D: // SRA L - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2E: // SRA (HL) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x2F: // SRA A - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x30: // SL1 B - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x31: // SL1 C - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x32: // SL1 D - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x33: // SL1 E - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x34: // SL1 H - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x35: // SL1 L - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x36: // SL1 (HL) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x37: // SL1 A - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x38: // SRL B - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x39: // SRL C - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x3A: // SRL D - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x3B: // SRL E - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x3C: // SRL H - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x3D: // SRL L - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x3E: // SRL (HL) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x3F: // SRL A - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x40: // BIT 0, B - RegFlagZ = (RegBC.High & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x41: // BIT 0, C - RegFlagZ = (RegBC.Low & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x42: // BIT 0, D - RegFlagZ = (RegDE.High & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x43: // BIT 0, E - RegFlagZ = (RegDE.Low & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x44: // BIT 0, H - RegFlagZ = (RegHL.High & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x45: // BIT 0, L - RegFlagZ = (RegHL.Low & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x46: // BIT 0, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x47: // BIT 0, A - RegFlagZ = (RegAF.High & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x48: // BIT 1, B - RegFlagZ = (RegBC.High & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x49: // BIT 1, C - RegFlagZ = (RegBC.Low & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4A: // BIT 1, D - RegFlagZ = (RegDE.High & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4B: // BIT 1, E - RegFlagZ = (RegDE.Low & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4C: // BIT 1, H - RegFlagZ = (RegHL.High & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4D: // BIT 1, L - RegFlagZ = (RegHL.Low & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4E: // BIT 1, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x4F: // BIT 1, A - RegFlagZ = (RegAF.High & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x50: // BIT 2, B - RegFlagZ = (RegBC.High & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x51: // BIT 2, C - RegFlagZ = (RegBC.Low & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x52: // BIT 2, D - RegFlagZ = (RegDE.High & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x53: // BIT 2, E - RegFlagZ = (RegDE.Low & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x54: // BIT 2, H - RegFlagZ = (RegHL.High & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x55: // BIT 2, L - RegFlagZ = (RegHL.Low & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x56: // BIT 2, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x57: // BIT 2, A - RegFlagZ = (RegAF.High & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x58: // BIT 3, B - RegFlagZ = (RegBC.High & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x59: // BIT 3, C - RegFlagZ = (RegBC.Low & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5A: // BIT 3, D - RegFlagZ = (RegDE.High & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5B: // BIT 3, E - RegFlagZ = (RegDE.Low & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5C: // BIT 3, H - RegFlagZ = (RegHL.High & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5D: // BIT 3, L - RegFlagZ = (RegHL.Low & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5E: // BIT 3, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x5F: // BIT 3, A - RegFlagZ = (RegAF.High & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x60: // BIT 4, B - RegFlagZ = (RegBC.High & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x61: // BIT 4, C - RegFlagZ = (RegBC.Low & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x62: // BIT 4, D - RegFlagZ = (RegDE.High & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x63: // BIT 4, E - RegFlagZ = (RegDE.Low & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x64: // BIT 4, H - RegFlagZ = (RegHL.High & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x65: // BIT 4, L - RegFlagZ = (RegHL.Low & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x66: // BIT 4, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x67: // BIT 4, A - RegFlagZ = (RegAF.High & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x68: // BIT 5, B - RegFlagZ = (RegBC.High & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x69: // BIT 5, C - RegFlagZ = (RegBC.Low & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6A: // BIT 5, D - RegFlagZ = (RegDE.High & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6B: // BIT 5, E - RegFlagZ = (RegDE.Low & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6C: // BIT 5, H - RegFlagZ = (RegHL.High & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6D: // BIT 5, L - RegFlagZ = (RegHL.Low & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6E: // BIT 5, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x6F: // BIT 5, A - RegFlagZ = (RegAF.High & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x70: // BIT 6, B - RegFlagZ = (RegBC.High & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x71: // BIT 6, C - RegFlagZ = (RegBC.Low & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x72: // BIT 6, D - RegFlagZ = (RegDE.High & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x73: // BIT 6, E - RegFlagZ = (RegDE.Low & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x74: // BIT 6, H - RegFlagZ = (RegHL.High & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x75: // BIT 6, L - RegFlagZ = (RegHL.Low & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x76: // BIT 6, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x77: // BIT 6, A - RegFlagZ = (RegAF.High & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x78: // BIT 7, B - RegFlagZ = (RegBC.High & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x79: // BIT 7, C - RegFlagZ = (RegBC.Low & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7A: // BIT 7, D - RegFlagZ = (RegDE.High & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7B: // BIT 7, E - RegFlagZ = (RegDE.Low & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7C: // BIT 7, H - RegFlagZ = (RegHL.High & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7D: // BIT 7, L - RegFlagZ = (RegHL.Low & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7E: // BIT 7, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x7F: // BIT 7, A - RegFlagZ = (RegAF.High & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x80: // RES 0, B - RegBC.High &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x81: // RES 0, C - RegBC.Low &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x82: // RES 0, D - RegDE.High &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x83: // RES 0, E - RegDE.Low &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x84: // RES 0, H - RegHL.High &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x85: // RES 0, L - RegHL.Low &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x86: // RES 0, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x01))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x87: // RES 0, A - RegAF.High &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x88: // RES 1, B - RegBC.High &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x89: // RES 1, C - RegBC.Low &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8A: // RES 1, D - RegDE.High &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8B: // RES 1, E - RegDE.Low &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8C: // RES 1, H - RegHL.High &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8D: // RES 1, L - RegHL.Low &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8E: // RES 1, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x02))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x8F: // RES 1, A - RegAF.High &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x90: // RES 2, B - RegBC.High &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x91: // RES 2, C - RegBC.Low &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x92: // RES 2, D - RegDE.High &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x93: // RES 2, E - RegDE.Low &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x94: // RES 2, H - RegHL.High &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x95: // RES 2, L - RegHL.Low &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x96: // RES 2, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x04))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x97: // RES 2, A - RegAF.High &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x98: // RES 3, B - RegBC.High &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x99: // RES 3, C - RegBC.Low &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9A: // RES 3, D - RegDE.High &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9B: // RES 3, E - RegDE.Low &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9C: // RES 3, H - RegHL.High &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9D: // RES 3, L - RegHL.Low &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9E: // RES 3, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x08))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x9F: // RES 3, A - RegAF.High &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA0: // RES 4, B - RegBC.High &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA1: // RES 4, C - RegBC.Low &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA2: // RES 4, D - RegDE.High &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA3: // RES 4, E - RegDE.Low &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA4: // RES 4, H - RegHL.High &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA5: // RES 4, L - RegHL.Low &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA6: // RES 4, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x10))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xA7: // RES 4, A - RegAF.High &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA8: // RES 5, B - RegBC.High &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA9: // RES 5, C - RegBC.Low &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAA: // RES 5, D - RegDE.High &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAB: // RES 5, E - RegDE.Low &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAC: // RES 5, H - RegHL.High &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAD: // RES 5, L - RegHL.Low &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAE: // RES 5, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x20))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xAF: // RES 5, A - RegAF.High &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB0: // RES 6, B - RegBC.High &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB1: // RES 6, C - RegBC.Low &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB2: // RES 6, D - RegDE.High &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB3: // RES 6, E - RegDE.Low &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB4: // RES 6, H - RegHL.High &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB5: // RES 6, L - RegHL.Low &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB6: // RES 6, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x40))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xB7: // RES 6, A - RegAF.High &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB8: // RES 7, B - RegBC.High &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB9: // RES 7, C - RegBC.Low &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBA: // RES 7, D - RegDE.High &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBB: // RES 7, E - RegDE.Low &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBC: // RES 7, H - RegHL.High &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBD: // RES 7, L - RegHL.Low &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBE: // RES 7, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x80))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xBF: // RES 7, A - RegAF.High &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC0: // SET 0, B - RegBC.High |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC1: // SET 0, C - RegBC.Low |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC2: // SET 0, D - RegDE.High |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC3: // SET 0, E - RegDE.Low |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC4: // SET 0, H - RegHL.High |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC5: // SET 0, L - RegHL.Low |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC6: // SET 0, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x01))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xC7: // SET 0, A - RegAF.High |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC8: // SET 1, B - RegBC.High |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC9: // SET 1, C - RegBC.Low |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xCA: // SET 1, D - RegDE.High |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xCB: // SET 1, E - RegDE.Low |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xCC: // SET 1, H - RegHL.High |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xCD: // SET 1, L - RegHL.Low |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xCE: // SET 1, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x02))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xCF: // SET 1, A - RegAF.High |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD0: // SET 2, B - RegBC.High |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD1: // SET 2, C - RegBC.Low |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD2: // SET 2, D - RegDE.High |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD3: // SET 2, E - RegDE.Low |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD4: // SET 2, H - RegHL.High |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD5: // SET 2, L - RegHL.Low |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD6: // SET 2, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x04))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xD7: // SET 2, A - RegAF.High |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD8: // SET 3, B - RegBC.High |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD9: // SET 3, C - RegBC.Low |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xDA: // SET 3, D - RegDE.High |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xDB: // SET 3, E - RegDE.Low |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xDC: // SET 3, H - RegHL.High |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xDD: // SET 3, L - RegHL.Low |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xDE: // SET 3, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x08))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xDF: // SET 3, A - RegAF.High |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE0: // SET 4, B - RegBC.High |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE1: // SET 4, C - RegBC.Low |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE2: // SET 4, D - RegDE.High |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE3: // SET 4, E - RegDE.Low |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE4: // SET 4, H - RegHL.High |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE5: // SET 4, L - RegHL.Low |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE6: // SET 4, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x10))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xE7: // SET 4, A - RegAF.High |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE8: // SET 5, B - RegBC.High |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE9: // SET 5, C - RegBC.Low |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xEA: // SET 5, D - RegDE.High |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xEB: // SET 5, E - RegDE.Low |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xEC: // SET 5, H - RegHL.High |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xED: // SET 5, L - RegHL.Low |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xEE: // SET 5, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x20))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xEF: // SET 5, A - RegAF.High |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF0: // SET 6, B - RegBC.High |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF1: // SET 6, C - RegBC.Low |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF2: // SET 6, D - RegDE.High |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF3: // SET 6, E - RegDE.Low |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF4: // SET 6, H - RegHL.High |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF5: // SET 6, L - RegHL.Low |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF6: // SET 6, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x40))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xF7: // SET 6, A - RegAF.High |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF8: // SET 7, B - RegBC.High |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF9: // SET 7, C - RegBC.Low |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xFA: // SET 7, D - RegDE.High |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xFB: // SET 7, E - RegDE.Low |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xFC: // SET 7, H - RegHL.High |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xFD: // SET 7, L - RegHL.Low |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xFE: // SET 7, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x80))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xFF: // SET 7, A - RegAF.High |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - } - break; - case 0xCC: // CALL Z, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagZ) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xCD: // CALL nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - break; - case 0xCE: // ADC A, n - RegAF.Word = TableALU[1, RegAF.High, FetchMemoryWrapper(RegPC.Word++), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xCF: // RST $08 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x08; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD0: // RET NC - if (!RegFlagC) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xD1: // POP DE - RegDE.Low = ReadMemoryWrapper(RegSP.Word++); RegDE.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xD2: // JP NC, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagC) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xD3: // OUT n, A - WriteHardware(FetchMemoryWrapper(RegPC.Word++), RegAF.High); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD4: // CALL NC, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xD5: // PUSH DE - WriteMemoryWrapper(--RegSP.Word, RegDE.High); WriteMemoryWrapper(--RegSP.Word, RegDE.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD6: // SUB n - RegAF.Word = TableALU[2, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xD7: // RST $10 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x10; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD8: // RET C - if (RegFlagC) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xD9: // EXX - TUS = RegBC.Word; RegBC.Word = RegAltBC.Word; RegAltBC.Word = TUS; - TUS = RegDE.Word; RegDE.Word = RegAltDE.Word; RegAltDE.Word = TUS; - TUS = RegHL.Word; RegHL.Word = RegAltHL.Word; RegAltHL.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDA: // JP C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xDB: // IN A, n - RegAF.High = ReadHardware((ushort)FetchMemoryWrapper(RegPC.Word++)); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xDC: // CALL C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xDD: // (Prefix) - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x01: // LD BC, nn - RegBC.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x02: // LD (BC), A - RegWZ.Low = (byte)((RegBC.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegBC.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x03: // INC BC - ++RegBC.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x04: // INC B - RegAF.Low = (byte)(TableInc[++RegBC.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x05: // DEC B - RegAF.Low = (byte)(TableDec[--RegBC.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x06: // LD B, n - RegBC.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x07: // RLCA - RegAF.Word = TableRotShift[0, 0, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x08: // EX AF, AF' - TUS = RegAF.Word; RegAF.Word = RegAltAF.Word; RegAltAF.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x09: // ADD IX, BC - RegWZ = (ushort)(RegIX + 1); - TI1 = (short)RegIX.Word; TI2 = (short)RegBC.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIX.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x0A: // LD A, (BC) - RegAF.High = ReadMemoryWrapper(RegBC.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegBC.Word + 1); - break; - case 0x0B: // DEC BC - --RegBC.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x0C: // INC C - RegAF.Low = (byte)(TableInc[++RegBC.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0D: // DEC C - RegAF.Low = (byte)(TableDec[--RegBC.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0E: // LD C, n - RegBC.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x0F: // RRCA - RegAF.Word = TableRotShift[0, 1, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x10: // DJNZ d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (--RegBC.High != 0) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 13; pendingCycles -= 13; - } - else - { - totalExecutedCycles += 8; pendingCycles -= 8; - } - break; - case 0x11: // LD DE, nn - RegDE.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x12: // LD (DE), A - RegWZ.Low = (byte)((RegDE.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegDE.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x13: // INC DE - ++RegDE.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x14: // INC D - RegAF.Low = (byte)(TableInc[++RegDE.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x15: // DEC D - RegAF.Low = (byte)(TableDec[--RegDE.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x16: // LD D, n - RegDE.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x17: // RLA - RegAF.Word = TableRotShift[0, 2, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x18: // JR d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x19: // ADD IX, DE - RegWZ = (ushort)(RegIX + 1); - TI1 = (short)RegIX.Word; TI2 = (short)RegDE.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIX.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x1A: // LD A, (DE) - RegAF.High = ReadMemoryWrapper(RegDE.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegDE.Word + 1); - break; - case 0x1B: // DEC DE - --RegDE.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x1C: // INC E - RegAF.Low = (byte)(TableInc[++RegDE.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1D: // DEC E - RegAF.Low = (byte)(TableDec[--RegDE.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1E: // LD E, n - RegDE.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x1F: // RRA - RegAF.Word = TableRotShift[0, 3, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x20: // JR NZ, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (!RegFlagZ) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x21: // LD IX, nn - RegIX.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x22: // LD (nn), IX - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegIX.Low); - WriteMemoryWrapper(TUS, RegIX.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x23: // INC IX - ++RegIX.Word; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x24: // INC IXH - RegAF.Low = (byte)(TableInc[++RegIX.High] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x25: // DEC IXH - RegAF.Low = (byte)(TableDec[--RegIX.High] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x26: // LD IXH, n - RegIX.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x27: // DAA - RegAF.Word = TableDaa[RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x28: // JR Z, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (RegFlagZ) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x29: // ADD IX, IX - RegWZ = (ushort)(RegIX + 1); - TI1 = (short)RegIX.Word; TI2 = (short)RegIX.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIX.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x2A: // LD IX, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegIX.Low = ReadMemoryWrapper(TUS++); RegIX.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x2B: // DEC IX - --RegIX.Word; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x2C: // INC IXL - RegAF.Low = (byte)(TableInc[++RegIX.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2D: // DEC IXL - RegAF.Low = (byte)(TableDec[--RegIX.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2E: // LD IXL, n - RegIX.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x2F: // CPL - RegAF.High ^= 0xFF; RegFlagH = true; RegFlagN = true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x30: // JR NC, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (!RegFlagC) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x31: // LD SP, nn - RegSP.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x32: // LD (nn), A - temp_WZ = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ.Low = (byte)((temp_WZ + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(temp_WZ, RegAF.High); - totalExecutedCycles += 13; pendingCycles -= 13; - break; - case 0x33: // INC SP - ++RegSP.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x34: // INC (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - TB = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); RegAF.Low = (byte)(TableInc[++TB] | (RegAF.Low & 1)); WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), TB); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x35: // DEC (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - TB = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); RegAF.Low = (byte)(TableDec[--TB] | (RegAF.Low & 1)); WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), TB); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x36: // LD (IX+d), n - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), FetchMemoryWrapper(RegPC.Word++)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x37: // SCF - RegFlagH = false; RegFlagN = false; RegFlagC = true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x38: // JR C, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (RegFlagC) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x39: // ADD IX, SP - RegWZ = (ushort)(RegIX + 1); - TI1 = (short)RegIX.Word; TI2 = (short)RegSP.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIX.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x3A: // LD A, (nn) - temp_WZ = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegAF.High = ReadMemoryWrapper(temp_WZ); - totalExecutedCycles += 13; pendingCycles -= 13; - RegWZ = (ushort)(temp_WZ + 1); - break; - case 0x3B: // DEC SP - --RegSP.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x3C: // INC A - RegAF.Low = (byte)(TableInc[++RegAF.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3D: // DEC A - RegAF.Low = (byte)(TableDec[--RegAF.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3E: // LD A, n - RegAF.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x3F: // CCF - RegFlagH = RegFlagC; RegFlagN = false; RegFlagC ^= true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x40: // LD B, B - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x41: // LD B, C - RegBC.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x42: // LD B, D - RegBC.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x43: // LD B, E - RegBC.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x44: // LD B, IXH - RegBC.High = RegIX.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x45: // LD B, IXL - RegBC.High = RegIX.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x46: // LD B, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegBC.High = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x47: // LD B, A - RegBC.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x48: // LD C, B - RegBC.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x49: // LD C, C - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4A: // LD C, D - RegBC.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4B: // LD C, E - RegBC.Low = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4C: // LD C, IXH - RegBC.Low = RegIX.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4D: // LD C, IXL - RegBC.Low = RegIX.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4E: // LD C, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegBC.Low = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x4F: // LD C, A - RegBC.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x50: // LD D, B - RegDE.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x51: // LD D, C - RegDE.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x52: // LD D, D - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x53: // LD D, E - RegDE.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x54: // LD D, IXH - RegDE.High = RegIX.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x55: // LD D, IXL - RegDE.High = RegIX.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x56: // LD D, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegDE.High = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x57: // LD D, A - RegDE.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x58: // LD E, B - RegDE.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x59: // LD E, C - RegDE.Low = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5A: // LD E, D - RegDE.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5B: // LD E, E - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5C: // LD E, IXH - RegDE.Low = RegIX.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5D: // LD E, IXL - RegDE.Low = RegIX.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5E: // LD E, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegDE.Low = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x5F: // LD E, A - RegDE.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x60: // LD IXH, B - RegIX.High = RegBC.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x61: // LD IXH, C - RegIX.High = RegBC.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x62: // LD IXH, D - RegIX.High = RegDE.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x63: // LD IXH, E - RegIX.High = RegDE.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x64: // LD IXH, IXH - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x65: // LD IXH, IXL - RegIX.High = RegIX.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x66: // LD H, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegHL.High = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x67: // LD IXH, A - RegIX.High = RegAF.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x68: // LD IXL, B - RegIX.Low = RegBC.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x69: // LD IXL, C - RegIX.Low = RegBC.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6A: // LD IXL, D - RegIX.Low = RegDE.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6B: // LD IXL, E - RegIX.Low = RegDE.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6C: // LD IXL, IXH - RegIX.Low = RegIX.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6D: // LD IXL, IXL - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6E: // LD L, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegHL.Low = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x6F: // LD IXL, A - RegIX.Low = RegAF.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x70: // LD (IX+d), B - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x71: // LD (IX+d), C - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x72: // LD (IX+d), D - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x73: // LD (IX+d), E - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x74: // LD (IX+d), H - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x75: // LD (IX+d), L - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x76: // HALT - Halt(); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x77: // LD (IX+d), A - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x78: // LD A, B - RegAF.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x79: // LD A, C - RegAF.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7A: // LD A, D - RegAF.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7B: // LD A, E - RegAF.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7C: // LD A, IXH - RegAF.High = RegIX.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7D: // LD A, IXL - RegAF.High = RegIX.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7E: // LD A, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.High = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x7F: // LD A, A - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x80: // ADD A, B - RegAF.Word = TableALU[0, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x81: // ADD A, C - RegAF.Word = TableALU[0, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x82: // ADD A, D - RegAF.Word = TableALU[0, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x83: // ADD A, E - RegAF.Word = TableALU[0, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x84: // ADD A, IXH - RegAF.Word = TableALU[0, RegAF.High, RegIX.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x85: // ADD A, IXL - RegAF.Word = TableALU[0, RegAF.High, RegIX.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x86: // ADD A, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[0, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x87: // ADD A, A - RegAF.Word = TableALU[0, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x88: // ADC A, B - RegAF.Word = TableALU[1, RegAF.High, RegBC.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x89: // ADC A, C - RegAF.Word = TableALU[1, RegAF.High, RegBC.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8A: // ADC A, D - RegAF.Word = TableALU[1, RegAF.High, RegDE.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8B: // ADC A, E - RegAF.Word = TableALU[1, RegAF.High, RegDE.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8C: // ADC A, IXH - RegAF.Word = TableALU[1, RegAF.High, RegIX.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8D: // ADC A, IXL - RegAF.Word = TableALU[1, RegAF.High, RegIX.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8E: // ADC A, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[1, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), RegFlagC ? 1 : 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x8F: // ADC A, A - RegAF.Word = TableALU[1, RegAF.High, RegAF.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x90: // SUB B - RegAF.Word = TableALU[2, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x91: // SUB C - RegAF.Word = TableALU[2, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x92: // SUB D - RegAF.Word = TableALU[2, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x93: // SUB E - RegAF.Word = TableALU[2, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x94: // SUB IXH - RegAF.Word = TableALU[2, RegAF.High, RegIX.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x95: // SUB IXL - RegAF.Word = TableALU[2, RegAF.High, RegIX.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x96: // SUB (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[2, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x97: // SUB A, A - RegAF.Word = TableALU[2, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x98: // SBC A, B - RegAF.Word = TableALU[3, RegAF.High, RegBC.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x99: // SBC A, C - RegAF.Word = TableALU[3, RegAF.High, RegBC.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9A: // SBC A, D - RegAF.Word = TableALU[3, RegAF.High, RegDE.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9B: // SBC A, E - RegAF.Word = TableALU[3, RegAF.High, RegDE.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9C: // SBC A, IXH - RegAF.Word = TableALU[3, RegAF.High, RegIX.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9D: // SBC A, IXL - RegAF.Word = TableALU[3, RegAF.High, RegIX.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9E: // SBC A, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[3, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), RegFlagC ? 1 : 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x9F: // SBC A, A - RegAF.Word = TableALU[3, RegAF.High, RegAF.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA0: // AND B - RegAF.Word = TableALU[4, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA1: // AND C - RegAF.Word = TableALU[4, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA2: // AND D - RegAF.Word = TableALU[4, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA3: // AND E - RegAF.Word = TableALU[4, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA4: // AND IXH - RegAF.Word = TableALU[4, RegAF.High, RegIX.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA5: // AND IXL - RegAF.Word = TableALU[4, RegAF.High, RegIX.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA6: // AND (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[4, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xA7: // AND A - RegAF.Word = TableALU[4, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA8: // XOR B - RegAF.Word = TableALU[5, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA9: // XOR C - RegAF.Word = TableALU[5, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAA: // XOR D - RegAF.Word = TableALU[5, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAB: // XOR E - RegAF.Word = TableALU[5, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAC: // XOR IXH - RegAF.Word = TableALU[5, RegAF.High, RegIX.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAD: // XOR IXL - RegAF.Word = TableALU[5, RegAF.High, RegIX.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAE: // XOR (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[5, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xAF: // XOR A - RegAF.Word = TableALU[5, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB0: // OR B - RegAF.Word = TableALU[6, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB1: // OR C - RegAF.Word = TableALU[6, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB2: // OR D - RegAF.Word = TableALU[6, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB3: // OR E - RegAF.Word = TableALU[6, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB4: // OR IXH - RegAF.Word = TableALU[6, RegAF.High, RegIX.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB5: // OR IXL - RegAF.Word = TableALU[6, RegAF.High, RegIX.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB6: // OR (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[6, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xB7: // OR A - RegAF.Word = TableALU[6, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB8: // CP B - RegAF.Word = TableALU[7, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB9: // CP C - RegAF.Word = TableALU[7, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBA: // CP D - RegAF.Word = TableALU[7, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBB: // CP E - RegAF.Word = TableALU[7, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBC: // CP IXH - RegAF.Word = TableALU[7, RegAF.High, RegIX.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBD: // CP IXL - RegAF.Word = TableALU[7, RegAF.High, RegIX.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBE: // CP (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[7, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xBF: // CP A - RegAF.Word = TableALU[7, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC0: // RET NZ - if (!RegFlagZ) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xC1: // POP BC - RegBC.Low = ReadMemoryWrapper(RegSP.Word++); RegBC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC2: // JP NZ, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagZ) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC3: // JP nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - RegPC.Word = TUS; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC4: // CALL NZ, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagZ) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xC5: // PUSH BC - WriteMemoryWrapper(--RegSP.Word, RegBC.High); WriteMemoryWrapper(--RegSP.Word, RegBC.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xC6: // ADD A, n - RegAF.Word = TableALU[0, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xC7: // RST $00 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x00; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xC8: // RET Z - if (RegFlagZ) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xC9: // RET - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xCA: // JP Z, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagZ) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xCB: // (Prefix) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // RLC (IX+d)→B - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x01: // RLC (IX+d)→C - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x02: // RLC (IX+d)→D - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x03: // RLC (IX+d)→E - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x04: // RLC (IX+d)→H - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x05: // RLC (IX+d)→L - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x06: // RLC (IX+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x07: // RLC (IX+d)→A - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x08: // RRC (IX+d)→B - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x09: // RRC (IX+d)→C - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0A: // RRC (IX+d)→D - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0B: // RRC (IX+d)→E - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0C: // RRC (IX+d)→H - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0D: // RRC (IX+d)→L - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0E: // RRC (IX+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0F: // RRC (IX+d)→A - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x10: // RL (IX+d)→B - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x11: // RL (IX+d)→C - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x12: // RL (IX+d)→D - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x13: // RL (IX+d)→E - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x14: // RL (IX+d)→H - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x15: // RL (IX+d)→L - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x16: // RL (IX+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x17: // RL (IX+d)→A - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x18: // RR (IX+d)→B - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x19: // RR (IX+d)→C - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1A: // RR (IX+d)→D - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1B: // RR (IX+d)→E - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1C: // RR (IX+d)→H - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1D: // RR (IX+d)→L - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1E: // RR (IX+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1F: // RR (IX+d)→A - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x20: // SLA (IX+d)→B - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x21: // SLA (IX+d)→C - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x22: // SLA (IX+d)→D - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x23: // SLA (IX+d)→E - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x24: // SLA (IX+d)→H - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x25: // SLA (IX+d)→L - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x26: // SLA (IX+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x27: // SLA (IX+d)→A - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x28: // SRA (IX+d)→B - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x29: // SRA (IX+d)→C - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2A: // SRA (IX+d)→D - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2B: // SRA (IX+d)→E - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2C: // SRA (IX+d)→H - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2D: // SRA (IX+d)→L - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2E: // SRA (IX+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2F: // SRA (IX+d)→A - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x30: // SL1 (IX+d)→B - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x31: // SL1 (IX+d)→C - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x32: // SL1 (IX+d)→D - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x33: // SL1 (IX+d)→E - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x34: // SL1 (IX+d)→H - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x35: // SL1 (IX+d)→L - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x36: // SL1 (IX+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x37: // SL1 (IX+d)→A - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x38: // SRL (IX+d)→B - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x39: // SRL (IX+d)→C - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3A: // SRL (IX+d)→D - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3B: // SRL (IX+d)→E - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3C: // SRL (IX+d)→H - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3D: // SRL (IX+d)→L - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3E: // SRL (IX+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3F: // SRL (IX+d)→A - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x40: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x41: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x42: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x43: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x44: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x45: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x46: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x47: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x48: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x49: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4A: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4B: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4C: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4D: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4E: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4F: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x50: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x51: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x52: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x53: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x54: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x55: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x56: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x57: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x58: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x59: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5A: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5B: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5C: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5D: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5E: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5F: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x60: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x61: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x62: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x63: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x64: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x65: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x66: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x67: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x68: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x69: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6A: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6B: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6C: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6D: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6E: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6F: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x70: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x71: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x72: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x73: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x74: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x75: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x76: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x77: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x78: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x79: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7A: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7B: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7C: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7D: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7E: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7F: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x80: // RES 0, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x81: // RES 0, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x82: // RES 0, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x83: // RES 0, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x84: // RES 0, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x85: // RES 0, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x86: // RES 0, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x87: // RES 0, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x88: // RES 1, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x89: // RES 1, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8A: // RES 1, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8B: // RES 1, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8C: // RES 1, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8D: // RES 1, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8E: // RES 1, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8F: // RES 1, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x90: // RES 2, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x91: // RES 2, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x92: // RES 2, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x93: // RES 2, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x94: // RES 2, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x95: // RES 2, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x96: // RES 2, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x97: // RES 2, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x98: // RES 3, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x99: // RES 3, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9A: // RES 3, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9B: // RES 3, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9C: // RES 3, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9D: // RES 3, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9E: // RES 3, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9F: // RES 3, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA0: // RES 4, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA1: // RES 4, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA2: // RES 4, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA3: // RES 4, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA4: // RES 4, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA5: // RES 4, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA6: // RES 4, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA7: // RES 4, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA8: // RES 5, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA9: // RES 5, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAA: // RES 5, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAB: // RES 5, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAC: // RES 5, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAD: // RES 5, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAE: // RES 5, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAF: // RES 5, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB0: // RES 6, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB1: // RES 6, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB2: // RES 6, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB3: // RES 6, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB4: // RES 6, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB5: // RES 6, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB6: // RES 6, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB7: // RES 6, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB8: // RES 7, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB9: // RES 7, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBA: // RES 7, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBB: // RES 7, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBC: // RES 7, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBD: // RES 7, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBE: // RES 7, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBF: // RES 7, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC0: // SET 0, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC1: // SET 0, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC2: // SET 0, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC3: // SET 0, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC4: // SET 0, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC5: // SET 0, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC6: // SET 0, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC7: // SET 0, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC8: // SET 1, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC9: // SET 1, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCA: // SET 1, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCB: // SET 1, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCC: // SET 1, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCD: // SET 1, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCE: // SET 1, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCF: // SET 1, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD0: // SET 2, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD1: // SET 2, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD2: // SET 2, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD3: // SET 2, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD4: // SET 2, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD5: // SET 2, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD6: // SET 2, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD7: // SET 2, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD8: // SET 3, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD9: // SET 3, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDA: // SET 3, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDB: // SET 3, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDC: // SET 3, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDD: // SET 3, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDE: // SET 3, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDF: // SET 3, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE0: // SET 4, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE1: // SET 4, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE2: // SET 4, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE3: // SET 4, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE4: // SET 4, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE5: // SET 4, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE6: // SET 4, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE7: // SET 4, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE8: // SET 5, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE9: // SET 5, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEA: // SET 5, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEB: // SET 5, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEC: // SET 5, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xED: // SET 5, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEE: // SET 5, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEF: // SET 5, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF0: // SET 6, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF1: // SET 6, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF2: // SET 6, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF3: // SET 6, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF4: // SET 6, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF5: // SET 6, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF6: // SET 6, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF7: // SET 6, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF8: // SET 7, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF9: // SET 7, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFA: // SET 7, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFB: // SET 7, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFC: // SET 7, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFD: // SET 7, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFE: // SET 7, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFF: // SET 7, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - } - break; - case 0xCC: // CALL Z, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagZ) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xCD: // CALL nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - break; - case 0xCE: // ADC A, n - RegAF.Word = TableALU[1, RegAF.High, FetchMemoryWrapper(RegPC.Word++), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xCF: // RST $08 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x08; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD0: // RET NC - if (!RegFlagC) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xD1: // POP DE - RegDE.Low = ReadMemoryWrapper(RegSP.Word++); RegDE.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xD2: // JP NC, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagC) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xD3: // OUT n, A - WriteHardware(FetchMemoryWrapper(RegPC.Word++), RegAF.High); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD4: // CALL NC, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xD5: // PUSH DE - WriteMemoryWrapper(--RegSP.Word, RegDE.High); WriteMemoryWrapper(--RegSP.Word, RegDE.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD6: // SUB n - RegAF.Word = TableALU[2, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xD7: // RST $10 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x10; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD8: // RET C - if (RegFlagC) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xD9: // EXX - TUS = RegBC.Word; RegBC.Word = RegAltBC.Word; RegAltBC.Word = TUS; - TUS = RegDE.Word; RegDE.Word = RegAltDE.Word; RegAltDE.Word = TUS; - TUS = RegHL.Word; RegHL.Word = RegAltHL.Word; RegAltHL.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDA: // JP C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xDB: // IN A, n - RegAF.High = ReadHardware((ushort)FetchMemoryWrapper(RegPC.Word++)); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xDC: // CALL C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xDD: // <- - // Invalid sequence. - totalExecutedCycles += 1337; pendingCycles -= 1337; - break; - case 0xDE: // SBC A, n - RegAF.Word = TableALU[3, RegAF.High, FetchMemoryWrapper(RegPC.Word++), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xDF: // RST $18 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x18; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE0: // RET PO - if (!RegFlagP) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xE1: // POP IX - RegIX.Low = ReadMemoryWrapper(RegSP.Word++); RegIX.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0xE2: // JP PO, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagP) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xE3: // EX (SP), IX - TUS = RegSP.Word; TBL = ReadMemoryWrapper(TUS++); TBH = ReadMemoryWrapper(TUS--); - WriteMemoryWrapper(TUS++, RegIX.Low); WriteMemoryWrapper(TUS, RegIX.High); - RegIX.Low = TBL; RegIX.High = TBH; - RegWZ = RegIX; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE4: // CALL C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xE5: // PUSH IX - WriteMemoryWrapper(--RegSP.Word, RegIX.High); WriteMemoryWrapper(--RegSP.Word, RegIX.Low); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xE6: // AND n - RegAF.Word = TableALU[4, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xE7: // RST $20 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x20; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE8: // RET PE - if (RegFlagP) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xE9: // JP IX - RegWZ = RegIX; - RegPC.Word = RegIX.Word; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xEA: // JP PE, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagP) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xEB: // EX DE, HL - TUS = RegDE.Word; RegDE.Word = RegHL.Word; RegHL.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEC: // CALL PE, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagP) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xED: // (Prefix) - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x01: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x02: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x03: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x04: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x05: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x06: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x07: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x08: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x09: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x10: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x11: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x12: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x13: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x14: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x15: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x16: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x17: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x18: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x19: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x20: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x21: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x22: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x23: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x24: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x25: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x26: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x27: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x28: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x29: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x30: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x31: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x32: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x33: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x34: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x35: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x36: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x37: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x38: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x39: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x40: // IN B, C - RegBC.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegBC.High > 127; - RegFlagZ = RegBC.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegBC.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x41: // OUT C, B - WriteHardware(RegBC.Low, RegBC.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x42: // SBC HL, BC - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegBC.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegBC.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x43: // LD (nn), BC - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegBC.Low); - WriteMemoryWrapper(TUS, RegBC.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x44: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x45: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x46: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x47: // LD I, A - RegI = RegAF.High; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x48: // IN C, C - RegBC.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegBC.Low > 127; - RegFlagZ = RegBC.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegBC.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x49: // OUT C, C - WriteHardware(RegBC.Low, RegBC.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x4A: // ADC HL, BC - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x4B: // LD BC, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegBC.Low = ReadMemoryWrapper(TUS++); RegBC.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x4E: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4F: // LD R, A - RegR = RegAF.High; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x50: // IN D, C - RegDE.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegDE.High > 127; - RegFlagZ = RegDE.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegDE.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x51: // OUT C, D - WriteHardware(RegBC.Low, RegDE.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x52: // SBC HL, DE - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegDE.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegDE.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x53: // LD (nn), DE - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegDE.Low); - WriteMemoryWrapper(TUS, RegDE.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x54: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x55: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x56: // IM $1 - interruptMode = 1; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x57: // LD A, I - RegAF.High = RegI; - RegFlagS = RegI > 127; - RegFlagZ = RegI == 0; - RegFlagH = false; - RegFlagN = false; - RegFlagP = IFF2; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x58: // IN E, C - RegDE.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegDE.Low > 127; - RegFlagZ = RegDE.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegDE.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x59: // OUT C, E - WriteHardware(RegBC.Low, RegDE.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x5A: // ADC HL, DE - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x5B: // LD DE, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegDE.Low = ReadMemoryWrapper(TUS++); RegDE.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x5E: // IM $2 - interruptMode = 2; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5F: // LD A, R - RegAF.High = (byte)(RegR & 0x7F); - RegFlagS = (byte)(RegR & 0x7F) > 127; - RegFlagZ = (byte)(RegR & 0x7F) == 0; - RegFlagH = false; - RegFlagN = false; - RegFlagP = IFF2; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x60: // IN H, C - RegHL.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegHL.High > 127; - RegFlagZ = RegHL.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegHL.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x61: // OUT C, H - WriteHardware(RegBC.Low, RegHL.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x62: // SBC HL, HL - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegHL.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegHL.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x63: // LD (nn), HL - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegHL.Low); - WriteMemoryWrapper(TUS, RegHL.High); - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0x64: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x65: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x66: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x67: // RRD - RegWZ = (ushort)(RegHL + 1); - TB1 = RegAF.High; TB2 = ReadMemoryWrapper(RegHL.Word); - WriteMemoryWrapper(RegHL.Word, (byte)((TB2 >> 4) + (TB1 << 4))); - RegAF.High = (byte)((TB1 & 0xF0) + (TB2 & 0x0F)); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - RegFlag3 = (RegAF.High & 0x08) != 0; - RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 18; pendingCycles -= 18; - break; - case 0x68: // IN L, C - RegHL.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegHL.Low > 127; - RegFlagZ = RegHL.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegHL.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x69: // OUT C, L - WriteHardware(RegBC.Low, RegHL.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x6A: // ADC HL, HL - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x6B: // LD HL, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegHL.Low = ReadMemoryWrapper(TUS++); RegHL.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0x6C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x6E: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6F: // RLD - RegWZ = (ushort)(RegHL + 1); - TB1 = RegAF.High; TB2 = ReadMemoryWrapper(RegHL.Word); - WriteMemoryWrapper(RegHL.Word, (byte)((TB1 & 0x0F) + (TB2 << 4))); - RegAF.High = (byte)((TB1 & 0xF0) + (TB2 >> 4)); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - RegFlag3 = (RegAF.High & 0x08) != 0; - RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 18; pendingCycles -= 18; - break; - case 0x70: // IN 0, C - TB = ReadHardware((ushort)RegBC.Low); - RegFlagS = TB > 127; - RegFlagZ = TB == 0; - RegFlagH = false; - RegFlagP = TableParity[TB]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x71: // OUT C, 0 - WriteHardware(RegBC.Low, 0); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x72: // SBC HL, SP - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegSP.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegSP.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x73: // LD (nn), SP - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegSP.Low); - WriteMemoryWrapper(TUS, RegSP.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x74: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x75: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x76: // IM $1 - interruptMode = 1; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x77: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x78: // IN A, C - RegAF.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x79: // OUT C, A - WriteHardware(RegBC.Low, RegAF.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x7A: // ADC HL, SP - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x7B: // LD SP, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegSP.Low = ReadMemoryWrapper(TUS++); RegSP.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x7E: // IM $2 - interruptMode = 2; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x80: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x81: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x82: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x83: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x84: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x85: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x86: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x87: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x88: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x89: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x90: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x91: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x92: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x93: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x94: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x95: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x96: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x97: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x98: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x99: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA0: // LDI - WriteMemoryWrapper(RegDE.Word++, TB1 = ReadMemoryWrapper(RegHL.Word++)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA1: // CPI - RegWZ = (ushort)(RegWZ + 1); - TB1 = ReadMemoryWrapper(RegHL.Word++); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA2: // INI - RegWZ = (ushort)(RegBC + 1); - WriteMemoryWrapper(RegHL.Word++, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA3: // OUTI - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word++)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA8: // LDD - WriteMemoryWrapper(RegDE.Word--, TB1 = ReadMemoryWrapper(RegHL.Word--)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA9: // CPD - RegWZ = (ushort)(RegWZ - 1); - TB1 = ReadMemoryWrapper(RegHL.Word--); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAA: // IND - RegWZ = (ushort)(RegBC - 1); - WriteMemoryWrapper(RegHL.Word--, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAB: // OUTD - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word--)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB0: // LDIR - WriteMemoryWrapper(RegDE.Word++, TB1 = ReadMemoryWrapper(RegHL.Word++)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - if (RegBC.Word != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB1: // CPIR - TB1 = ReadMemoryWrapper(RegHL.Word++); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - if (RegBC.Word != 0 && !RegFlagZ) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB2: // INIR - WriteMemoryWrapper(RegHL.Word++, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB3: // OTIR - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word++)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB8: // LDDR - WriteMemoryWrapper(RegDE.Word--, TB1 = ReadMemoryWrapper(RegHL.Word--)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - if (RegBC.Word != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB9: // CPDR - TB1 = ReadMemoryWrapper(RegHL.Word--); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - if (RegBC.Word != 0 && !RegFlagZ) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBA: // INDR - WriteMemoryWrapper(RegHL.Word--, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBB: // OTDR - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word--)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xED: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - } - break; - case 0xEE: // XOR n - RegAF.Word = TableALU[5, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xEF: // RST $28 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x28; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF0: // RET P - if (!RegFlagS) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xF1: // POP AF - RegAF.Low = ReadMemoryWrapper(RegSP.Word++); RegAF.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xF2: // JP P, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagS) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xF3: // DI - IFF1 = IFF2 = false; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF4: // CALL P, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagS) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xF5: // PUSH AF - WriteMemoryWrapper(--RegSP.Word, RegAF.High); WriteMemoryWrapper(--RegSP.Word, RegAF.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF6: // OR n - RegAF.Word = TableALU[6, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xF7: // RST $30 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x30; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF8: // RET M - if (RegFlagS) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xF9: // LD SP, IX - RegSP.Word = RegIX.Word; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xFA: // JP M, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagS) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xFB: // EI - EI_pending = 2; - Interruptable = false; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFC: // CALL M, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagS) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xFD: // <- - // Invalid sequence. - totalExecutedCycles += 1337; pendingCycles -= 1337; - break; - case 0xFE: // CP n - RegAF.Word = TableALU[7, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xFF: // RST $38 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x38; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - } - break; - case 0xDE: // SBC A, n - RegAF.Word = TableALU[3, RegAF.High, FetchMemoryWrapper(RegPC.Word++), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xDF: // RST $18 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x18; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE0: // RET PO - if (!RegFlagP) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xE1: // POP HL - RegHL.Low = ReadMemoryWrapper(RegSP.Word++); RegHL.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xE2: // JP PO, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagP) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xE3: // EX (SP), HL - TUS = RegSP.Word; TBL = ReadMemoryWrapper(TUS++); TBH = ReadMemoryWrapper(TUS--); - WriteMemoryWrapper(TUS++, RegHL.Low); WriteMemoryWrapper(TUS, RegHL.High); - RegHL.Low = TBL; RegHL.High = TBH; - RegWZ = RegHL; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xE4: // CALL PO, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagP) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xE5: // PUSH HL - WriteMemoryWrapper(--RegSP.Word, RegHL.High); WriteMemoryWrapper(--RegSP.Word, RegHL.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE6: // AND n - RegAF.Word = TableALU[4, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xE7: // RST $20 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x20; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE8: // RET PE - if (RegFlagP) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xE9: // JP HL - RegWZ = RegHL; - RegPC.Word = RegHL.Word; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEA: // JP PE, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagP) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xEB: // EX DE, HL - TUS = RegDE.Word; RegDE.Word = RegHL.Word; RegHL.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEC: // CALL PE, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagP) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xED: // (Prefix) - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x01: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x02: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x03: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x04: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x05: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x06: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x07: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x08: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x09: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x10: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x11: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x12: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x13: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x14: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x15: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x16: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x17: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x18: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x19: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x20: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x21: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x22: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x23: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x24: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x25: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x26: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x27: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x28: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x29: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x30: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x31: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x32: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x33: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x34: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x35: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x36: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x37: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x38: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x39: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x40: // IN B, C - RegBC.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegBC.High > 127; - RegFlagZ = RegBC.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegBC.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x41: // OUT C, B - WriteHardware(RegBC.Low, RegBC.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x42: // SBC HL, BC - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegBC.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegBC.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x43: // LD (nn), BC - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegBC.Low); - WriteMemoryWrapper(TUS, RegBC.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x44: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x45: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x46: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x47: // LD I, A - RegI = RegAF.High; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x48: // IN C, C - RegBC.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegBC.Low > 127; - RegFlagZ = RegBC.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegBC.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x49: // OUT C, C - WriteHardware(RegBC.Low, RegBC.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x4A: // ADC HL, BC - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x4B: // LD BC, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegBC.Low = ReadMemoryWrapper(TUS++); RegBC.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x4E: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4F: // LD R, A - RegR = RegAF.High; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x50: // IN D, C - RegDE.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegDE.High > 127; - RegFlagZ = RegDE.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegDE.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x51: // OUT C, D - WriteHardware(RegBC.Low, RegDE.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x52: // SBC HL, DE - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegDE.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegDE.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x53: // LD (nn), DE - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegDE.Low); - WriteMemoryWrapper(TUS, RegDE.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x54: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x55: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x56: // IM $1 - interruptMode = 1; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x57: // LD A, I - RegAF.High = RegI; - RegFlagS = RegI > 127; - RegFlagZ = RegI == 0; - RegFlagH = false; - RegFlagN = false; - RegFlagP = IFF2; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x58: // IN E, C - RegDE.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegDE.Low > 127; - RegFlagZ = RegDE.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegDE.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x59: // OUT C, E - WriteHardware(RegBC.Low, RegDE.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x5A: // ADC HL, DE - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x5B: // LD DE, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegDE.Low = ReadMemoryWrapper(TUS++); RegDE.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x5E: // IM $2 - interruptMode = 2; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5F: // LD A, R - RegAF.High = (byte)(RegR & 0x7F); - RegFlagS = (byte)(RegR & 0x7F) > 127; - RegFlagZ = (byte)(RegR & 0x7F) == 0; - RegFlagH = false; - RegFlagN = false; - RegFlagP = IFF2; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x60: // IN H, C - RegHL.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegHL.High > 127; - RegFlagZ = RegHL.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegHL.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x61: // OUT C, H - WriteHardware(RegBC.Low, RegHL.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x62: // SBC HL, HL - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegHL.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegHL.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x63: // LD (nn), HL - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegHL.Low); - WriteMemoryWrapper(TUS, RegHL.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x64: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x65: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x66: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x67: // RRD - RegWZ = (ushort)(RegHL + 1); - TB1 = RegAF.High; TB2 = ReadMemoryWrapper(RegHL.Word); - WriteMemoryWrapper(RegHL.Word, (byte)((TB2 >> 4) + (TB1 << 4))); - RegAF.High = (byte)((TB1 & 0xF0) + (TB2 & 0x0F)); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - RegFlag3 = (RegAF.High & 0x08) != 0; - RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 18; pendingCycles -= 18; - break; - case 0x68: // IN L, C - RegHL.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegHL.Low > 127; - RegFlagZ = RegHL.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegHL.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x69: // OUT C, L - WriteHardware(RegBC.Low, RegHL.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x6A: // ADC HL, HL - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x6B: // LD HL, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegHL.Low = ReadMemoryWrapper(TUS++); RegHL.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x6E: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6F: // RLD - RegWZ = (ushort)(RegHL + 1); - TB1 = RegAF.High; TB2 = ReadMemoryWrapper(RegHL.Word); - WriteMemoryWrapper(RegHL.Word, (byte)((TB1 & 0x0F) + (TB2 << 4))); - RegAF.High = (byte)((TB1 & 0xF0) + (TB2 >> 4)); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - RegFlag3 = (RegAF.High & 0x08) != 0; - RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 18; pendingCycles -= 18; - break; - case 0x70: // IN 0, C - TB = ReadHardware((ushort)RegBC.Low); - RegFlagS = TB > 127; - RegFlagZ = TB == 0; - RegFlagH = false; - RegFlagP = TableParity[TB]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x71: // OUT C, 0 - WriteHardware(RegBC.Low, 0); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x72: // SBC HL, SP - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegSP.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegSP.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x73: // LD (nn), SP - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegSP.Low); - WriteMemoryWrapper(TUS, RegSP.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x74: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x75: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x76: // IM $1 - interruptMode = 1; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x77: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x78: // IN A, C - RegAF.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x79: // OUT C, A - WriteHardware(RegBC.Low, RegAF.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x7A: // ADC HL, SP - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x7B: // LD SP, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegSP.Low = ReadMemoryWrapper(TUS++); RegSP.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x7E: // IM $2 - interruptMode = 2; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x80: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x81: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x82: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x83: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x84: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x85: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x86: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x87: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x88: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x89: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x90: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x91: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x92: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x93: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x94: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x95: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x96: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x97: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x98: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x99: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA0: // LDI - WriteMemoryWrapper(RegDE.Word++, TB1 = ReadMemoryWrapper(RegHL.Word++)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA1: // CPI - RegWZ = (ushort)(RegWZ + 1); - TB1 = ReadMemoryWrapper(RegHL.Word++); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA2: // INI - RegWZ = (ushort)(RegBC + 1); - WriteMemoryWrapper(RegHL.Word++, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA3: // OUTI - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word++)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA8: // LDD - WriteMemoryWrapper(RegDE.Word--, TB1 = ReadMemoryWrapper(RegHL.Word--)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA9: // CPD - RegWZ = (ushort)(RegWZ - 1); - TB1 = ReadMemoryWrapper(RegHL.Word--); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAA: // IND - RegWZ = (ushort)(RegBC - 1); - WriteMemoryWrapper(RegHL.Word--, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAB: // OUTD - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word--)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB0: // LDIR - WriteMemoryWrapper(RegDE.Word++, TB1 = ReadMemoryWrapper(RegHL.Word++)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - if (RegBC.Word != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB1: // CPIR - TB1 = ReadMemoryWrapper(RegHL.Word++); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - if (RegBC.Word != 0 && !RegFlagZ) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB2: // INIR - WriteMemoryWrapper(RegHL.Word++, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB3: // OTIR - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word++)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB8: // LDDR - WriteMemoryWrapper(RegDE.Word--, TB1 = ReadMemoryWrapper(RegHL.Word--)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - if (RegBC.Word != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB9: // CPDR - TB1 = ReadMemoryWrapper(RegHL.Word--); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - if (RegBC.Word != 0 && !RegFlagZ) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBA: // INDR - WriteMemoryWrapper(RegHL.Word--, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBB: // OTDR - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word--)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xED: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - } - break; - case 0xEE: // XOR n - RegAF.Word = TableALU[5, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xEF: // RST $28 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x28; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF0: // RET P - if (!RegFlagS) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xF1: // POP AF - RegAF.Low = ReadMemoryWrapper(RegSP.Word++); RegAF.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xF2: // JP P, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagS) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xF3: // DI - IFF1 = IFF2 = false; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF4: // CALL P, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagS) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xF5: // PUSH AF - WriteMemoryWrapper(--RegSP.Word, RegAF.High); WriteMemoryWrapper(--RegSP.Word, RegAF.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF6: // OR n - RegAF.Word = TableALU[6, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xF7: // RST $30 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x30; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF8: // RET M - if (RegFlagS) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xF9: // LD SP, HL - RegSP.Word = RegHL.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0xFA: // JP M, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagS) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xFB: // EI - EI_pending = 2; - Interruptable = false; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFC: // CALL M, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagS) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xFD: // (Prefix) - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x01: // LD BC, nn - RegBC.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x02: // LD (BC), A - RegWZ.Low = (byte)((RegBC.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegBC.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x03: // INC BC - ++RegBC.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x04: // INC B - RegAF.Low = (byte)(TableInc[++RegBC.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x05: // DEC B - RegAF.Low = (byte)(TableDec[--RegBC.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x06: // LD B, n - RegBC.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x07: // RLCA - RegAF.Word = TableRotShift[0, 0, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x08: // EX AF, AF' - TUS = RegAF.Word; RegAF.Word = RegAltAF.Word; RegAltAF.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x09: // ADD IY, BC - RegWZ = (ushort)(RegIY + 1); - TI1 = (short)RegIY.Word; TI2 = (short)RegBC.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIY.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x0A: // LD A, (BC) - RegAF.High = ReadMemoryWrapper(RegBC.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegBC.Word + 1); - break; - case 0x0B: // DEC BC - --RegBC.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x0C: // INC C - RegAF.Low = (byte)(TableInc[++RegBC.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0D: // DEC C - RegAF.Low = (byte)(TableDec[--RegBC.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0E: // LD C, n - RegBC.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x0F: // RRCA - RegAF.Word = TableRotShift[0, 1, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x10: // DJNZ d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (--RegBC.High != 0) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 13; pendingCycles -= 13; - } - else - { - totalExecutedCycles += 8; pendingCycles -= 8; - } - break; - case 0x11: // LD DE, nn - RegDE.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x12: // LD (DE), A - RegWZ.Low = (byte)((RegDE.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegDE.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x13: // INC DE - ++RegDE.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x14: // INC D - RegAF.Low = (byte)(TableInc[++RegDE.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x15: // DEC D - RegAF.Low = (byte)(TableDec[--RegDE.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x16: // LD D, n - RegDE.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x17: // RLA - RegAF.Word = TableRotShift[0, 2, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x18: // JR d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x19: // ADD IY, DE - RegWZ = (ushort)(RegIY + 1); - TI1 = (short)RegIY.Word; TI2 = (short)RegDE.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIY.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x1A: // LD A, (DE) - RegAF.High = ReadMemoryWrapper(RegDE.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegDE.Word + 1); - break; - case 0x1B: // DEC DE - --RegDE.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x1C: // INC E - RegAF.Low = (byte)(TableInc[++RegDE.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1D: // DEC E - RegAF.Low = (byte)(TableDec[--RegDE.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1E: // LD E, n - RegDE.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x1F: // RRA - RegAF.Word = TableRotShift[0, 3, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x20: // JR NZ, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (!RegFlagZ) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x21: // LD IY, nn - RegIY.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x22: // LD (nn), IY - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegIY.Low); - WriteMemoryWrapper(TUS, RegIY.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x23: // INC IY - ++RegIY.Word; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x24: // INC IYH - RegAF.Low = (byte)(TableInc[++RegIY.High] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x25: // DEC IYH - RegAF.Low = (byte)(TableDec[--RegIY.High] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x26: // LD IYH, n - RegIY.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x27: // DAA - RegAF.Word = TableDaa[RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x28: // JR Z, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (RegFlagZ) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x29: // ADD IY, IY - RegWZ = (ushort)(RegIY + 1); - TI1 = (short)RegIY.Word; TI2 = (short)RegIY.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIY.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x2A: // LD IY, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegIY.Low = ReadMemoryWrapper(TUS++); RegIY.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x2B: // DEC IY - --RegIY.Word; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x2C: // INC IYL - RegAF.Low = (byte)(TableInc[++RegIY.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2D: // DEC IYL - RegAF.Low = (byte)(TableDec[--RegIY.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2E: // LD IYL, n - RegIY.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x2F: // CPL - RegAF.High ^= 0xFF; RegFlagH = true; RegFlagN = true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x30: // JR NC, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (!RegFlagC) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x31: // LD SP, nn - RegSP.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x32: // LD (nn), A - temp_WZ = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ.Low = (byte)((temp_WZ + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(temp_WZ, RegAF.High); - totalExecutedCycles += 13; pendingCycles -= 13; - break; - case 0x33: // INC SP - ++RegSP.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x34: // INC (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - TB = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); RegAF.Low = (byte)(TableInc[++TB] | (RegAF.Low & 1)); WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), TB); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x35: // DEC (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - TB = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); RegAF.Low = (byte)(TableDec[--TB] | (RegAF.Low & 1)); WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), TB); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x36: // LD (IY+d), n - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), FetchMemoryWrapper(RegPC.Word++)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x37: // SCF - RegFlagH = false; RegFlagN = false; RegFlagC = true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x38: // JR C, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (RegFlagC) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x39: // ADD IY, SP - RegWZ = (ushort)(RegIY + 1); - TI1 = (short)RegIY.Word; TI2 = (short)RegSP.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIY.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x3A: // LD A, (nn) - temp_WZ = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegAF.High = ReadMemoryWrapper(temp_WZ); - totalExecutedCycles += 13; pendingCycles -= 13; - RegWZ = (ushort)(temp_WZ + 1); - break; - case 0x3B: // DEC SP - --RegSP.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x3C: // INC A - RegAF.Low = (byte)(TableInc[++RegAF.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3D: // DEC A - RegAF.Low = (byte)(TableDec[--RegAF.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3E: // LD A, n - RegAF.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x3F: // CCF - RegFlagH = RegFlagC; RegFlagN = false; RegFlagC ^= true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x40: // LD B, B - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x41: // LD B, C - RegBC.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x42: // LD B, D - RegBC.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x43: // LD B, E - RegBC.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x44: // LD B, IYH - RegBC.High = RegIY.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x45: // LD B, IYL - RegBC.High = RegIY.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x46: // LD B, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegBC.High = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x47: // LD B, A - RegBC.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x48: // LD C, B - RegBC.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x49: // LD C, C - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4A: // LD C, D - RegBC.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4B: // LD C, E - RegBC.Low = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4C: // LD C, IYH - RegBC.Low = RegIY.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4D: // LD C, IYL - RegBC.Low = RegIY.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4E: // LD C, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegBC.Low = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x4F: // LD C, A - RegBC.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x50: // LD D, B - RegDE.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x51: // LD D, C - RegDE.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x52: // LD D, D - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x53: // LD D, E - RegDE.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x54: // LD D, IYH - RegDE.High = RegIY.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x55: // LD D, IYL - RegDE.High = RegIY.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x56: // LD D, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegDE.High = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x57: // LD D, A - RegDE.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x58: // LD E, B - RegDE.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x59: // LD E, C - RegDE.Low = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5A: // LD E, D - RegDE.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5B: // LD E, E - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5C: // LD E, IYH - RegDE.Low = RegIY.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5D: // LD E, IYL - RegDE.Low = RegIY.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5E: // LD E, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegDE.Low = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x5F: // LD E, A - RegDE.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x60: // LD IYH, B - RegIY.High = RegBC.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x61: // LD IYH, C - RegIY.High = RegBC.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x62: // LD IYH, D - RegIY.High = RegDE.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x63: // LD IYH, E - RegIY.High = RegDE.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x64: // LD IYH, IYH - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x65: // LD IYH, IYL - RegIY.High = RegIY.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x66: // LD H, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegHL.High = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x67: // LD IYH, A - RegIY.High = RegAF.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x68: // LD IYL, B - RegIY.Low = RegBC.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x69: // LD IYL, C - RegIY.Low = RegBC.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6A: // LD IYL, D - RegIY.Low = RegDE.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6B: // LD IYL, E - RegIY.Low = RegDE.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6C: // LD IYL, IYH - RegIY.Low = RegIY.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6D: // LD IYL, IYL - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6E: // LD L, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegHL.Low = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x6F: // LD IYL, A - RegIY.Low = RegAF.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x70: // LD (IY+d), B - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegBC.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x71: // LD (IY+d), C - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegBC.Low); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x72: // LD (IY+d), D - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegDE.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x73: // LD (IY+d), E - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegDE.Low); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x74: // LD (IY+d), H - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegHL.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x75: // LD (IY+d), L - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegHL.Low); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x76: // HALT - Halt(); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x77: // LD (IY+d), A - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegAF.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x78: // LD A, B - RegAF.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x79: // LD A, C - RegAF.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7A: // LD A, D - RegAF.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7B: // LD A, E - RegAF.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7C: // LD A, IYH - RegAF.High = RegIY.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7D: // LD A, IYL - RegAF.High = RegIY.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7E: // LD A, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.High = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x7F: // LD A, A - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x80: // ADD A, B - RegAF.Word = TableALU[0, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x81: // ADD A, C - RegAF.Word = TableALU[0, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x82: // ADD A, D - RegAF.Word = TableALU[0, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x83: // ADD A, E - RegAF.Word = TableALU[0, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x84: // ADD A, IYH - RegAF.Word = TableALU[0, RegAF.High, RegIY.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x85: // ADD A, IYL - RegAF.Word = TableALU[0, RegAF.High, RegIY.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x86: // ADD A, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[0, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x87: // ADD A, A - RegAF.Word = TableALU[0, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x88: // ADC A, B - RegAF.Word = TableALU[1, RegAF.High, RegBC.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x89: // ADC A, C - RegAF.Word = TableALU[1, RegAF.High, RegBC.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8A: // ADC A, D - RegAF.Word = TableALU[1, RegAF.High, RegDE.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8B: // ADC A, E - RegAF.Word = TableALU[1, RegAF.High, RegDE.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8C: // ADC A, IYH - RegAF.Word = TableALU[1, RegAF.High, RegIY.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8D: // ADC A, IYL - RegAF.Word = TableALU[1, RegAF.High, RegIY.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8E: // ADC A, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[1, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), RegFlagC ? 1 : 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x8F: // ADC A, A - RegAF.Word = TableALU[1, RegAF.High, RegAF.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x90: // SUB B - RegAF.Word = TableALU[2, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x91: // SUB C - RegAF.Word = TableALU[2, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x92: // SUB D - RegAF.Word = TableALU[2, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x93: // SUB E - RegAF.Word = TableALU[2, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x94: // SUB IYH - RegAF.Word = TableALU[2, RegAF.High, RegIY.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x95: // SUB IYL - RegAF.Word = TableALU[2, RegAF.High, RegIY.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x96: // SUB (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[2, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x97: // SUB A, A - RegAF.Word = TableALU[2, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x98: // SBC A, B - RegAF.Word = TableALU[3, RegAF.High, RegBC.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x99: // SBC A, C - RegAF.Word = TableALU[3, RegAF.High, RegBC.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9A: // SBC A, D - RegAF.Word = TableALU[3, RegAF.High, RegDE.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9B: // SBC A, E - RegAF.Word = TableALU[3, RegAF.High, RegDE.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9C: // SBC A, IYH - RegAF.Word = TableALU[3, RegAF.High, RegIY.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9D: // SBC A, IYL - RegAF.Word = TableALU[3, RegAF.High, RegIY.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9E: // SBC A, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[3, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), RegFlagC ? 1 : 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x9F: // SBC A, A - RegAF.Word = TableALU[3, RegAF.High, RegAF.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA0: // AND B - RegAF.Word = TableALU[4, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA1: // AND C - RegAF.Word = TableALU[4, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA2: // AND D - RegAF.Word = TableALU[4, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA3: // AND E - RegAF.Word = TableALU[4, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA4: // AND IYH - RegAF.Word = TableALU[4, RegAF.High, RegIY.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA5: // AND IYL - RegAF.Word = TableALU[4, RegAF.High, RegIY.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA6: // AND (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[4, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xA7: // AND A - RegAF.Word = TableALU[4, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA8: // XOR B - RegAF.Word = TableALU[5, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA9: // XOR C - RegAF.Word = TableALU[5, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAA: // XOR D - RegAF.Word = TableALU[5, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAB: // XOR E - RegAF.Word = TableALU[5, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAC: // XOR IYH - RegAF.Word = TableALU[5, RegAF.High, RegIY.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAD: // XOR IYL - RegAF.Word = TableALU[5, RegAF.High, RegIY.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAE: // XOR (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[5, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xAF: // XOR A - RegAF.Word = TableALU[5, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB0: // OR B - RegAF.Word = TableALU[6, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB1: // OR C - RegAF.Word = TableALU[6, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB2: // OR D - RegAF.Word = TableALU[6, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB3: // OR E - RegAF.Word = TableALU[6, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB4: // OR IYH - RegAF.Word = TableALU[6, RegAF.High, RegIY.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB5: // OR IYL - RegAF.Word = TableALU[6, RegAF.High, RegIY.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB6: // OR (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[6, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xB7: // OR A - RegAF.Word = TableALU[6, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB8: // CP B - RegAF.Word = TableALU[7, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB9: // CP C - RegAF.Word = TableALU[7, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBA: // CP D - RegAF.Word = TableALU[7, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBB: // CP E - RegAF.Word = TableALU[7, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBC: // CP IYH - RegAF.Word = TableALU[7, RegAF.High, RegIY.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBD: // CP IYL - RegAF.Word = TableALU[7, RegAF.High, RegIY.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBE: // CP (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[7, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xBF: // CP A - RegAF.Word = TableALU[7, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC0: // RET NZ - if (!RegFlagZ) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xC1: // POP BC - RegBC.Low = ReadMemoryWrapper(RegSP.Word++); RegBC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC2: // JP NZ, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagZ) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC3: // JP nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - RegPC.Word = TUS; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC4: // CALL NZ, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagZ) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xC5: // PUSH BC - WriteMemoryWrapper(--RegSP.Word, RegBC.High); WriteMemoryWrapper(--RegSP.Word, RegBC.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xC6: // ADD A, n - RegAF.Word = TableALU[0, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xC7: // RST $00 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x00; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xC8: // RET Z - if (RegFlagZ) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xC9: // RET - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xCA: // JP Z, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagZ) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xCB: // (Prefix) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // RLC (IY+d) - RegWZ = (ushort)(RegIY.Word + Displacement); - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x01: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x02: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x03: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x04: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x05: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x06: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x07: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x08: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x09: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0A: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0B: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0C: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0D: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0E: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0F: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x10: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x11: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x12: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x13: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x14: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x15: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x16: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x17: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x18: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x19: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1A: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1B: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1C: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1D: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1E: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1F: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x20: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x21: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x22: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x23: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x24: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x25: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x26: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x27: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x28: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x29: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2A: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2B: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2C: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2D: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2E: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2F: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x30: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x31: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x32: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x33: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x34: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x35: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x36: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x37: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x38: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x39: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3A: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3B: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3C: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3D: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3E: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3F: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x40: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x41: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x42: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x43: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x44: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x45: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x46: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x47: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x48: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x49: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4A: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4B: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4C: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4D: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4E: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4F: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x50: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x51: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x52: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x53: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x54: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x55: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x56: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x57: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x58: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x59: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5A: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5B: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5C: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5D: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5E: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5F: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x60: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x61: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x62: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x63: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x64: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x65: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x66: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x67: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x68: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x69: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6A: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6B: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6C: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6D: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6E: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6F: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x70: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x71: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x72: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x73: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x74: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x75: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x76: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x77: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x78: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x79: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7A: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7B: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7C: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7D: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7E: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7F: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x80: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x81: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x82: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x83: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x84: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x85: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x86: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x87: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x88: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x89: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8A: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8B: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8C: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8D: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8E: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8F: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x90: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x91: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x92: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x93: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x94: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x95: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x96: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x97: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x98: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x99: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9A: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9B: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9C: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9D: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9E: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9F: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA0: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA1: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA2: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA3: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA4: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA5: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA6: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA7: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA8: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA9: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAA: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAB: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAC: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAD: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAE: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAF: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB0: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB1: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB2: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB3: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB4: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB5: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB6: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB7: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB8: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB9: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBA: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBB: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBC: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBD: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBE: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBF: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC0: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC1: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC2: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC3: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC4: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC5: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC6: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC7: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC8: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC9: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCA: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCB: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCC: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCD: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCE: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCF: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD0: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD1: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD2: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD3: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD4: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD5: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD6: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD7: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD8: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD9: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDA: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDB: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDC: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDD: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDE: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDF: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE0: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE1: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE2: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE3: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE4: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE5: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE6: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE7: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE8: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE9: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEA: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEB: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEC: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xED: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEE: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEF: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF0: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF1: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF2: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF3: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF4: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF5: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF6: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF7: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF8: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF9: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFA: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFB: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFC: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFD: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFE: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFF: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - } - break; - case 0xCC: // CALL Z, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagZ) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xCD: // CALL nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - break; - case 0xCE: // ADC A, n - RegAF.Word = TableALU[1, RegAF.High, FetchMemoryWrapper(RegPC.Word++), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xCF: // RST $08 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x08; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD0: // RET NC - if (!RegFlagC) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xD1: // POP DE - RegDE.Low = ReadMemoryWrapper(RegSP.Word++); RegDE.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xD2: // JP NC, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagC) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xD3: // OUT n, A - WriteHardware(FetchMemoryWrapper(RegPC.Word++), RegAF.High); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD4: // CALL NC, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xD5: // PUSH DE - WriteMemoryWrapper(--RegSP.Word, RegDE.High); WriteMemoryWrapper(--RegSP.Word, RegDE.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD6: // SUB n - RegAF.Word = TableALU[2, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xD7: // RST $10 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x10; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD8: // RET C - if (RegFlagC) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xD9: // EXX - TUS = RegBC.Word; RegBC.Word = RegAltBC.Word; RegAltBC.Word = TUS; - TUS = RegDE.Word; RegDE.Word = RegAltDE.Word; RegAltDE.Word = TUS; - TUS = RegHL.Word; RegHL.Word = RegAltHL.Word; RegAltHL.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDA: // JP C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xDB: // IN A, n - RegAF.High = ReadHardware((ushort)FetchMemoryWrapper(RegPC.Word++)); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xDC: // CALL C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xDD: // <- - // Invalid sequence. - totalExecutedCycles += 1337; pendingCycles -= 1337; - break; - case 0xDE: // SBC A, n - RegAF.Word = TableALU[3, RegAF.High, FetchMemoryWrapper(RegPC.Word++), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xDF: // RST $18 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x18; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE0: // RET PO - if (!RegFlagP) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xE1: // POP IY - RegIY.Low = ReadMemoryWrapper(RegSP.Word++); RegIY.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0xE2: // JP PO, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagP) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xE3: // EX (SP), IY - TUS = RegSP.Word; TBL = ReadMemoryWrapper(TUS++); TBH = ReadMemoryWrapper(TUS--); - WriteMemoryWrapper(TUS++, RegIY.Low); WriteMemoryWrapper(TUS, RegIY.High); - RegIY.Low = TBL; RegIY.High = TBH; - RegWZ = RegIY; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE4: // CALL C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xE5: // PUSH IY - WriteMemoryWrapper(--RegSP.Word, RegIY.High); WriteMemoryWrapper(--RegSP.Word, RegIY.Low); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xE6: // AND n - RegAF.Word = TableALU[4, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xE7: // RST $20 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x20; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE8: // RET PE - if (RegFlagP) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xE9: // JP IY - RegWZ = RegIY; - RegPC.Word = RegIY.Word; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xEA: // JP PE, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagP) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xEB: // EX DE, HL - TUS = RegDE.Word; RegDE.Word = RegHL.Word; RegHL.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEC: // CALL PE, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagP) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xED: // (Prefix) - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x01: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x02: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x03: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x04: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x05: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x06: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x07: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x08: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x09: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x10: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x11: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x12: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x13: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x14: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x15: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x16: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x17: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x18: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x19: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x20: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x21: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x22: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x23: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x24: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x25: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x26: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x27: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x28: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x29: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x30: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x31: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x32: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x33: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x34: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x35: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x36: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x37: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x38: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x39: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x40: // IN B, C - RegBC.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegBC.High > 127; - RegFlagZ = RegBC.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegBC.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x41: // OUT C, B - WriteHardware(RegBC.Low, RegBC.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x42: // SBC HL, BC - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegBC.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegBC.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x43: // LD (nn), BC - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegBC.Low); - WriteMemoryWrapper(TUS, RegBC.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x44: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x45: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x46: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x47: // LD I, A - RegI = RegAF.High; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x48: // IN C, C - RegBC.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegBC.Low > 127; - RegFlagZ = RegBC.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegBC.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x49: // OUT C, C - WriteHardware(RegBC.Low, RegBC.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x4A: // ADC HL, BC - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x4B: // LD BC, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegBC.Low = ReadMemoryWrapper(TUS++); RegBC.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x4E: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4F: // LD R, A - RegR = RegAF.High; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x50: // IN D, C - RegDE.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegDE.High > 127; - RegFlagZ = RegDE.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegDE.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x51: // OUT C, D - WriteHardware(RegBC.Low, RegDE.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x52: // SBC HL, DE - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegDE.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegDE.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x53: // LD (nn), DE - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegDE.Low); - WriteMemoryWrapper(TUS, RegDE.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x54: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x55: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x56: // IM $1 - interruptMode = 1; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x57: // LD A, I - RegAF.High = RegI; - RegFlagS = RegI > 127; - RegFlagZ = RegI == 0; - RegFlagH = false; - RegFlagN = false; - RegFlagP = IFF2; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x58: // IN E, C - RegDE.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegDE.Low > 127; - RegFlagZ = RegDE.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegDE.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x59: // OUT C, E - WriteHardware(RegBC.Low, RegDE.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x5A: // ADC HL, DE - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x5B: // LD DE, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegDE.Low = ReadMemoryWrapper(TUS++); RegDE.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x5E: // IM $2 - interruptMode = 2; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5F: // LD A, R - RegAF.High = (byte)(RegR & 0x7F); - RegFlagS = (byte)(RegR & 0x7F) > 127; - RegFlagZ = (byte)(RegR & 0x7F) == 0; - RegFlagH = false; - RegFlagN = false; - RegFlagP = IFF2; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x60: // IN H, C - RegHL.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegHL.High > 127; - RegFlagZ = RegHL.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegHL.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x61: // OUT C, H - WriteHardware(RegBC.Low, RegHL.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x62: // SBC HL, HL - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegHL.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegHL.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x63: // LD (nn), HL - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegHL.Low); - WriteMemoryWrapper(TUS, RegHL.High); - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0x64: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x65: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x66: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x67: // RRD - RegWZ = (ushort)(RegHL + 1); - TB1 = RegAF.High; TB2 = ReadMemoryWrapper(RegHL.Word); - WriteMemoryWrapper(RegHL.Word, (byte)((TB2 >> 4) + (TB1 << 4))); - RegAF.High = (byte)((TB1 & 0xF0) + (TB2 & 0x0F)); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - RegFlag3 = (RegAF.High & 0x08) != 0; - RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 18; pendingCycles -= 18; - break; - case 0x68: // IN L, C - RegHL.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegHL.Low > 127; - RegFlagZ = RegHL.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegHL.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x69: // OUT C, L - WriteHardware(RegBC.Low, RegHL.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x6A: // ADC HL, HL - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x6B: // LD HL, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegHL.Low = ReadMemoryWrapper(TUS++); RegHL.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0x6C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x6E: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6F: // RLD - RegWZ = (ushort)(RegHL + 1); - TB1 = RegAF.High; TB2 = ReadMemoryWrapper(RegHL.Word); - WriteMemoryWrapper(RegHL.Word, (byte)((TB1 & 0x0F) + (TB2 << 4))); - RegAF.High = (byte)((TB1 & 0xF0) + (TB2 >> 4)); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - RegFlag3 = (RegAF.High & 0x08) != 0; - RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 18; pendingCycles -= 18; - break; - case 0x70: // IN 0, C - TB = ReadHardware((ushort)RegBC.Low); - RegFlagS = TB > 127; - RegFlagZ = TB == 0; - RegFlagH = false; - RegFlagP = TableParity[TB]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x71: // OUT C, 0 - WriteHardware(RegBC.Low, 0); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x72: // SBC HL, SP - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegSP.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegSP.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x73: // LD (nn), SP - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegSP.Low); - WriteMemoryWrapper(TUS, RegSP.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x74: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x75: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x76: // IM $1 - interruptMode = 1; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x77: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x78: // IN A, C - RegAF.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x79: // OUT C, A - WriteHardware(RegBC.Low, RegAF.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x7A: // ADC HL, SP - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x7B: // LD SP, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegSP.Low = ReadMemoryWrapper(TUS++); RegSP.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x7E: // IM $2 - interruptMode = 2; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x80: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x81: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x82: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x83: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x84: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x85: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x86: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x87: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x88: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x89: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x90: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x91: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x92: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x93: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x94: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x95: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x96: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x97: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x98: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x99: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA0: // LDI - WriteMemoryWrapper(RegDE.Word++, TB1 = ReadMemoryWrapper(RegHL.Word++)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA1: // CPI - RegWZ = (ushort)(RegWZ + 1); - TB1 = ReadMemoryWrapper(RegHL.Word++); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA2: // INI - RegWZ = (ushort)(RegBC + 1); - WriteMemoryWrapper(RegHL.Word++, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA3: // OUTI - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word++)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA8: // LDD - WriteMemoryWrapper(RegDE.Word--, TB1 = ReadMemoryWrapper(RegHL.Word--)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA9: // CPD - RegWZ = (ushort)(RegWZ - 1); - TB1 = ReadMemoryWrapper(RegHL.Word--); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAA: // IND - RegWZ = (ushort)(RegBC - 1); - WriteMemoryWrapper(RegHL.Word--, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAB: // OUTD - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word--)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB0: // LDIR - WriteMemoryWrapper(RegDE.Word++, TB1 = ReadMemoryWrapper(RegHL.Word++)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - if (RegBC.Word != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB1: // CPIR - TB1 = ReadMemoryWrapper(RegHL.Word++); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - if (RegBC.Word != 0 && !RegFlagZ) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB2: // INIR - WriteMemoryWrapper(RegHL.Word++, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB3: // OTIR - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word++)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB8: // LDDR - WriteMemoryWrapper(RegDE.Word--, TB1 = ReadMemoryWrapper(RegHL.Word--)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - if (RegBC.Word != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB9: // CPDR - TB1 = ReadMemoryWrapper(RegHL.Word--); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - if (RegBC.Word != 0 && !RegFlagZ) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBA: // INDR - WriteMemoryWrapper(RegHL.Word--, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBB: // OTDR - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word--)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xED: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - } - break; - case 0xEE: // XOR n - RegAF.Word = TableALU[5, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xEF: // RST $28 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x28; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF0: // RET P - if (!RegFlagS) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xF1: // POP AF - RegAF.Low = ReadMemoryWrapper(RegSP.Word++); RegAF.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xF2: // JP P, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagS) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xF3: // DI - IFF1 = IFF2 = false; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF4: // CALL P, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagS) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xF5: // PUSH AF - WriteMemoryWrapper(--RegSP.Word, RegAF.High); WriteMemoryWrapper(--RegSP.Word, RegAF.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF6: // OR n - RegAF.Word = TableALU[6, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xF7: // RST $30 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x30; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF8: // RET M - if (RegFlagS) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xF9: // LD SP, IY - RegSP.Word = RegIY.Word; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xFA: // JP M, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagS) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xFB: // EI - EI_pending = 2; - Interruptable = false; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFC: // CALL M, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagS) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xFD: // <- - // Invalid sequence. - totalExecutedCycles += 1337; pendingCycles -= 1337; - break; - case 0xFE: // CP n - RegAF.Word = TableALU[7, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xFF: // RST $38 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x38; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - } - break; - case 0xFE: // CP n - RegAF.Word = TableALU[7, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xFF: // RST $38 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x38; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - } - - } - - //EI (enable interrupts) actually takes effect after the NEXT instruction - if (EI_pending > 0) - { - EI_pending--; - if (EI_pending == 0) - { - IFF1 = IFF2 = true; - } - } - - // Process interrupt requests. - if (nonMaskableInterruptPending) - { - halted = false; - - totalExecutedCycles += 11; pendingCycles -= 11; - nonMaskableInterruptPending = false; - - iff2 = iff1; - iff1 = false; - - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x66; - NMICallback(); - - } - else if (iff1 && interrupt && Interruptable) - { - Halted = false; - - iff1 = iff2 = false; - - switch (interruptMode) - { - case 0: - totalExecutedCycles += 13; pendingCycles -= 13; - break; - case 1: - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x38; - totalExecutedCycles += 13; pendingCycles -= 13; - break; - case 2: - TUS = (ushort)(RegI * 256 + 0); - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Low = ReadMemoryWrapper(TUS++); RegPC.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - } - IRQCallback(); - } - - - } - } - - // TODO, not super thrilled with the existing Z80 disassembler, lets see if we can find something decent to replace it with - Disassembler Disassembler = new Disassembler(); - - public string TraceHeader - { - get { return "Z80: PC, machine code, mnemonic, operands, registers (AF, BC, DE, HL, IX, IY, SP, Cy), flags (CNP3H5ZS)"; } - } - - public TraceInfo State() - { - ushort tempPC = RegPC.Word; - - return new TraceInfo - { - Disassembly = string.Format( - "{0:X4}: {1:X2} {2}", - RegPC.Word, - FetchMemoryWrapper(RegPC.Word), - Disassembler.Disassemble(() => ReadMemoryWrapper(tempPC++))).PadRight(26), - RegisterInfo = string.Format( - "AF:{0:X4} BC:{1:X4} DE:{2:X4} HL:{3:X4} IX:{4:X4} IY:{5:X4} SP:{6:X4} Cy:{7} {8}{9}{10}{11}{12}{13}{14}{15}", - RegAF.Word, - RegBC.Word, - RegDE.Word, - RegHL.Word, - RegIX.Word, - RegIY.Word, - RegSP.Word, - TotalExecutedCycles, - RegFlagC ? "C" : "c", - RegFlagN ? "N" : "n", - RegFlagP ? "P" : "p", - RegFlag3 ? "3" : "-", - RegFlagH ? "H" : "h", - RegFlag5 ? "5" : "-", - RegFlagZ ? "Z" : "z", - RegFlagS ? "S" : "s" - ) - }; - } - } -} diff --git a/BizHawk.Emulation.Cores/CPUs/Z80/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/Z80/Interrupts.cs deleted file mode 100644 index 738f1dad74..0000000000 --- a/BizHawk.Emulation.Cores/CPUs/Z80/Interrupts.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; - -namespace BizHawk.Emulation.Cores.Components.Z80 -{ - public partial class Z80A - { - private bool iff1; - public bool IFF1 { get { return iff1; } set { iff1 = value; } } - - private bool iff2; - public bool IFF2 { get { return iff2; } set { iff2 = value; } } - - private bool interrupt; - public bool Interrupt { get { return interrupt; } set { interrupt = value; } } - - private bool nonMaskableInterrupt; - public bool NonMaskableInterrupt - { - get { return nonMaskableInterrupt; } - set { if (value && !nonMaskableInterrupt) NonMaskableInterruptPending = true; nonMaskableInterrupt = value; } - } - - private bool nonMaskableInterruptPending; - public bool NonMaskableInterruptPending { get { return nonMaskableInterruptPending; } set { nonMaskableInterruptPending = value; } } - - private int interruptMode; - public int InterruptMode - { - get { return interruptMode; } - set { if (value < 0 || value > 2) throw new ArgumentOutOfRangeException(); interruptMode = value; } - } - - private bool halted; - public bool Halted { get { return halted; } set { halted = value; } } - - public Action IRQCallback = delegate() { }; - public Action NMICallback = delegate() { }; - - private void ResetInterrupts() - { - IFF1 = false; - IFF2 = false; - Interrupt = false; - NonMaskableInterrupt = false; - NonMaskableInterruptPending = false; - InterruptMode = 1; - Halted = false; - } - - private void Halt() - { - Halted = true; - } - } -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Z80/Registers.cs deleted file mode 100644 index bd5fe98cbc..0000000000 --- a/BizHawk.Emulation.Cores/CPUs/Z80/Registers.cs +++ /dev/null @@ -1,270 +0,0 @@ -using System.Runtime.InteropServices; -using System; - -namespace BizHawk.Emulation.Cores.Components.Z80 -{ - public partial class Z80A - { - [StructLayout(LayoutKind.Explicit)] - [Serializable()] - public struct RegisterPair - { - [FieldOffset(0)] - public ushort Word; - - [FieldOffset(0)] - public byte Low; - - [FieldOffset(1)] - public byte High; - - public RegisterPair(ushort value) - { - Word = value; - Low = (byte)(Word); - High = (byte)(Word >> 8); - } - - public static implicit operator ushort(RegisterPair rp) - { - return rp.Word; - } - - public static implicit operator RegisterPair(ushort value) - { - return new RegisterPair(value); - } - } - - private bool RegFlagC - { - get { return (RegAF.Low & 0x01) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x01) | (value ? 0x01 : 0x00)); } - } - - private bool RegFlagN - { - get { return (RegAF.Low & 0x02) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x02) | (value ? 0x02 : 0x00)); } - } - - private bool RegFlagP - { - get { return (RegAF.Low & 0x04) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x04) | (value ? 0x04 : 0x00)); } - } - - private bool RegFlag3 - { - get { return (RegAF.Low & 0x08) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x08) | (value ? 0x08 : 0x00)); } - } - - private bool RegFlagH - { - get { return (RegAF.Low & 0x10) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x10) | (value ? 0x10 : 0x00)); } - } - - private bool RegFlag5 - { - get { return (RegAF.Low & 0x20) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x20) | (value ? 0x20 : 0x00)); } - } - - private bool RegFlagZ - { - get { return (RegAF.Low & 0x40) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x40) | (value ? 0x40 : 0x00)); } - } - - private bool RegFlagS - { - get { return (RegAF.Low & 0x80) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x80) | (value ? 0x80 : 0x00)); } - } - - private RegisterPair RegAF; - private RegisterPair RegBC; - private RegisterPair RegDE; - private RegisterPair RegHL; - private RegisterPair RegWZ; - - private RegisterPair RegAltAF; // Shadow for A and F - private RegisterPair RegAltBC; // Shadow for B and C - private RegisterPair RegAltDE; // Shadow for D and E - private RegisterPair RegAltHL; // Shadow for H and L - // NOTE: There is no AltWZ register (despite it being shown on various block diagrams) - - private byte RegI; // I (interrupt vector) - private byte RegR; // R (memory refresh) - - private RegisterPair RegIX; // IX (index register x) - private RegisterPair RegIY; // IY (index register y) - - private RegisterPair RegSP; // SP (stack pointer) - private RegisterPair RegPC; // PC (program counter) - - private void ResetRegisters() - { - // Clear main registers - RegAF = 0; RegBC = 0; RegDE = 0; RegHL = 0; RegWZ = 0; - // Clear alternate registers - RegAltAF = 0; RegAltBC = 0; RegAltDE = 0; RegAltHL = 0; - // Clear special purpose registers - RegI = 0; RegR = 0; - RegIX.Word = 0; RegIY.Word = 0; - RegSP.Word = 0; RegPC.Word = 0; - } - - public byte RegisterA - { - get { return RegAF.High; } - set { RegAF.High = value; } - } - - public byte RegisterF - { - get { return RegAF.Low; } - set { RegAF.Low = value; } - } - - public ushort RegisterAF - { - get { return RegAF.Word; } - set { RegAF.Word = value; } - } - - public byte RegisterB - { - get { return RegBC.High; } - set { RegBC.High = value; } - } - - public byte RegisterC - { - get { return RegBC.Low; } - set { RegBC.Low = value; } - } - - public ushort RegisterBC - { - get { return RegBC.Word; } - set { RegBC.Word = value; } - } - - public byte RegisterD - { - get { return RegDE.High; } - set { RegDE.High = value; } - } - - public byte RegisterE - { - get { return RegDE.Low; } - set { RegDE.Low = value; } - } - - public ushort RegisterDE - { - get { return RegDE.Word; } - set { RegDE.Word = value; } - } - - public byte RegisterH - { - get { return RegHL.High; } - set { RegHL.High = value; } - } - - public byte RegisterL - { - get { return RegHL.Low; } - set { RegHL.Low = value; } - } - - public ushort RegisterHL - { - get { return RegHL.Word; } - set { RegHL.Word = value; } - } - - public byte RegisterW - { - get { return RegWZ.High; } - set { RegWZ.High = value; } - } - - public byte RegisterZ - { - get { return RegWZ.Low; } - set { RegWZ.Low = value; } - } - - public ushort RegisterWZ - { - get { return RegWZ.Word; } - set { RegWZ.Word = value; } - } - - public ushort RegisterPC - { - get { return RegPC.Word; } - set { RegPC.Word = value; } - } - - public ushort RegisterSP - { - get { return RegSP.Word; } - set { RegSP.Word = value; } - } - - public ushort RegisterIX - { - get { return RegIX.Word; } - set { RegIX.Word = value; } - } - - public ushort RegisterIY - { - get { return RegIY.Word; } - set { RegIY.Word = value; } - } - - public byte RegisterI - { - get { return RegI; } - set { RegI = value; } - } - - public byte RegisterR - { - get { return RegR; } - set { RegR = value; } - } - - public ushort RegisterShadowAF - { - get { return RegAltAF.Word; } - set { RegAltAF.Word = value; } - } - - public ushort RegisterShadowBC - { - get { return RegAltBC.Word; } - set { RegAltBC.Word = value; } - } - - public ushort RegisterShadowDE - { - get { return RegAltDE.Word; } - set { RegAltDE.Word = value; } - } - - public ushort RegisterShadowHL - { - get { return RegAltHL.Word; } - set { RegAltHL.Word = value; } - } - } -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80/Tables.cs b/BizHawk.Emulation.Cores/CPUs/Z80/Tables.cs deleted file mode 100644 index a50e9a1aeb..0000000000 --- a/BizHawk.Emulation.Cores/CPUs/Z80/Tables.cs +++ /dev/null @@ -1,331 +0,0 @@ -namespace BizHawk.Emulation.Cores.Components.Z80 -{ - public partial class Z80A - { - private void InitialiseTables() - { - InitTableInc(); - InitTableDec(); - InitTableParity(); - InitTableALU(); - InitTableRotShift(); - InitTableHalfBorrow(); - InitTableHalfCarry(); - InitTableNeg(); - InitTableDaa(); - } - - private byte[] TableInc; - private void InitTableInc() - { - TableInc = new byte[256]; - for (int i = 0; i < 256; ++i) - TableInc[i] = FlagByte(false, false, i == 0x80, UndocumentedX(i), (i & 0xF) == 0x0, UndocumentedY(i), i == 0, i > 127); - } - - private byte[] TableDec; - private void InitTableDec() - { - TableDec = new byte[256]; - for (int i = 0; i < 256; ++i) - TableDec[i] = FlagByte(false, true, i == 0x7F, UndocumentedX(i), (i & 0xF) == 0xF, UndocumentedY(i), i == 0, i > 127); - } - - private bool[] TableParity; - private void InitTableParity() - { - TableParity = new bool[256]; - for (int i = 0; i < 256; ++i) - { - int Bits = 0; - for (int j = 0; j < 8; ++j) - { - Bits += (i >> j) & 1; - } - TableParity[i] = (Bits & 1) == 0; - } - } - - private ushort[, , ,] TableALU; - private void InitTableALU() - { - TableALU = new ushort[8, 256, 256, 2]; // Class, OP1, OP2, Carry - - for (int i = 0; i < 8; ++i) - { - for (int op1 = 0; op1 < 256; ++op1) - { - for (int op2 = 0; op2 < 256; ++op2) - { - for (int c = 0; c < 2; ++c) - { - - int ac = (i == 1 || i == 3) ? c : 0; - - bool S = false; - bool Z = false; - bool C = false; - bool H = false; - bool N = false; - bool P = false; - - byte result_b = 0; - int result_si = 0; - int result_ui = 0; - - // Fetch result - switch (i) - { - case 0: - case 1: - result_si = (sbyte)op1 + (sbyte)op2 + ac; - result_ui = op1 + op2 + ac; - break; - case 2: - case 3: - case 7: - result_si = (sbyte)op1 - (sbyte)op2 - ac; - result_ui = op1 - op2 - ac; - break; - case 4: - result_si = op1 & op2; - break; - case 5: - result_si = op1 ^ op2; - break; - case 6: - result_si = op1 | op2; - break; - } - - result_b = (byte)result_si; - - // Parity/Carry - - switch (i) - { - case 0: - case 1: - case 2: - case 3: - case 7: - P = result_si < -128 || result_si > 127; - C = result_ui < 0 || result_ui > 255; - break; - case 4: - case 5: - case 6: - P = TableParity[result_b]; - C = false; - break; - } - - // Subtraction - N = i == 2 || i == 3 || i == 7; - - // Half carry - switch (i) - { - case 0: - case 1: - H = ((op1 & 0xF) + (op2 & 0xF) + (ac & 0xF)) > 0xF; - break; - case 2: - case 3: - case 7: - H = ((op1 & 0xF) - (op2 & 0xF) - (ac & 0xF)) < 0x0; - break; - case 4: - H = true; - break; - case 5: - case 6: - H = false; - break; - } - - // Undocumented - byte UndocumentedFlags = (byte)(result_b & 0x28); - if (i == 7) UndocumentedFlags = (byte)(op2 & 0x28); - - S = result_b > 127; - Z = result_b == 0; - - if (i == 7) result_b = (byte)op1; - - TableALU[i, op1, op2, c] = (ushort)( - result_b * 256 + - ((C ? 0x01 : 0) + (N ? 0x02 : 0) + (P ? 0x04 : 0) + (H ? 0x10 : 0) + (Z ? 0x40 : 0) + (S ? 0x80 : 0)) + - (UndocumentedFlags)); - - } - } - } - } - } - - private bool[,] TableHalfBorrow; - private void InitTableHalfBorrow() - { - TableHalfBorrow = new bool[256, 256]; - for (int i = 0; i < 256; i++) - { - for (int j = 0; j < 256; j++) - { - TableHalfBorrow[i, j] = ((i & 0xF) - (j & 0xF)) < 0; - } - } - } - - private bool[,] TableHalfCarry; - private void InitTableHalfCarry() - { - TableHalfCarry = new bool[256, 256]; - for (int i = 0; i < 256; i++) - { - for (int j = 0; j < 256; j++) - { - TableHalfCarry[i, j] = ((i & 0xF) + (j & 0xF)) > 0xF; - } - } - } - - private ushort[, ,] TableRotShift; - private void InitTableRotShift() - { - TableRotShift = new ushort[2, 8, 65536]; // All, operation, AF - for (int all = 0; all < 2; all++) - { - for (int y = 0; y < 8; ++y) - { - for (int af = 0; af < 65536; af++) - { - byte Old = (byte)(af >> 8); - bool OldCarry = (af & 0x01) != 0; - - ushort newAf = (ushort)(af & ~(0x13)); // Clear HALF-CARRY, SUBTRACT and CARRY flags - - byte New = Old; - if ((y & 1) == 0) - { - if ((Old & 0x80) != 0) ++newAf; - - New <<= 1; - - if ((y & 0x04) == 0) - { - if (((y & 0x02) == 0) ? ((newAf & 0x01) != 0) : OldCarry) New |= 0x01; - } - else - { - if ((y & 0x02) != 0) New |= 0x01; - } - - } - else - { - - if ((Old & 0x01) != 0) ++newAf; - - New >>= 1; - - if ((y & 0x04) == 0) - { - if (((y & 0x02) == 0) ? ((newAf & 0x01) != 0) : OldCarry) New |= 0x80; - } - else - { - if ((y & 0x02) == 0) New |= (byte)(Old & 0x80); - } - } - - newAf &= 0xFF; - newAf |= (ushort)(New * 256); - - if (all == 1) - { - newAf &= unchecked((ushort)~0xC4); // Clear S, Z, P - if (New > 127) newAf |= 0x80; - if (New == 0) newAf |= 0x40; - if (TableParity[New]) newAf |= 0x04; - } - - TableRotShift[all, y, af] = (ushort)((newAf & ~0x28) | ((newAf >> 8) & 0x28)); - } - } - } - } - - private ushort[] TableNeg; - private void InitTableNeg() - { - TableNeg = new ushort[65536]; - for (int af = 0; af < 65536; af++) - { - ushort raf = 0; - byte b = (byte)(af >> 8); - byte a = (byte)-b; - raf |= (ushort)(a * 256); - raf |= FlagByte(b != 0x00, true, b == 0x80, UndocumentedX(a), TableHalfCarry[a, b], UndocumentedY(a), a == 0, a > 127); - TableNeg[af] = raf; - } - } - - private ushort[] TableDaa; - private void InitTableDaa() - { - TableDaa = new ushort[65536]; - for (int af = 0; af < 65536; ++af) - { - byte a = (byte)(af >> 8); - byte tmp = a; - - if (IsN(af)) - { - if (IsH(af) || ((a & 0x0F) > 0x09)) tmp -= 0x06; - if (IsC(af) || a > 0x99) tmp -= 0x60; - } - else - { - if (IsH(af) || ((a & 0x0F) > 0x09)) tmp += 0x06; - if (IsC(af) || a > 0x99) tmp += 0x60; - } - - TableDaa[af] = (ushort)((tmp * 256) + FlagByte(IsC(af) || a > 0x99, IsN(af), TableParity[tmp], UndocumentedX(tmp), ((a ^ tmp) & 0x10) != 0, UndocumentedY(tmp), tmp == 0, tmp > 127)); - } - } - - private byte FlagByte(bool C, bool N, bool P, bool X, bool H, bool Y, bool Z, bool S) - { - return (byte)( - (C ? 0x01 : 0) + - (N ? 0x02 : 0) + - (P ? 0x04 : 0) + - (X ? 0x08 : 0) + - (H ? 0x10 : 0) + - (Y ? 0x20 : 0) + - (Z ? 0x40 : 0) + - (S ? 0x80 : 0) - ); - } - - private bool UndocumentedX(int value) - { - return (value & 0x08) != 0; - } - - private bool UndocumentedY(int value) - { - return (value & 0x20) != 0; - } - - private bool IsC(int value) { return (value & 0x01) != 0; } - private bool IsN(int value) { return (value & 0x02) != 0; } - private bool IsP(int value) { return (value & 0x04) != 0; } - private bool IsX(int value) { return (value & 0x08) != 0; } - private bool IsH(int value) { return (value & 0x10) != 0; } - private bool IsY(int value) { return (value & 0x20) != 0; } - private bool IsZ(int value) { return (value & 0x40) != 0; } - private bool IsS(int value) { return (value & 0x80) != 0; } - } -} diff --git a/BizHawk.Emulation.Cores/CPUs/Z80/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80/Z80A.cs deleted file mode 100644 index 35b7d7038c..0000000000 --- a/BizHawk.Emulation.Cores/CPUs/Z80/Z80A.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Globalization; -using System.IO; - -using BizHawk.Common; -using BizHawk.Emulation.Common; - -// This Z80 emulator is a modified version of Ben Ryves 'Brazil' emulator. -// It is MIT licensed. - -// for WZ register details, see: http://www.grimware.org/lib/exe/fetch.php/documentations/devices/z80/z80.memptr.eng.txt - -namespace BizHawk.Emulation.Cores.Components.Z80 -{ - public sealed partial class Z80A - { - public Z80A() - { - InitialiseTables(); - Reset(); - } - - public void Reset() - { - ResetRegisters(); - ResetInterrupts(); - PendingCycles = 0; - ExpectedExecutedCycles = 0; - TotalExecutedCycles = 0; - } - - public void SoftReset() - { - ResetRegisters(); - ResetInterrupts(); - } - - // Memory Access - - public Func FetchMemory; - public Func ReadMemory; - public Action WriteMemory; - - public byte ReadMemoryWrapper(ushort addr) - { - if (MemoryCallbacks != null) - { - MemoryCallbacks.CallReads(addr); - } - - return ReadMemory(addr); - } - - public byte FetchFirstMemoryWrapper(ushort addr) - { - if (MemoryCallbacks != null) - { - MemoryCallbacks.CallReads(addr); - } - - if (FetchMemory != null) - { - return FetchMemory(addr, true); - } - - return ReadMemory(addr); - } - - public byte FetchMemoryWrapper(ushort addr) - { - if (MemoryCallbacks != null) - { - MemoryCallbacks.CallReads(addr); - } - - if (FetchMemory != null) - { - return FetchMemory(addr, false); - } - - return ReadMemory(addr); - } - - public void WriteMemoryWrapper(ushort addr, byte value) - { - if (MemoryCallbacks != null) - { - MemoryCallbacks.CallWrites(addr); - } - - WriteMemory(addr, value); - } - - public IMemoryCallbackSystem MemoryCallbacks { get; set; } - - // Utility function, not used by core - public ushort ReadWord(ushort addr) - { - ushort value = ReadMemory(addr++); - value |= (ushort)(ReadMemory(addr) << 8); - return value; - } - - // Hardware I/O Port Access - - public Func ReadHardware; - public Action WriteHardware; - - // State Save/Load - - public void SyncState(Serializer ser) - { - ser.BeginSection("Z80"); - ser.Sync("AF", ref RegAF.Word); - ser.Sync("BC", ref RegBC.Word); - ser.Sync("DE", ref RegDE.Word); - ser.Sync("HL", ref RegHL.Word); - ser.Sync("WZ", ref RegWZ.Word); - ser.Sync("ShadowAF", ref RegAltAF.Word); - ser.Sync("ShadowBC", ref RegAltBC.Word); - ser.Sync("ShadowDE", ref RegAltDE.Word); - ser.Sync("ShadowHL", ref RegAltHL.Word); - ser.Sync("I", ref RegI); - ser.Sync("R", ref RegR); - ser.Sync("IX", ref RegIX.Word); - ser.Sync("IY", ref RegIY.Word); - ser.Sync("SP", ref RegSP.Word); - ser.Sync("PC", ref RegPC.Word); - ser.Sync("IRQ", ref interrupt); - ser.Sync("NMI", ref nonMaskableInterrupt); - ser.Sync("NMIPending", ref nonMaskableInterruptPending); - ser.Sync("IM", ref interruptMode); - ser.Sync("IFF1", ref iff1); - ser.Sync("IFF2", ref iff2); - ser.Sync("Halted", ref halted); - ser.Sync("ExecutedCycles", ref totalExecutedCycles); - ser.Sync("PendingCycles", ref pendingCycles); - ser.Sync("EI_pending", ref EI_pending); - ser.EndSection(); - } - } -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs new file mode 100644 index 0000000000..c70e4aa503 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs @@ -0,0 +1,1468 @@ +using System; + +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public partial class Z80A + { + private int totalExecutedCycles; + public int TotalExecutedCycles { get { return totalExecutedCycles; } set { totalExecutedCycles = value; } } + + private int EI_pending; + + public const ushort CBpre = 0; + public const ushort EXTDpre = 1; + public const ushort IXpre = 2; + public const ushort IYpre = 3; + public const ushort IXCBpre = 4; + public const ushort IYCBpre = 5; + public const ushort IXYprefetch = 6; + + // variables for executing instructions + public int instr_pntr = 0; + public ushort[] cur_instr; + public int opcode; + public bool NO_prefix, CB_prefix, IX_prefix, EXTD_prefix, IY_prefix, IXCB_prefix, IYCB_prefix; + public bool IXCB_prefetch, IYCB_prefetch; // value is fetched before opcode + public bool halted; + public ushort PF; + + public void FetchInstruction(byte opcode) + { + if (NO_prefix) + { + switch (opcode) + { + 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: EXCH_(); break; // EXCH AF, AF' + 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: DJNZ_(); break; // DJNZ B + 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(true); 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(!FlagZ); break; // JR NZ, r8 + case 0x21: LD_IND_16(L, H, PCl, PCh); break; // LD HL, nn + case 0x22: LD_16_IND_nn(L, H); break; // LD (nn), HL + 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(FlagZ); break; // JR Z, r8 + case 0x29: ADD_16(L, H, L, H); break; // ADD HL, HL + case 0x2A: LD_IND_16_nn(L, H); break; // LD HL, (nn) + 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(!FlagC); break; // JR NC, r8 + case 0x31: LD_IND_16(SPl, SPh, PCl, PCh); break; // LD SP, nn + case 0x32: LD_8_IND_nn(A); break; // LD (nn), 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(FlagC); break; // JR C, r8 + case 0x39: ADD_16(L, H, SPl, SPh); break; // ADD HL, SP + case 0x3A: LD_IND_8_nn(A); break; // LD A, (nn) + 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(!FlagZ); break; // Ret NZ + case 0xC1: POP_(C, B); break; // POP BC + case 0xC2: JP_COND(!FlagZ); break; // JP NZ + case 0xC3: JP_COND(true); break; // JP + case 0xC4: CALL_COND(!FlagZ); 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(FlagZ); break; // RET Z + case 0xC9: RET_(); break; // RET + case 0xCA: JP_COND(FlagZ); break; // JP Z + case 0xCB: PREFIX_(CBpre); break; // PREFIX CB + case 0xCC: CALL_COND(FlagZ); break; // CALL Z + case 0xCD: CALL_COND(true); 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(!FlagC); break; // Ret NC + case 0xD1: POP_(E, D); break; // POP DE + case 0xD2: JP_COND(!FlagC); break; // JP NC + case 0xD3: OUT_(); break; // OUT A + case 0xD4: CALL_COND(!FlagC); 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(FlagC); break; // RET C + case 0xD9: EXX_(); break; // EXX + case 0xDA: JP_COND(FlagC); break; // JP C + case 0xDB: IN_(); break; // IN A + case 0xDC: CALL_COND(FlagC); break; // CALL C + case 0xDD: PREFIX_(IXpre); break; // PREFIX IX + case 0xDE: REG_OP_IND_INC(SBC8, A, PCl, PCh); break; // SBC A, n + case 0xDF: RST_(0x18); break; // RST 0x18 + case 0xE0: RET_COND(!FlagP); break; // RET Po + case 0xE1: POP_(L, H); break; // POP HL + case 0xE2: JP_COND(!FlagP); break; // JP Po + case 0xE3: EXCH_16_IND_(SPl, SPh, L, H); break; // ex (SP), HL + case 0xE4: CALL_COND(!FlagP); break; // CALL Po + 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: RET_COND(FlagP); break; // RET Pe + case 0xE9: JP_16(L, H); break; // JP (HL) + case 0xEA: JP_COND(FlagP); break; // JP Pe + case 0xEB: EXCH_16_(E,D, L, H); break; // ex DE, HL + case 0xEC: CALL_COND(FlagP); break; // CALL Pe + case 0xED: PREFIX_(EXTDpre); break; // PREFIX EXTD + case 0xEE: REG_OP_IND_INC(XOR8, A, PCl, PCh); break; // XOR A, n + case 0xEF: RST_(0x28); break; // RST 0x28 + case 0xF0: RET_COND(!FlagS); break; // RET p + case 0xF1: POP_(F, A); break; // POP AF + case 0xF2: JP_COND(!FlagS); break; // JP p + case 0xF3: DI_(); break; // DI + case 0xF4: CALL_COND(!FlagS); break; // CALL p + 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: RET_COND(FlagS); break; // RET M + case 0xF9: LD_SP_16(L, H); break; // LD SP, HL + case 0xFA: JP_COND(FlagS); break; // JP M + case 0xFB: EI_(); break; // EI + case 0xFC: CALL_COND(FlagS); break; // CALL M + case 0xFD: PREFIX_(IYpre); break; // PREFIX IY + case 0xFE: REG_OP_IND_INC(CP8, A, PCl, PCh); break; // CP A, n + case 0xFF: RST_(0x38); break; // RST 0x38 + } + } + else if (CB_prefix) + { + CB_prefix = false; + NO_prefix = true; + switch (opcode) + { + 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(SLL, B); break; // SLL B + case 0x31: INT_OP(SLL, C); break; // SLL C + case 0x32: INT_OP(SLL, D); break; // SLL D + case 0x33: INT_OP(SLL, E); break; // SLL E + case 0x34: INT_OP(SLL, H); break; // SLL H + case 0x35: INT_OP(SLL, L); break; // SLL L + case 0x36: INT_OP_IND(SLL, L, H); break; // SLL (HL) + case 0x37: INT_OP(SLL, A); break; // SLL 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 + } + } + else if (EXTD_prefix) + { + // NOTE: Much of EXTD is empty + EXTD_prefix = false; + NO_prefix = true; + + switch (opcode) + { + case 0x40: IN_REG_(B, C); break; // IN B, (C) + case 0x41: OUT_REG_(C, B); break; // OUT (C), B + case 0x42: REG_OP_16_(SBC16, L, H, C, B); break; // SBC HL, BC + case 0x43: LD_16_IND_nn(C, B); break; // LD (nn), BC + case 0x44: INT_OP(NEG, A); break; // NEG + case 0x45: RETN_(); break; // RETN + case 0x46: INT_MODE_(0); break; // IM $0 + case 0x47: REG_OP_IR(TR, I, A); break; // LD I, A + case 0x48: IN_REG_(C, C); break; // IN C, (C) + case 0x49: OUT_REG_(C, C); break; // OUT (C), C + case 0x4A: REG_OP_16_(ADC16, L, H, C, B); break; // ADC HL, BC + case 0x4B: LD_IND_16_nn(C, B); break; // LD BC, (nn) + case 0x4C: INT_OP(NEG, A); break; // NEG + case 0x4D: RETI_(); break; // RETI + case 0x4E: INT_MODE_(0); break; // IM $0 + case 0x4F: REG_OP_IR(TR, R, A); break; // LD R, A + case 0x50: IN_REG_(D, C); break; // IN D, (C) + case 0x51: OUT_REG_(C, D); break; // OUT (C), D + case 0x52: REG_OP_16_(SBC16, L, H, E, D); break; // SBC HL, DE + case 0x53: LD_16_IND_nn(E, D); break; // LD (nn), DE + case 0x54: INT_OP(NEG, A); break; // NEG + case 0x55: RETN_(); break; // RETN + case 0x56: INT_MODE_(1); break; // IM $1 + case 0x57: REG_OP_IR(TR, A, I); break; // LD A, I + case 0x58: IN_REG_(E, C); break; // IN E, (C) + case 0x59: OUT_REG_(C, E); break; // OUT (C), E + case 0x5A: REG_OP_16_(ADC16, L, H, E, D); break; // ADC HL, DE + case 0x5B: LD_IND_16_nn(E, D); break; // LD DE, (nn) + case 0x5C: INT_OP(NEG, A); break; // NEG + case 0x5D: RETN_(); break; // RETI + case 0x5E: INT_MODE_(2); break; // IM $0 + case 0x5F: REG_OP_IR(TR, A, R); break; // LD A, R + case 0x60: IN_REG_(H, C); break; // IN H, (C) + case 0x61: OUT_REG_(C, H); break; // OUT (C), H + case 0x62: REG_OP_16_(SBC16, L, H, L, H); break; // SBC HL, HL + case 0x63: LD_16_IND_nn(L, H); break; // LD (nn), HL + case 0x64: INT_OP(NEG, A); break; // NEG + case 0x65: RETN_(); break; // RETN + case 0x66: INT_MODE_(0); break; // IM $0 + case 0x67: RRD_(); break; // RRD + case 0x68: IN_REG_(L, C); break; // IN L, (C) + case 0x69: OUT_REG_(C, L); break; // OUT (C), L + case 0x6A: REG_OP_16_(ADC16, L, H, L, H); break; // ADC HL, HL + case 0x6B: LD_IND_16_nn(L, H); break; // LD HL, (nn) + case 0x6C: INT_OP(NEG, A); break; // NEG + case 0x6D: RETN_(); break; // RETI + case 0x6E: INT_MODE_(0); break; // IM $0 + case 0x6F: RLD_(); break; // LD R, A + case 0x70: IN_REG_(ALU, C); break; // IN 0, (C) + case 0x71: OUT_REG_(C, ZERO); break; // OUT (C), 0 + case 0x72: REG_OP_16_(SBC16, L, H, SPl, SPh); break; // SBC HL, SP + case 0x73: LD_16_IND_nn(SPl, SPh); break; // LD (nn), SP + case 0x74: INT_OP(NEG, A); break; // NEG + case 0x75: RETN_(); break; // RETN + case 0x76: INT_MODE_(1); break; // IM $1 + case 0x77: NOP_(); break; // NOP + case 0x78: IN_REG_(A, C); break; // IN A, (C) + case 0x79: OUT_REG_(C, A); break; // OUT (C), A + case 0x7A: REG_OP_16_(ADC16, L, H, SPl, SPh); break; // ADC HL, SP + case 0x7B: LD_IND_16_nn(SPl, SPh); break; // LD SP, (nn) + case 0x7C: INT_OP(NEG, A); break; // NEG + case 0x7D: RETN_(); break; // RETI + case 0x7E: INT_MODE_(2); break; // IM $2 + case 0x7F: NOP_(); break; // NOP + case 0xA0: LD_OP_R(INC16, 0); break; // LDI + case 0xA1: CP_OP_R(INC16, 0); break; // CPI + case 0xA2: IN_OP_R(INC16, 0); break; // INI + case 0xA3: OUT_OP_R(INC16, 0); break; // OUTI + case 0xA8: LD_OP_R(DEC16, 0); break; // LDD + case 0xA9: CP_OP_R(DEC16, 0); break; // CPD + case 0xAA: IN_OP_R(DEC16, 0); break; // IND + case 0xAB: OUT_OP_R(DEC16, 0); break; // OUTD + case 0xB0: LD_OP_R(INC16, 1); break; // LDIR + case 0xB1: CP_OP_R(INC16, 1); break; // CPIR + case 0xB2: IN_OP_R(INC16, 1); break; // INIR + case 0xB3: OUT_OP_R(INC16, 1); break; // OTIR + case 0xB8: LD_OP_R(DEC16, 1); break; // LDDR + case 0xB9: CP_OP_R(DEC16, 1); break; // CPDR + case 0xBA: IN_OP_R(DEC16, 1); break; // INDR + case 0xBB: OUT_OP_R(DEC16, 1); break; // OTDR + default: NOP_(); break; // NOP + + } + } + else if (IX_prefix) + { + IX_prefix = false; + NO_prefix = true; + + switch (opcode) + { + 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: EXCH_(); break; // EXCH AF, AF' + case 0x09: ADD_16(Ixl, Ixh, C, B); break; // ADD Ix, 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: DJNZ_(); break; // DJNZ B + 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(true); break; // JR, r8 + case 0x19: ADD_16(Ixl, Ixh, E, D); break; // ADD Ix, 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(!FlagZ); break; // JR NZ, r8 + case 0x21: LD_IND_16(Ixl, Ixh, PCl, PCh); break; // LD Ix, nn + case 0x22: LD_16_IND_nn(Ixl, Ixh); break; // LD (nn), Ix + case 0x23: INC_16(Ixl, Ixh); break; // INC Ix + case 0x24: INT_OP(INC8, Ixh); break; // INC Ixh + case 0x25: INT_OP(DEC8, Ixh); break; // DEC Ixh + case 0x26: LD_IND_8_INC(Ixh, PCl, PCh); break; // LD Ixh, n + case 0x27: INT_OP(DA, A); break; // DAA + case 0x28: JR_COND(FlagZ); break; // JR Z, r8 + case 0x29: ADD_16(Ixl, Ixh, Ixl, Ixh); break; // ADD Ix, Ix + case 0x2A: LD_IND_16_nn(Ixl, Ixh); break; // LD Ix, (nn) + case 0x2B: DEC_16(Ixl, Ixh); break; // DEC Ix + case 0x2C: INT_OP(INC8, Ixl); break; // INC Ixl + case 0x2D: INT_OP(DEC8, Ixl); break; // DEC Ixl + case 0x2E: LD_IND_8_INC(Ixl, PCl, PCh); break; // LD Ixl, n + case 0x2F: INT_OP(CPL, A); break; // CPL + case 0x30: JR_COND(!FlagC); break; // JR NC, r8 + case 0x31: LD_IND_16(SPl, SPh, PCl, PCh); break; // LD SP, nn + case 0x32: LD_8_IND_nn(A); break; // LD (nn), A + case 0x33: INC_16(SPl, SPh); break; // INC SP + case 0x34: I_OP_n(INC8, Ixl, Ixh); break; // INC (Ix + n) + case 0x35: I_OP_n(DEC8, Ixl, Ixh); break; // DEC (Ix + n) + case 0x36: I_OP_n_n(Ixl, Ixh); break; // LD (Ix + n), n + case 0x37: INT_OP(SCF, A); break; // SCF + case 0x38: JR_COND(FlagC); break; // JR C, r8 + case 0x39: ADD_16(Ixl, Ixh, SPl, SPh); break; // ADD Ix, SP + case 0x3A: LD_IND_8_nn(A); break; // LD A, (nn) + 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, Ixh); break; // LD B, Ixh + case 0x45: REG_OP(TR, B, Ixl); break; // LD B, Ixl + case 0x46: I_REG_OP_IND_n(TR, B, Ixl, Ixh); break; // LD B, (Ix + n) + 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, Ixh); break; // LD C, Ixh + case 0x4D: REG_OP(TR, C, Ixl); break; // LD C, Ixl + case 0x4E: I_REG_OP_IND_n(TR, C, Ixl, Ixh); break; // LD C, (Ix + n) + 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, Ixh); break; // LD D, Ixh + case 0x55: REG_OP(TR, D, Ixl); break; // LD D, Ixl + case 0x56: I_REG_OP_IND_n(TR, D, Ixl, Ixh); break; // LD D, (Ix + n) + 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, Ixh); break; // LD E, Ixh + case 0x5D: REG_OP(TR, E, Ixl); break; // LD E, Ixl + case 0x5E: I_REG_OP_IND_n(TR, E, Ixl, Ixh); break; // LD E, (Ix + n) + case 0x5F: REG_OP(TR, E, A); break; // LD E, A + case 0x60: REG_OP(TR, Ixh, B); break; // LD Ixh, B + case 0x61: REG_OP(TR, Ixh, C); break; // LD Ixh, C + case 0x62: REG_OP(TR, Ixh, D); break; // LD Ixh, D + case 0x63: REG_OP(TR, Ixh, E); break; // LD Ixh, E + case 0x64: REG_OP(TR, Ixh, Ixh); break; // LD Ixh, Ixh + case 0x65: REG_OP(TR, Ixh, Ixl); break; // LD Ixh, Ixl + case 0x66: I_REG_OP_IND_n(TR, H, Ixl, Ixh); break; // LD H, (Ix + n) + case 0x67: REG_OP(TR, Ixh, A); break; // LD Ixh, A + case 0x68: REG_OP(TR, Ixl, B); break; // LD Ixl, B + case 0x69: REG_OP(TR, Ixl, C); break; // LD Ixl, C + case 0x6A: REG_OP(TR, Ixl, D); break; // LD Ixl, D + case 0x6B: REG_OP(TR, Ixl, E); break; // LD Ixl, E + case 0x6C: REG_OP(TR, Ixl, Ixh); break; // LD Ixl, Ixh + case 0x6D: REG_OP(TR, Ixl, Ixl); break; // LD Ixl, Ixl + case 0x6E: I_REG_OP_IND_n(TR, L, Ixl, Ixh); break; // LD L, (Ix + n) + case 0x6F: REG_OP(TR, Ixl, A); break; // LD Ixl, A + case 0x70: I_LD_8_IND_n(Ixl, Ixh, B); break; // LD (Ix + n), B + case 0x71: I_LD_8_IND_n(Ixl, Ixh, C); break; // LD (Ix + n), C + case 0x72: I_LD_8_IND_n(Ixl, Ixh, D); break; // LD (Ix + n), D + case 0x73: I_LD_8_IND_n(Ixl, Ixh, E); break; // LD (Ix + n), E + case 0x74: I_LD_8_IND_n(Ixl, Ixh, H); break; // LD (Ix + n), H + case 0x75: I_LD_8_IND_n(Ixl, Ixh, L); break; // LD (Ix + n), L + case 0x76: HALT_(); break; // HALT + case 0x77: I_LD_8_IND_n(Ixl, Ixh, A); break; // LD (Ix + n), 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, Ixh); break; // LD A, Ixh + case 0x7D: REG_OP(TR, A, Ixl); break; // LD A, Ixl + case 0x7E: I_REG_OP_IND_n(TR, A, Ixl, Ixh); break; // LD A, (Ix + n) + 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, Ixh); break; // ADD A, Ixh + case 0x85: REG_OP(ADD8, A, Ixl); break; // ADD A, Ixl + case 0x86: I_REG_OP_IND_n(ADD8, A, Ixl, Ixh); break; // ADD A, (Ix + n) + 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, Ixh); break; // ADC A, Ixh + case 0x8D: REG_OP(ADC8, A, Ixl); break; // ADC A, Ixl + case 0x8E: I_REG_OP_IND_n(ADC8, A, Ixl, Ixh); break; // ADC A, (Ix + n) + 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, Ixh); break; // SUB A, Ixh + case 0x95: REG_OP(SUB8, A, Ixl); break; // SUB A, Ixl + case 0x96: I_REG_OP_IND_n(SUB8, A, Ixl, Ixh); break; // SUB A, (Ix + n) + 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, Ixh); break; // SBC A, Ixh + case 0x9D: REG_OP(SBC8, A, Ixl); break; // SBC A, Ixl + case 0x9E: I_REG_OP_IND_n(SBC8, A, Ixl, Ixh); break; // SBC A, (Ix + n) + 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, Ixh); break; // AND A, Ixh + case 0xA5: REG_OP(AND8, A, Ixl); break; // AND A, Ixl + case 0xA6: I_REG_OP_IND_n(AND8, A, Ixl, Ixh); break; // AND A, (Ix + n) + 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, Ixh); break; // XOR A, Ixh + case 0xAD: REG_OP(XOR8, A, Ixl); break; // XOR A, Ixl + case 0xAE: I_REG_OP_IND_n(XOR8, A, Ixl, Ixh); break; // XOR A, (Ix + n) + 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, Ixh); break; // OR A, Ixh + case 0xB5: REG_OP(OR8, A, Ixl); break; // OR A, Ixl + case 0xB6: I_REG_OP_IND_n(OR8, A, Ixl, Ixh); break; // OR A, (Ix + n) + 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, Ixh); break; // CP A, Ixh + case 0xBD: REG_OP(CP8, A, Ixl); break; // CP A, Ixl + case 0xBE: I_REG_OP_IND_n(CP8, A, Ixl, Ixh); break; // CP A, (Ix + n) + case 0xBF: REG_OP(CP8, A, A); break; // CP A, A + case 0xC0: RET_COND(!FlagZ); break; // Ret NZ + case 0xC1: POP_(C, B); break; // POP BC + case 0xC2: JP_COND(!FlagZ); break; // JP NZ + case 0xC3: JP_COND(true); break; // JP + case 0xC4: CALL_COND(!FlagZ); 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(FlagZ); break; // RET Z + case 0xC9: RET_(); break; // RET + case 0xCA: JP_COND(FlagZ); break; // JP Z + case 0xCB: PREFIX_(IXCBpre); break; // PREFIX IXCB + case 0xCC: CALL_COND(FlagZ); break; // CALL Z + case 0xCD: CALL_COND(true); 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(!FlagC); break; // Ret NC + case 0xD1: POP_(E, D); break; // POP DE + case 0xD2: JP_COND(!FlagC); break; // JP NC + case 0xD3: OUT_(); break; // OUT A + case 0xD4: CALL_COND(!FlagC); 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(FlagC); break; // RET C + case 0xD9: EXX_(); break; // EXX + case 0xDA: JP_COND(FlagC); break; // JP C + case 0xDB: IN_(); break; // IN A + case 0xDC: CALL_COND(FlagC); break; // CALL C + case 0xDD: PREFIX_(IXpre); break; // IX Prefix + case 0xDE: REG_OP_IND_INC(SBC8, A, PCl, PCh); break; // SBC A, n + case 0xDF: RST_(0x18); break; // RST 0x18 + case 0xE0: RET_COND(!FlagP); break; // RET Po + case 0xE1: POP_(Ixl, Ixh); break; // POP Ix + case 0xE2: JP_COND(!FlagP); break; // JP Po + case 0xE3: EXCH_16_IND_(SPl, SPh, Ixl, Ixh); break; // ex (SP), Ix + case 0xE4: CALL_COND(!FlagP); break; // CALL Po + case 0xE5: PUSH_(Ixl, Ixh); break; // PUSH Ix + case 0xE6: REG_OP_IND_INC(AND8, A, PCl, PCh); break; // AND A, n + case 0xE7: RST_(0x20); break; // RST 0x20 + case 0xE8: RET_COND(FlagP); break; // RET Pe + case 0xE9: JP_16(Ixl, Ixh); break; // JP (Ix) + case 0xEA: JP_COND(FlagP); break; // JP Pe + case 0xEB: EXCH_16_(E, D, L, H); break; // ex DE, HL + case 0xEC: CALL_COND(FlagP); break; // CALL Pe + case 0xED: PREFIX_(EXTDpre); break; // EXTD Prefix + case 0xEE: REG_OP_IND_INC(XOR8, A, PCl, PCh); break; // XOR A, n + case 0xEF: RST_(0x28); break; // RST 0x28 + case 0xF0: RET_COND(!FlagS); break; // RET p + case 0xF1: POP_(F, A); break; // POP AF + case 0xF2: JP_COND(!FlagS); break; // JP p + case 0xF3: DI_(); break; // DI + case 0xF4: CALL_COND(!FlagS); break; // CALL p + 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: RET_COND(FlagS); break; // RET M + case 0xF9: LD_SP_16(Ixl, Ixh); break; // LD SP, Ix + case 0xFA: JP_COND(FlagS); break; // JP M + case 0xFB: EI_(); break; // EI + case 0xFC: CALL_COND(FlagS); break; // CALL M + case 0xFD: PREFIX_(IYpre); break; // IY Prefix + case 0xFE: REG_OP_IND_INC(CP8, A, PCl, PCh); break; // CP A, n + case 0xFF: RST_(0x38); break; // RST $38 + } + } + else if (IY_prefix) + { + IY_prefix = false; + NO_prefix = true; + + switch (opcode) + { + 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: EXCH_(); break; // EXCH AF, AF' + case 0x09: ADD_16(Iyl, Iyh, C, B); break; // ADD Iy, 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: DJNZ_(); break; // DJNZ B + 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(true); break; // JR, r8 + case 0x19: ADD_16(Iyl, Iyh, E, D); break; // ADD Iy, 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(!FlagZ); break; // JR NZ, r8 + case 0x21: LD_IND_16(Iyl, Iyh, PCl, PCh); break; // LD Iy, nn + case 0x22: LD_16_IND_nn(Iyl, Iyh); break; // LD (nn), Iy + case 0x23: INC_16(Iyl, Iyh); break; // INC Iy + case 0x24: INT_OP(INC8, Iyh); break; // INC Iyh + case 0x25: INT_OP(DEC8, Iyh); break; // DEC Iyh + case 0x26: LD_IND_8_INC(Iyh, PCl, PCh); break; // LD Iyh, n + case 0x27: INT_OP(DA, A); break; // DAA + case 0x28: JR_COND(FlagZ); break; // JR Z, r8 + case 0x29: ADD_16(Iyl, Iyh, Iyl, Iyh); break; // ADD Iy, Iy + case 0x2A: LD_IND_16_nn(Iyl, Iyh); break; // LD Iy, (nn) + case 0x2B: DEC_16(Iyl, Iyh); break; // DEC Iy + case 0x2C: INT_OP(INC8, Iyl); break; // INC Iyl + case 0x2D: INT_OP(DEC8, Iyl); break; // DEC Iyl + case 0x2E: LD_IND_8_INC(Iyl, PCl, PCh); break; // LD Iyl, n + case 0x2F: INT_OP(CPL, A); break; // CPL + case 0x30: JR_COND(!FlagC); break; // JR NC, r8 + case 0x31: LD_IND_16(SPl, SPh, PCl, PCh); break; // LD SP, nn + case 0x32: LD_8_IND_nn(A); break; // LD (nn), A + case 0x33: INC_16(SPl, SPh); break; // INC SP + case 0x34: I_OP_n(INC8, Iyl, Iyh); break; // INC (Iy + n) + case 0x35: I_OP_n(DEC8, Iyl, Iyh); break; // DEC (Iy + n) + case 0x36: I_OP_n_n(Iyl, Iyh); break; // LD (Iy + n), n + case 0x37: INT_OP(SCF, A); break; // SCF + case 0x38: JR_COND(FlagC); break; // JR C, r8 + case 0x39: ADD_16(Iyl, Iyh, SPl, SPh); break; // ADD Iy, SP + case 0x3A: LD_IND_8_nn(A); break; // LD A, (nn) + 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, Iyh); break; // LD B, Iyh + case 0x45: REG_OP(TR, B, Iyl); break; // LD B, Iyl + case 0x46: I_REG_OP_IND_n(TR, B, Iyl, Iyh); break; // LD B, (Iy + n) + 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, Iyh); break; // LD C, Iyh + case 0x4D: REG_OP(TR, C, Iyl); break; // LD C, Iyl + case 0x4E: I_REG_OP_IND_n(TR, C, Iyl, Iyh); break; // LD C, (Iy + n) + 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, Iyh); break; // LD D, Iyh + case 0x55: REG_OP(TR, D, Iyl); break; // LD D, Iyl + case 0x56: I_REG_OP_IND_n(TR, D, Iyl, Iyh); break; // LD D, (Iy + n) + 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, Iyh); break; // LD E, Iyh + case 0x5D: REG_OP(TR, E, Iyl); break; // LD E, Iyl + case 0x5E: I_REG_OP_IND_n(TR, E, Iyl, Iyh); break; // LD E, (Iy + n) + case 0x5F: REG_OP(TR, E, A); break; // LD E, A + case 0x60: REG_OP(TR, Iyh, B); break; // LD Iyh, B + case 0x61: REG_OP(TR, Iyh, C); break; // LD Iyh, C + case 0x62: REG_OP(TR, Iyh, D); break; // LD Iyh, D + case 0x63: REG_OP(TR, Iyh, E); break; // LD Iyh, E + case 0x64: REG_OP(TR, Iyh, Iyh); break; // LD Iyh, Iyh + case 0x65: REG_OP(TR, Iyh, Iyl); break; // LD Iyh, Iyl + case 0x66: I_REG_OP_IND_n(TR, H, Iyl, Iyh); break; // LD H, (Iy + n) + case 0x67: REG_OP(TR, Iyh, A); break; // LD Iyh, A + case 0x68: REG_OP(TR, Iyl, B); break; // LD Iyl, B + case 0x69: REG_OP(TR, Iyl, C); break; // LD Iyl, C + case 0x6A: REG_OP(TR, Iyl, D); break; // LD Iyl, D + case 0x6B: REG_OP(TR, Iyl, E); break; // LD Iyl, E + case 0x6C: REG_OP(TR, Iyl, Iyh); break; // LD Iyl, Iyh + case 0x6D: REG_OP(TR, Iyl, Iyl); break; // LD Iyl, Iyl + case 0x6E: I_REG_OP_IND_n(TR, L, Iyl, Iyh); break; // LD L, (Iy + n) + case 0x6F: REG_OP(TR, Iyl, A); break; // LD Iyl, A + case 0x70: I_LD_8_IND_n(Iyl, Iyh, B); break; // LD (Iy + n), B + case 0x71: I_LD_8_IND_n(Iyl, Iyh, C); break; // LD (Iy + n), C + case 0x72: I_LD_8_IND_n(Iyl, Iyh, D); break; // LD (Iy + n), D + case 0x73: I_LD_8_IND_n(Iyl, Iyh, E); break; // LD (Iy + n), E + case 0x74: I_LD_8_IND_n(Iyl, Iyh, H); break; // LD (Iy + n), H + case 0x75: I_LD_8_IND_n(Iyl, Iyh, L); break; // LD (Iy + n), L + case 0x76: HALT_(); break; // HALT + case 0x77: I_LD_8_IND_n(Iyl, Iyh, A); break; // LD (Iy + n), 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, Iyh); break; // LD A, Iyh + case 0x7D: REG_OP(TR, A, Iyl); break; // LD A, Iyl + case 0x7E: I_REG_OP_IND_n(TR, A, Iyl, Iyh); break; // LD A, (Iy + n) + 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, Iyh); break; // ADD A, Iyh + case 0x85: REG_OP(ADD8, A, Iyl); break; // ADD A, Iyl + case 0x86: I_REG_OP_IND_n(ADD8, A, Iyl, Iyh); break; // ADD A, (Iy + n) + 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, Iyh); break; // ADC A, Iyh + case 0x8D: REG_OP(ADC8, A, Iyl); break; // ADC A, Iyl + case 0x8E: I_REG_OP_IND_n(ADC8, A, Iyl, Iyh); break; // ADC A, (Iy + n) + 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, Iyh); break; // SUB A, Iyh + case 0x95: REG_OP(SUB8, A, Iyl); break; // SUB A, Iyl + case 0x96: I_REG_OP_IND_n(SUB8, A, Iyl, Iyh); break; // SUB A, (Iy + n) + 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, Iyh); break; // SBC A, Iyh + case 0x9D: REG_OP(SBC8, A, Iyl); break; // SBC A, Iyl + case 0x9E: I_REG_OP_IND_n(SBC8, A, Iyl, Iyh); break; // SBC A, (Iy + n) + 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, Iyh); break; // AND A, Iyh + case 0xA5: REG_OP(AND8, A, Iyl); break; // AND A, Iyl + case 0xA6: I_REG_OP_IND_n(AND8, A, Iyl, Iyh); break; // AND A, (Iy + n) + 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, Iyh); break; // XOR A, Iyh + case 0xAD: REG_OP(XOR8, A, Iyl); break; // XOR A, Iyl + case 0xAE: I_REG_OP_IND_n(XOR8, A, Iyl, Iyh); break; // XOR A, (Iy + n) + 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, Iyh); break; // OR A, Iyh + case 0xB5: REG_OP(OR8, A, Iyl); break; // OR A, Iyl + case 0xB6: I_REG_OP_IND_n(OR8, A, Iyl, Iyh); break; // OR A, (Iy + n) + 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, Iyh); break; // CP A, Iyh + case 0xBD: REG_OP(CP8, A, Iyl); break; // CP A, Iyl + case 0xBE: I_REG_OP_IND_n(CP8, A, Iyl, Iyh); break; // CP A, (Iy + n) + case 0xBF: REG_OP(CP8, A, A); break; // CP A, A + case 0xC0: RET_COND(!FlagZ); break; // Ret NZ + case 0xC1: POP_(C, B); break; // POP BC + case 0xC2: JP_COND(!FlagZ); break; // JP NZ + case 0xC3: JP_COND(true); break; // JP + case 0xC4: CALL_COND(!FlagZ); 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(FlagZ); break; // RET Z + case 0xC9: RET_(); break; // RET + case 0xCA: JP_COND(FlagZ); break; // JP Z + case 0xCB: PREFIX_(IYCBpre); break; // PREFIy IyCB + case 0xCC: CALL_COND(FlagZ); break; // CALL Z + case 0xCD: CALL_COND(true); 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(!FlagC); break; // Ret NC + case 0xD1: POP_(E, D); break; // POP DE + case 0xD2: JP_COND(!FlagC); break; // JP NC + case 0xD3: OUT_(); break; // OUT A + case 0xD4: CALL_COND(!FlagC); 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(FlagC); break; // RET C + case 0xD9: EXX_(); break; // EXX + case 0xDA: JP_COND(FlagC); break; // JP C + case 0xDB: IN_(); break; // IN A + case 0xDC: CALL_COND(FlagC); break; // CALL C + case 0xDD: PREFIX_(IXpre); break; // IX Prefix + case 0xDE: REG_OP_IND_INC(SBC8, A, PCl, PCh); break; // SBC A, n + case 0xDF: RST_(0x18); break; // RST 0x18 + case 0xE0: RET_COND(!FlagP); break; // RET Po + case 0xE1: POP_(Iyl, Iyh); break; // POP Iy + case 0xE2: JP_COND(!FlagP); break; // JP Po + case 0xE3: EXCH_16_IND_(SPl, SPh, Iyl, Iyh); break; // ex (SP), Iy + case 0xE4: CALL_COND(!FlagP); break; // CALL Po + case 0xE5: PUSH_(Iyl, Iyh); break; // PUSH Iy + case 0xE6: REG_OP_IND_INC(AND8, A, PCl, PCh); break; // AND A, n + case 0xE7: RST_(0x20); break; // RST 0x20 + case 0xE8: RET_COND(FlagP); break; // RET Pe + case 0xE9: JP_16(Iyl, Iyh); break; // JP (Iy) + case 0xEA: JP_COND(FlagP); break; // JP Pe + case 0xEB: EXCH_16_(E, D, L, H); break; // ex DE, HL + case 0xEC: CALL_COND(FlagP); break; // CALL Pe + case 0xED: PREFIX_(EXTDpre); break; // EXTD Prefix + case 0xEE: REG_OP_IND_INC(XOR8, A, PCl, PCh); break; // XOR A, n + case 0xEF: RST_(0x28); break; // RST 0x28 + case 0xF0: RET_COND(!FlagS); break; // RET p + case 0xF1: POP_(F, A); break; // POP AF + case 0xF2: JP_COND(!FlagS); break; // JP p + case 0xF3: DI_(); break; // DI + case 0xF4: CALL_COND(!FlagS); break; // CALL p + 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: RET_COND(FlagS); break; // RET M + case 0xF9: LD_SP_16(Iyl, Iyh); break; // LD SP, Iy + case 0xFA: JP_COND(FlagS); break; // JP M + case 0xFB: EI_(); break; // EI + case 0xFC: CALL_COND(FlagS); break; // CALL M + case 0xFD: PREFIX_(IYpre); break; // IY Prefix + case 0xFE: REG_OP_IND_INC(CP8, A, PCl, PCh); break; // CP A, n + case 0xFF: RST_(0x38); break; // RST $38 + } + } + else if (IXCB_prefix || IYCB_prefix) + { + // the first byte fetched is the prefetch value to use with the instruction + // we pick Ix or Iy here, the indexed value is stored in WZ + // In this way, we don't need to pass them as an argument to the I_Funcs. + if (IXCB_prefetch) + { + IXCB_prefetch = false; + PF = opcode; + Regs[ALU] = PF; + PREFETCH_(Ixl, Ixh); + return; + } + + if (IYCB_prefetch) + { + IYCB_prefetch = false; + PF = opcode; + Regs[ALU] = PF; + PREFETCH_(Iyl, Iyh); + return; + } + + IXCB_prefix = false; + IYCB_prefix = false; + NO_prefix = true; + + switch (opcode) + { + case 0x00: I_INT_OP(RLC, B); break; // RLC (I* + n) -> B + case 0x01: I_INT_OP(RLC, C); break; // RLC (I* + n) -> C + case 0x02: I_INT_OP(RLC, D); break; // RLC (I* + n) -> D + case 0x03: I_INT_OP(RLC, E); break; // RLC (I* + n) -> E + case 0x04: I_INT_OP(RLC, H); break; // RLC (I* + n) -> H + case 0x05: I_INT_OP(RLC, L); break; // RLC (I* + n) -> L + case 0x06: I_INT_OP(RLC, ALU); break; // RLC (I* + n) + case 0x07: I_INT_OP(RLC, A); break; // RLC (I* + n) -> A + case 0x08: I_INT_OP(RRC, B); break; // RRC (I* + n) -> B + case 0x09: I_INT_OP(RRC, C); break; // RRC (I* + n) -> C + case 0x0A: I_INT_OP(RRC, D); break; // RRC (I* + n) -> D + case 0x0B: I_INT_OP(RRC, E); break; // RRC (I* + n) -> E + case 0x0C: I_INT_OP(RRC, H); break; // RRC (I* + n) -> H + case 0x0D: I_INT_OP(RRC, L); break; // RRC (I* + n) -> L + case 0x0E: I_INT_OP(RRC, ALU); break; // RRC (I* + n) + case 0x0F: I_INT_OP(RRC, A); break; // RRC (I* + n) -> A + case 0x10: I_INT_OP(RL, B); break; // RL (I* + n) -> B + case 0x11: I_INT_OP(RL, C); break; // RL (I* + n) -> C + case 0x12: I_INT_OP(RL, D); break; // RL (I* + n) -> D + case 0x13: I_INT_OP(RL, E); break; // RL (I* + n) -> E + case 0x14: I_INT_OP(RL, H); break; // RL (I* + n) -> H + case 0x15: I_INT_OP(RL, L); break; // RL (I* + n) -> L + case 0x16: I_INT_OP(RL, ALU); break; // RL (I* + n) + case 0x17: I_INT_OP(RL, A); break; // RL (I* + n) -> A + case 0x18: I_INT_OP(RR, B); break; // RR (I* + n) -> B + case 0x19: I_INT_OP(RR, C); break; // RR (I* + n) -> C + case 0x1A: I_INT_OP(RR, D); break; // RR (I* + n) -> D + case 0x1B: I_INT_OP(RR, E); break; // RR (I* + n) -> E + case 0x1C: I_INT_OP(RR, H); break; // RR (I* + n) -> H + case 0x1D: I_INT_OP(RR, L); break; // RR (I* + n) -> L + case 0x1E: I_INT_OP(RR, ALU); break; // RR (I* + n) + case 0x1F: I_INT_OP(RR, A); break; // RR (I* + n) -> A + case 0x20: I_INT_OP(SLA, B); break; // SLA (I* + n) -> B + case 0x21: I_INT_OP(SLA, C); break; // SLA (I* + n) -> C + case 0x22: I_INT_OP(SLA, D); break; // SLA (I* + n) -> D + case 0x23: I_INT_OP(SLA, E); break; // SLA (I* + n) -> E + case 0x24: I_INT_OP(SLA, H); break; // SLA (I* + n) -> H + case 0x25: I_INT_OP(SLA, L); break; // SLA (I* + n) -> L + case 0x26: I_INT_OP(SLA, ALU); break; // SLA (I* + n) + case 0x27: I_INT_OP(SLA, A); break; // SLA (I* + n) -> A + case 0x28: I_INT_OP(SRA, B); break; // SRA (I* + n) -> B + case 0x29: I_INT_OP(SRA, C); break; // SRA (I* + n) -> C + case 0x2A: I_INT_OP(SRA, D); break; // SRA (I* + n) -> D + case 0x2B: I_INT_OP(SRA, E); break; // SRA (I* + n) -> E + case 0x2C: I_INT_OP(SRA, H); break; // SRA (I* + n) -> H + case 0x2D: I_INT_OP(SRA, L); break; // SRA (I* + n) -> L + case 0x2E: I_INT_OP(SRA, ALU); break; // SRA (I* + n) + case 0x2F: I_INT_OP(SRA, A); break; // SRA (I* + n) -> A + case 0x30: I_INT_OP(SLL, B); break; // SLL (I* + n) -> B + case 0x31: I_INT_OP(SLL, C); break; // SLL (I* + n) -> C + case 0x32: I_INT_OP(SLL, D); break; // SLL (I* + n) -> D + case 0x33: I_INT_OP(SLL, E); break; // SLL (I* + n) -> E + case 0x34: I_INT_OP(SLL, H); break; // SLL (I* + n) -> H + case 0x35: I_INT_OP(SLL, L); break; // SLL (I* + n) -> L + case 0x36: I_INT_OP(SLL, ALU); break; // SLL (I* + n) + case 0x37: I_INT_OP(SLL, A); break; // SLL (I* + n) -> A + case 0x38: I_INT_OP(SRL, B); break; // SRL (I* + n) -> B + case 0x39: I_INT_OP(SRL, C); break; // SRL (I* + n) -> C + case 0x3A: I_INT_OP(SRL, D); break; // SRL (I* + n) -> D + case 0x3B: I_INT_OP(SRL, E); break; // SRL (I* + n) -> E + case 0x3C: I_INT_OP(SRL, H); break; // SRL (I* + n) -> H + case 0x3D: I_INT_OP(SRL, L); break; // SRL (I* + n) -> L + case 0x3E: I_INT_OP(SRL, ALU); break; // SRL (I* + n) + case 0x3F: I_INT_OP(SRL, A); break; // SRL (I* + n) -> A + case 0x40: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x41: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x42: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x43: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x44: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x45: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x46: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x47: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x48: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x49: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x4A: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x4B: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x4C: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x4D: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x4E: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x4F: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x50: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x51: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x52: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x53: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x54: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x55: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x56: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x57: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x58: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x59: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x5A: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x5B: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x5C: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x5D: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x5E: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x5F: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x60: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x61: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x62: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x63: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x64: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x65: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x66: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x67: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x68: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x69: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x6A: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x6B: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x6C: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x6D: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x6E: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x6F: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x70: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x71: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x72: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x73: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x74: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x75: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x76: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x77: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x78: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x79: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x7A: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x7B: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x7C: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x7D: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x7E: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x7F: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x80: I_BIT_OP(RES, 0, B); break; // RES 0, (I* + n) -> B + case 0x81: I_BIT_OP(RES, 0, C); break; // RES 0, (I* + n) -> C + case 0x82: I_BIT_OP(RES, 0, D); break; // RES 0, (I* + n) -> D + case 0x83: I_BIT_OP(RES, 0, E); break; // RES 0, (I* + n) -> E + case 0x84: I_BIT_OP(RES, 0, H); break; // RES 0, (I* + n) -> H + case 0x85: I_BIT_OP(RES, 0, L); break; // RES 0, (I* + n) -> L + case 0x86: I_BIT_OP(RES, 0, ALU); break; // RES 0, (I* + n) + case 0x87: I_BIT_OP(RES, 0, A); break; // RES 0, (I* + n) -> A + case 0x88: I_BIT_OP(RES, 1, B); break; // RES 1, (I* + n) -> B + case 0x89: I_BIT_OP(RES, 1, C); break; // RES 1, (I* + n) -> C + case 0x8A: I_BIT_OP(RES, 1, D); break; // RES 1, (I* + n) -> D + case 0x8B: I_BIT_OP(RES, 1, E); break; // RES 1, (I* + n) -> E + case 0x8C: I_BIT_OP(RES, 1, H); break; // RES 1, (I* + n) -> H + case 0x8D: I_BIT_OP(RES, 1, L); break; // RES 1, (I* + n) -> L + case 0x8E: I_BIT_OP(RES, 1, ALU); break; // RES 1, (I* + n) + case 0x8F: I_BIT_OP(RES, 1, A); break; // RES 1, (I* + n) -> A + case 0x90: I_BIT_OP(RES, 2, B); break; // RES 2, (I* + n) -> B + case 0x91: I_BIT_OP(RES, 2, C); break; // RES 2, (I* + n) -> C + case 0x92: I_BIT_OP(RES, 2, D); break; // RES 2, (I* + n) -> D + case 0x93: I_BIT_OP(RES, 2, E); break; // RES 2, (I* + n) -> E + case 0x94: I_BIT_OP(RES, 2, H); break; // RES 2, (I* + n) -> H + case 0x95: I_BIT_OP(RES, 2, L); break; // RES 2, (I* + n) -> L + case 0x96: I_BIT_OP(RES, 2, ALU); break; // RES 2, (I* + n) + case 0x97: I_BIT_OP(RES, 2, A); break; // RES 2, (I* + n) -> A + case 0x98: I_BIT_OP(RES, 3, B); break; // RES 3, (I* + n) -> B + case 0x99: I_BIT_OP(RES, 3, C); break; // RES 3, (I* + n) -> C + case 0x9A: I_BIT_OP(RES, 3, D); break; // RES 3, (I* + n) -> D + case 0x9B: I_BIT_OP(RES, 3, E); break; // RES 3, (I* + n) -> E + case 0x9C: I_BIT_OP(RES, 3, H); break; // RES 3, (I* + n) -> H + case 0x9D: I_BIT_OP(RES, 3, L); break; // RES 3, (I* + n) -> L + case 0x9E: I_BIT_OP(RES, 3, ALU); break; // RES 3, (I* + n) + case 0x9F: I_BIT_OP(RES, 3, A); break; // RES 3, (I* + n) -> A + case 0xA0: I_BIT_OP(RES, 4, B); break; // RES 4, (I* + n) -> B + case 0xA1: I_BIT_OP(RES, 4, C); break; // RES 4, (I* + n) -> C + case 0xA2: I_BIT_OP(RES, 4, D); break; // RES 4, (I* + n) -> D + case 0xA3: I_BIT_OP(RES, 4, E); break; // RES 4, (I* + n) -> E + case 0xA4: I_BIT_OP(RES, 4, H); break; // RES 4, (I* + n) -> H + case 0xA5: I_BIT_OP(RES, 4, L); break; // RES 4, (I* + n) -> L + case 0xA6: I_BIT_OP(RES, 4, ALU); break; // RES 4, (I* + n) + case 0xA7: I_BIT_OP(RES, 4, A); break; // RES 4, (I* + n) -> A + case 0xA8: I_BIT_OP(RES, 5, B); break; // RES 5, (I* + n) -> B + case 0xA9: I_BIT_OP(RES, 5, C); break; // RES 5, (I* + n) -> C + case 0xAA: I_BIT_OP(RES, 5, D); break; // RES 5, (I* + n) -> D + case 0xAB: I_BIT_OP(RES, 5, E); break; // RES 5, (I* + n) -> E + case 0xAC: I_BIT_OP(RES, 5, H); break; // RES 5, (I* + n) -> H + case 0xAD: I_BIT_OP(RES, 5, L); break; // RES 5, (I* + n) -> L + case 0xAE: I_BIT_OP(RES, 5, ALU); break; // RES 5, (I* + n) + case 0xAF: I_BIT_OP(RES, 5, A); break; // RES 5, (I* + n) -> A + case 0xB0: I_BIT_OP(RES, 6, B); break; // RES 6, (I* + n) -> B + case 0xB1: I_BIT_OP(RES, 6, C); break; // RES 6, (I* + n) -> C + case 0xB2: I_BIT_OP(RES, 6, D); break; // RES 6, (I* + n) -> D + case 0xB3: I_BIT_OP(RES, 6, E); break; // RES 6, (I* + n) -> E + case 0xB4: I_BIT_OP(RES, 6, H); break; // RES 6, (I* + n) -> H + case 0xB5: I_BIT_OP(RES, 6, L); break; // RES 6, (I* + n) -> L + case 0xB6: I_BIT_OP(RES, 6, ALU); break; // RES 6, (I* + n) + case 0xB7: I_BIT_OP(RES, 6, A); break; // RES 6, (I* + n) -> A + case 0xB8: I_BIT_OP(RES, 7, B); break; // RES 7, (I* + n) -> B + case 0xB9: I_BIT_OP(RES, 7, C); break; // RES 7, (I* + n) -> C + case 0xBA: I_BIT_OP(RES, 7, D); break; // RES 7, (I* + n) -> D + case 0xBB: I_BIT_OP(RES, 7, E); break; // RES 7, (I* + n) -> E + case 0xBC: I_BIT_OP(RES, 7, H); break; // RES 7, (I* + n) -> H + case 0xBD: I_BIT_OP(RES, 7, L); break; // RES 7, (I* + n) -> L + case 0xBE: I_BIT_OP(RES, 7, ALU); break; // RES 7, (I* + n) + case 0xBF: I_BIT_OP(RES, 7, A); break; // RES 7, (I* + n) -> A + case 0xC0: I_BIT_OP(SET, 0, B); break; // SET 0, (I* + n) -> B + case 0xC1: I_BIT_OP(SET, 0, C); break; // SET 0, (I* + n) -> C + case 0xC2: I_BIT_OP(SET, 0, D); break; // SET 0, (I* + n) -> D + case 0xC3: I_BIT_OP(SET, 0, E); break; // SET 0, (I* + n) -> E + case 0xC4: I_BIT_OP(SET, 0, H); break; // SET 0, (I* + n) -> H + case 0xC5: I_BIT_OP(SET, 0, L); break; // SET 0, (I* + n) -> L + case 0xC6: I_BIT_OP(SET, 0, ALU); break; // SET 0, (I* + n) + case 0xC7: I_BIT_OP(SET, 0, A); break; // SET 0, (I* + n) -> A + case 0xC8: I_BIT_OP(SET, 1, B); break; // SET 1, (I* + n) -> B + case 0xC9: I_BIT_OP(SET, 1, C); break; // SET 1, (I* + n) -> C + case 0xCA: I_BIT_OP(SET, 1, D); break; // SET 1, (I* + n) -> D + case 0xCB: I_BIT_OP(SET, 1, E); break; // SET 1, (I* + n) -> E + case 0xCC: I_BIT_OP(SET, 1, H); break; // SET 1, (I* + n) -> H + case 0xCD: I_BIT_OP(SET, 1, L); break; // SET 1, (I* + n) -> L + case 0xCE: I_BIT_OP(SET, 1, ALU); break; // SET 1, (I* + n) + case 0xCF: I_BIT_OP(SET, 1, A); break; // SET 1, (I* + n) -> A + case 0xD0: I_BIT_OP(SET, 2, B); break; // SET 2, (I* + n) -> B + case 0xD1: I_BIT_OP(SET, 2, C); break; // SET 2, (I* + n) -> C + case 0xD2: I_BIT_OP(SET, 2, D); break; // SET 2, (I* + n) -> D + case 0xD3: I_BIT_OP(SET, 2, E); break; // SET 2, (I* + n) -> E + case 0xD4: I_BIT_OP(SET, 2, H); break; // SET 2, (I* + n) -> H + case 0xD5: I_BIT_OP(SET, 2, L); break; // SET 2, (I* + n) -> L + case 0xD6: I_BIT_OP(SET, 2, ALU); break; // SET 2, (I* + n) + case 0xD7: I_BIT_OP(SET, 2, A); break; // SET 2, (I* + n) -> A + case 0xD8: I_BIT_OP(SET, 3, B); break; // SET 3, (I* + n) -> B + case 0xD9: I_BIT_OP(SET, 3, C); break; // SET 3, (I* + n) -> C + case 0xDA: I_BIT_OP(SET, 3, D); break; // SET 3, (I* + n) -> D + case 0xDB: I_BIT_OP(SET, 3, E); break; // SET 3, (I* + n) -> E + case 0xDC: I_BIT_OP(SET, 3, H); break; // SET 3, (I* + n) -> H + case 0xDD: I_BIT_OP(SET, 3, L); break; // SET 3, (I* + n) -> L + case 0xDE: I_BIT_OP(SET, 3, ALU); break; // SET 3, (I* + n) + case 0xDF: I_BIT_OP(SET, 3, A); break; // SET 3, (I* + n) -> A + case 0xE0: I_BIT_OP(SET, 4, B); break; // SET 4, (I* + n) -> B + case 0xE1: I_BIT_OP(SET, 4, C); break; // SET 4, (I* + n) -> C + case 0xE2: I_BIT_OP(SET, 4, D); break; // SET 4, (I* + n) -> D + case 0xE3: I_BIT_OP(SET, 4, E); break; // SET 4, (I* + n) -> E + case 0xE4: I_BIT_OP(SET, 4, H); break; // SET 4, (I* + n) -> H + case 0xE5: I_BIT_OP(SET, 4, L); break; // SET 4, (I* + n) -> L + case 0xE6: I_BIT_OP(SET, 4, ALU); break; // SET 4, (I* + n) + case 0xE7: I_BIT_OP(SET, 4, A); break; // SET 4, (I* + n) -> A + case 0xE8: I_BIT_OP(SET, 5, B); break; // SET 5, (I* + n) -> B + case 0xE9: I_BIT_OP(SET, 5, C); break; // SET 5, (I* + n) -> C + case 0xEA: I_BIT_OP(SET, 5, D); break; // SET 5, (I* + n) -> D + case 0xEB: I_BIT_OP(SET, 5, E); break; // SET 5, (I* + n) -> E + case 0xEC: I_BIT_OP(SET, 5, H); break; // SET 5, (I* + n) -> H + case 0xED: I_BIT_OP(SET, 5, L); break; // SET 5, (I* + n) -> L + case 0xEE: I_BIT_OP(SET, 5, ALU); break; // SET 5, (I* + n) + case 0xEF: I_BIT_OP(SET, 5, A); break; // SET 5, (I* + n) -> A + case 0xF0: I_BIT_OP(SET, 6, B); break; // SET 6, (I* + n) -> B + case 0xF1: I_BIT_OP(SET, 6, C); break; // SET 6, (I* + n) -> C + case 0xF2: I_BIT_OP(SET, 6, D); break; // SET 6, (I* + n) -> D + case 0xF3: I_BIT_OP(SET, 6, E); break; // SET 6, (I* + n) -> E + case 0xF4: I_BIT_OP(SET, 6, H); break; // SET 6, (I* + n) -> H + case 0xF5: I_BIT_OP(SET, 6, L); break; // SET 6, (I* + n) -> L + case 0xF6: I_BIT_OP(SET, 6, ALU); break; // SET 6, (I* + n) + case 0xF7: I_BIT_OP(SET, 6, A); break; // SET 6, (I* + n) -> A + case 0xF8: I_BIT_OP(SET, 7, B); break; // SET 7, (I* + n) -> B + case 0xF9: I_BIT_OP(SET, 7, C); break; // SET 7, (I* + n) -> C + case 0xFA: I_BIT_OP(SET, 7, D); break; // SET 7, (I* + n) -> D + case 0xFB: I_BIT_OP(SET, 7, E); break; // SET 7, (I* + n) -> E + case 0xFC: I_BIT_OP(SET, 7, H); break; // SET 7, (I* + n) -> H + case 0xFD: I_BIT_OP(SET, 7, L); break; // SET 7, (I* + n) -> L + case 0xFE: I_BIT_OP(SET, 7, ALU); break; // SET 7, (I* + n) + case 0xFF: I_BIT_OP(SET, 7, A); break; // SET 7, (I* + n) -> A + } + } + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs new file mode 100644 index 0000000000..8dc1cd24ce --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs @@ -0,0 +1,123 @@ +using System; + +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public partial class Z80A + { + private bool iff1; + public bool IFF1 { get { return iff1; } set { iff1 = value; } } + + private bool iff2; + public bool IFF2 { get { return iff2; } set { iff2 = value; } } + + private bool nonMaskableInterrupt; + public bool NonMaskableInterrupt + { + get { return nonMaskableInterrupt; } + set { if (value && !nonMaskableInterrupt) NonMaskableInterruptPending = true; nonMaskableInterrupt = value; } + } + + private bool nonMaskableInterruptPending; + public bool NonMaskableInterruptPending { get { return nonMaskableInterruptPending; } set { nonMaskableInterruptPending = value; } } + + private int interruptMode; + public int InterruptMode + { + get { return interruptMode; } + set { if (value < 0 || value > 2) throw new ArgumentOutOfRangeException(); interruptMode = value; } + } + + public Action IRQCallback = delegate () { }; + public Action NMICallback = delegate () { }; + + private void NMI_() + { + cur_instr = new ushort[] + {IDLE, + DEC16, SPl, SPh, + WR, SPl, SPh, PCh, + IDLE, + DEC16, SPl, SPh, + WR, SPl, SPh, PCl, + IDLE, + ASGN, PCl, 0x66, + ASGN, PCh, 0, + IDLE, + OP }; + } + + // Mode 0 interrupts only take effect if a CALL or RST is on the data bus + // Otherwise operation just continues as normal + // For now assume a NOP is on the data bus, in which case no stack operations occur + + //NOTE: TODO: When a CALL is present on the data bus, adjust WZ accordingly + private void INTERRUPT_0(ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + OP }; + } + + // Just jump to $0038 + private void INTERRUPT_1() + { + cur_instr = new ushort[] + {DEC16, SPl, SPh, + IDLE, + WR, SPl, SPh, PCh, + IDLE, + DEC16, SPl, SPh, + IDLE, + WR, SPl, SPh, PCl, + IDLE, + ASGN, PCl, 0x38, + IDLE, + ASGN, PCh, 0, + IDLE, + OP }; + } + + // Interrupt mode 2 uses the I vector combined with a byte on the data bus + // Again for now we assume only a 0 on the data bus and jump to (0xI00) + private void INTERRUPT_2(ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + DEC16, SPl, SPh, + WR, SPl, SPh, PCh, + IDLE, + DEC16, SPl, SPh, + WR, SPl, SPh, PCl, + IDLE, + ASGN, PCl, 0, + TR, PCh, I, + IDLE, + IDLE, + RD, Z, PCl, PCh, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + IDLE, + TR16, PCl, PCh, Z, W, + OP }; + } + + private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60}; + + private void ResetInterrupts() + { + IFF1 = false; + IFF2 = false; + NonMaskableInterrupt = false; + NonMaskableInterruptPending = false; + FlagI = false; + InterruptMode = 1; + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80/Disassembler.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/NewDisassembler.cs similarity index 89% rename from BizHawk.Emulation.Cores/CPUs/Z80/Disassembler.cs rename to BizHawk.Emulation.Cores/CPUs/Z80A/NewDisassembler.cs index d5b9c2c4e1..6ac1a76444 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80/Disassembler.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/NewDisassembler.cs @@ -1,114 +1,27 @@ -//http://www.zophar.net/fileuploads/2/10819kouzv/z80undoc.html - -//TODO: ex. (IX+00h) could be turned into (IX) - -//usage: -//VgMuseum.Z80.Disassembler disasm = new Disassembler(); -//ushort pc = RegPC.Word; -//string str = disasm.Disassemble(() => ReadMemory(pc++)); -//Console.WriteLine(str); - -//please note that however much youre tempted to, timings can't be put in a table here because they depend on how the instruction executes at runtime - -using System; +using System; using System.Collections.Generic; using BizHawk.Emulation.Common; -namespace BizHawk.Emulation.Cores.Components.Z80 +namespace BizHawk.Emulation.Cores.Components.Z80A { - public class Disassembler : IDisassemblable + public sealed partial class Z80A : IDisassemblable { - readonly static sbyte[,] opcodeSizes = new sbyte[7, 256]; - - public static void GenerateOpcodeSizes() - { - Disassembler disasm = new Disassembler(); - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[0, i] = (sbyte)pc; - } - - opcodeSizes[0, 0xCB] = -1; - opcodeSizes[0, 0xED] = -2; - opcodeSizes[0, 0xDD] = -3; - opcodeSizes[0, 0xFD] = -4; - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { 0xCB, (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[1, i] = (sbyte)pc; - } - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { 0xED, (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[2, i] = (sbyte)pc; - } - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { 0xDD, (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[3, i] = (sbyte)pc; - } - - opcodeSizes[3, 0xCB] = -5; - opcodeSizes[3, 0xED] = -2; - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { 0xFD, (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[4, i] = (sbyte)pc; - } - - opcodeSizes[3, 0xCB] = -6; - opcodeSizes[3, 0xED] = -2; - - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { 0xDD, 0xCB, (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[5, i] = (sbyte)pc; - } - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { 0xFD, 0xCB, (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[6, i] = (sbyte)pc; - } - } - - static string Result(string format, Func read) + static string Result(string format, Func read, ref ushort 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.IndexOf("nn") != -1) { - byte B = read(); - byte C = read(); + byte B = read(addr++); + byte C = read(addr++); format = format.Replace("nn", string.Format("{0:X4}h", B + C * 256)); } if (format.IndexOf("n") != -1) { - byte B = read(); + byte B = read(addr++); format = format.Replace("n", string.Format("{0:X2}h", B)); } @@ -116,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80 if (format.IndexOf("d") != -1) { - byte B = read(); + byte B = read(addr++); bool neg = ((B & 0x80) != 0); char sign = neg ? '-' : '+'; int val = neg ? 256 - B : B; @@ -480,46 +393,49 @@ namespace BizHawk.Emulation.Cores.Components.Z80 "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0x100 }; - string DisassembleInternal(Func read) + public string Disassemble(ushort addr, Func read, out ushort size) { - byte A = read(); + ushort start_addr = addr; + ushort extra_inc = 0; + byte A = read(addr++); string format; switch (A) { case 0xCB: - A = read(); + A = read(addr++); format = mnemonicsCB[A]; break; case 0xDD: - A = read(); + A = read(addr++); switch (A) { - case 0xCB: format = mnemonicsDDCB[A]; break; + case 0xCB: format = mnemonicsDDCB[read((ushort)(addr + 1))]; extra_inc = 1; break; case 0xED: format = mnemonicsED[A]; break; default: format = mnemonicsDD[A]; break; } break; case 0xED: - A = read(); + A = read(addr++); format = mnemonicsED[A]; break; case 0xFD: - A = read(); + A = read(addr++); switch (A) { - case 0xCB: format = mnemonicsFDCB[A]; break; + case 0xCB: format = mnemonicsFDCB[read((ushort)(addr + 1))]; extra_inc = 1; break; case 0xED: format = mnemonicsED[A]; break; default: format = mnemonicsFD[A]; break; } break; default: format = mnemonics[A]; break; } - return format; - } + + string temp = Result(format, read, ref addr); - public string Disassemble(Func read) - { - return Result(DisassembleInternal(read), read); + addr += extra_inc; + + size = (ushort)(addr - start_addr); + return temp; } #region IDisassemblable @@ -543,7 +459,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80 public string Disassemble(MemoryDomain m, uint addr, out int length) { int loc = (int)addr; - string ret = Disassemble(() => m.PeekByte(loc++)); + ushort unused = 0; + string ret = Disassemble((ushort) addr, a => m.PeekByte(a), out unused); length = loc - (int)addr; return ret; } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs new file mode 100644 index 0000000000..cfaf517ec7 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs @@ -0,0 +1,742 @@ +using BizHawk.Common.NumberExtensions; +using System; + +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public partial class Z80A + { + public void Read_Func(ushort dest, ushort src_l, ushort src_h) + { + Regs[dest] = ReadMemory((ushort)(Regs[src_l] | (Regs[src_h]) << 8)); + } + + public void I_Read_Func(ushort dest, ushort src_l, ushort src_h, ushort inc) + { + Regs[dest] = ReadMemory((ushort)((Regs[src_l] | (Regs[src_h] << 8)) + inc)); + } + + public void Write_Func(ushort dest_l, ushort dest_h, ushort src) + { + WriteMemory((ushort)(Regs[dest_l] | (Regs[dest_h] << 8)), (byte)Regs[src]); + } + + public void I_Write_Func(ushort dest_l, ushort dest_h, ushort inc, ushort src) + { + WriteMemory((ushort)((Regs[dest_l] | (Regs[dest_h] << 8)) + inc), (byte)Regs[src]); + } + + public void OUT_Func(ushort dest, ushort src) + { + WriteHardware(Regs[dest], (byte)(Regs[src])); + } + + public void IN_Func(ushort dest, ushort src) + { + Regs[dest] = ReadHardware(Regs[src]); + } + + public void TR_Func(ushort dest, ushort src) + { + Regs[dest] = Regs[src]; + } + + public void TR16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + Regs[dest_l] = Regs[src_l]; + Regs[dest_h] = Regs[src_h]; + } + + public void ADD16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); + int Reg16_s = Regs[src_l] | (Regs[src_h] << 8); + int temp = Reg16_d + Reg16_s; + + FlagC = temp.Bit(16); + FlagH = ((Reg16_d & 0xFFF) + (Reg16_s & 0xFFF)) > 0xFFF; + FlagN = false; + Flag3 = (temp & 0x0800) != 0; + Flag5 = (temp & 0x2000) != 0; + + Regs[dest_l] = (ushort)(temp & 0xFF); + Regs[dest_h] = (ushort)((temp & 0xFF00) >> 8); + } + + public void ADD8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + Reg16_d += Regs[src]; + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d += (Regs[src] & 0xF); + + FlagH = Reg16_d.Bit(4); + FlagN = false; + Flag3 = (ans & 0x08) != 0; + Flag5 = (ans & 0x20) != 0; + FlagP = (Regs[dest].Bit(7) == Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + FlagS = ans > 127; + + Regs[dest] = ans; + } + + public void SUB8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + Reg16_d -= Regs[src]; + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d -= (Regs[src] & 0xF); + + FlagH = Reg16_d.Bit(4); + FlagN = true; + Flag3 = (ans & 0x08) != 0; + Flag5 = (ans & 0x20) != 0; + FlagP = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + FlagS = ans > 127; + + Regs[dest] = ans; + } + + public void BIT_Func(ushort bit, ushort src) + { + FlagZ = !Regs[src].Bit(bit); + FlagP = FlagZ; // special case + FlagH = true; + FlagN = false; + FlagS = ((bit == 7) && Regs[src].Bit(bit)); + Flag5 = Regs[src].Bit(5); + Flag3 = Regs[src].Bit(3); + } + + // When doing I* + n bit tests, flags 3 and 5 come from I* + n + // This cooresponds to the high byte of WZ + // This is the same for the (HL) bit tests, except that WZ were not assigned to before the test occurs + public void I_BIT_Func(ushort bit, ushort src) + { + FlagZ = !Regs[src].Bit(bit); + FlagP = FlagZ; // special case + FlagH = true; + FlagN = false; + FlagS = ((bit == 7) && Regs[src].Bit(bit)); + Flag5 = Regs[W].Bit(5); + Flag3 = Regs[W].Bit(3); + } + + public void SET_Func(ushort bit, ushort src) + { + Regs[src] |= (ushort)(1 << bit); + } + + public void RES_Func(ushort bit, ushort src) + { + Regs[src] &= (ushort)(0xFF - (1 << bit)); + } + + public void ASGN_Func(ushort src, ushort val) + { + Regs[src] = val; + } + + public void SLL_Func(ushort src) + { + FlagC = Regs[src].Bit(7); + + Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | 0x1); + + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void SLA_Func(ushort src) + { + FlagC = Regs[src].Bit(7); + + Regs[src] = (ushort)((Regs[src] << 1) & 0xFF); + + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void SRA_Func(ushort src) + { + FlagC = Regs[src].Bit(0); + + ushort temp = (ushort)(Regs[src] & 0x80); // MSB doesn't change in this operation + + Regs[src] = (ushort)((Regs[src] >> 1) | temp); + + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void SRL_Func(ushort src) + { + FlagC = Regs[src].Bit(0) ? true : false; + + Regs[src] = (ushort)(Regs[src] >> 1); + + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void CPL_Func(ushort src) + { + Regs[src] = (ushort)((~Regs[src]) & 0xFF); + + FlagH = true; + FlagN = true; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + } + + public void CCF_Func(ushort src) + { + FlagH = FlagC; + FlagC = !FlagC; + FlagN = false; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + } + + public void SCF_Func(ushort src) + { + FlagC = true; + FlagH = false; + FlagN = false; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + } + + public void AND8_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)(Regs[dest] & Regs[src]); + + FlagZ = Regs[dest] == 0; + FlagC = false; + FlagH = true; + FlagN = false; + Flag3 = (Regs[dest] & 0x08) != 0; + Flag5 = (Regs[dest] & 0x20) != 0; + FlagS = Regs[dest] > 127; + FlagP = TableParity[Regs[dest]]; + } + + public void OR8_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)(Regs[dest] | Regs[src]); + + FlagZ = Regs[dest] == 0; + FlagC = false; + FlagH = false; + FlagN = false; + Flag3 = (Regs[dest] & 0x08) != 0; + Flag5 = (Regs[dest] & 0x20) != 0; + FlagS = Regs[dest] > 127; + FlagP = TableParity[Regs[dest]]; + } + + public void XOR8_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)((Regs[dest] ^ Regs[src])); + + FlagZ = Regs[dest] == 0; + FlagC = false; + FlagH = false; + FlagN = false; + Flag3 = (Regs[dest] & 0x08) != 0; + Flag5 = (Regs[dest] & 0x20) != 0; + FlagS = Regs[dest] > 127; + FlagP = TableParity[Regs[dest]]; + } + + public void CP8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + Reg16_d -= Regs[src]; + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d -= (Regs[src] & 0xF); + + FlagH = Reg16_d.Bit(4); + FlagN = true; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagP = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + FlagS = ans > 127; + } + + public void RRC_Func(ushort src) + { + bool imm = src == Aim; + if (imm) { src = A; } + + FlagC = Regs[src].Bit(0); + + Regs[src] = (ushort)((FlagC ? 0x80 : 0) | (Regs[src] >> 1)); + + if (!imm) + { + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + } + + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void RR_Func(ushort src) + { + bool imm = src == Aim; + if (imm) { src = A; } + + ushort c = (ushort)(FlagC ? 0x80 : 0); + + FlagC = Regs[src].Bit(0); + + Regs[src] = (ushort)(c | (Regs[src] >> 1)); + + if (!imm) + { + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + } + + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void RLC_Func(ushort src) + { + bool imm = src == Aim; + if (imm) { src = A; } + + ushort c = (ushort)(Regs[src].Bit(7) ? 1 : 0); + FlagC = Regs[src].Bit(7); + + Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c); + + if (!imm) + { + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + } + + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void RL_Func(ushort src) + { + bool imm = src == Aim; + if (imm) { src = A; } + + ushort c = (ushort)(FlagC ? 1 : 0); + FlagC = Regs[src].Bit(7); + + Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c); + + if (!imm) + { + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + } + + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void INC8_Func(ushort src) + { + int Reg16_d = Regs[src]; + Reg16_d += 1; + + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[src] & 0xF; + Reg16_d += 1; + + FlagH = Reg16_d.Bit(4); + FlagN = false; + + Regs[src] = ans; + + FlagS = Regs[src].Bit(7); + FlagP = Regs[src] == 0x80; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + } + + public void DEC8_Func(ushort src) + { + int Reg16_d = Regs[src]; + Reg16_d -= 1; + + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[src] & 0xF; + Reg16_d -= 1; + + FlagH = Reg16_d.Bit(4); + FlagN = true; + + Regs[src] = ans; + + FlagS = Regs[src].Bit(7); + FlagP = Regs[src] == 0x7F; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + } + + public void INC16_Func(ushort src_l, ushort src_h) + { + int Reg16_d = Regs[src_l] | (Regs[src_h] << 8); + + Reg16_d += 1; + + Regs[src_l] = (ushort)(Reg16_d & 0xFF); + Regs[src_h] = (ushort)((Reg16_d & 0xFF00) >> 8); + } + + public void DEC16_Func(ushort src_l, ushort src_h) + { + int Reg16_d = Regs[src_l] | (Regs[src_h] << 8); + + Reg16_d -= 1; + + Regs[src_l] = (ushort)(Reg16_d & 0xFF); + Regs[src_h] = (ushort)((Reg16_d & 0xFF00) >> 8); + } + + public void ADC8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + int c = FlagC ? 1 : 0; + + Reg16_d += (Regs[src] + c); + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d += ((Regs[src] & 0xF) + c); + + FlagH = Reg16_d.Bit(4); + FlagN = false; + Flag3 = (ans & 0x08) != 0; + Flag5 = (ans & 0x20) != 0; + FlagP = (Regs[dest].Bit(7) == Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + FlagS = ans > 127; + + Regs[dest] = ans; + } + + public void SBC8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + int c = FlagC ? 1 : 0; + + Reg16_d -= (Regs[src] + c); + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d -= ((Regs[src] & 0xF) + c); + + FlagH = Reg16_d.Bit(4); + FlagN = true; + Flag3 = (ans & 0x08) != 0; + Flag5 = (ans & 0x20) != 0; + FlagP = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + FlagS = ans > 127; + + Regs[dest] = ans; + } + + public void DA_Func(ushort src) + { + byte a = (byte)Regs[src]; + byte temp = a; + + if (FlagN) + { + if (FlagH || ((a & 0x0F) > 0x09)) { temp -= 0x06; } + if (FlagC || a > 0x99) { temp -= 0x60; } + } + else + { + if (FlagH || ((a & 0x0F) > 0x09)) { temp += 0x06; } + if (FlagC || a > 0x99) { temp += 0x60; } + } + + temp &= 0xFF; + + FlagC = FlagC || a > 0x99; + FlagZ = temp == 0; + FlagH = ((a ^ temp) & 0x10) != 0; + FlagP = TableParity[temp]; + FlagS = temp > 127; + Flag3 = (temp & 0x08) != 0; + Flag5 = (temp & 0x20) != 0; + + Regs[src] = temp; + } + + // used for signed operations + public void ADDS_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + int Reg16_d = Regs[dest_l]; + int Reg16_s = Regs[src_l]; + + Reg16_d += Reg16_s; + + ushort temp = 0; + + // since this is signed addition, calculate the high byte carry appropriately + // note that flags are unaffected by this operation + if (Reg16_s.Bit(7)) + { + if (((Reg16_d & 0xFF) >= Regs[dest_l])) + { + temp = 0xFF; + } + else + { + temp = 0; + } + } + else + { + temp = (ushort)(Reg16_d.Bit(8) ? 1 : 0); + } + + ushort ans_l = (ushort)(Reg16_d & 0xFF); + + Regs[dest_l] = ans_l; + Regs[dest_h] += temp; + Regs[dest_h] &= 0xFF; + + } + + public void EXCH_16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + ushort temp = Regs[dest_l]; + Regs[dest_l] = Regs[src_l]; + Regs[src_l] = temp; + + temp = Regs[dest_h]; + Regs[dest_h] = Regs[src_h]; + Regs[src_h] = temp; + } + + public void SBC_16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); + int Reg16_s = Regs[src_l] | (Regs[src_h] << 8); + int c = FlagC ? 1 : 0; + + int ans = Reg16_d - Reg16_s - c; + + FlagN = true; + FlagC = ans.Bit(16); + FlagP = (Reg16_d.Bit(15) != Reg16_s.Bit(15)) && (Reg16_d.Bit(15) != ans.Bit(15)); + FlagS = (ushort)(ans & 0xFFFF) > 32767; + FlagZ = (ans & 0xFFFF) == 0; + Flag3 = (ans & 0x0800) != 0; + Flag5 = (ans & 0x2000) != 0; + + // redo for half carry flag + Reg16_d &= 0xFFF; + Reg16_d -= ((Reg16_s & 0xFFF) + c); + + FlagH = Reg16_d.Bit(12); + + Regs[dest_l] = (ushort)(ans & 0xFF); + Regs[dest_h] = (ushort)((ans >> 8) & 0xFF); + } + + public void ADC_16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); + int Reg16_s = Regs[src_l] | (Regs[src_h] << 8); + + int ans = Reg16_d + Reg16_s + (FlagC ? 1 : 0); + + FlagH = ((Reg16_d & 0xFFF) + (Reg16_s & 0xFFF) + (FlagC ? 1 : 0)) > 0xFFF; + FlagN = false; + FlagC = ans.Bit(16); + FlagP = (Reg16_d.Bit(15) == Reg16_s.Bit(15)) && (Reg16_d.Bit(15) != ans.Bit(15)); + FlagS = (ans & 0xFFFF) > 32767; + FlagZ = (ans & 0xFFFF) == 0; + Flag3 = (ans & 0x0800) != 0; + Flag5 = (ans & 0x2000) != 0; + + Regs[dest_l] = (ushort)(ans & 0xFF); + Regs[dest_h] = (ushort)((ans >> 8) & 0xFF); + } + + public void NEG_8_Func(ushort src) + { + int Reg16_d = 0; + Reg16_d -= Regs[src]; + + FlagC = Regs[src] != 0x0; + FlagZ = (Reg16_d & 0xFF) == 0; + FlagP = Regs[src] == 0x80; + FlagS = (Reg16_d & 0xFF) > 127; + + ushort ans = (ushort)(Reg16_d & 0xFF); + // redo for half carry flag + Reg16_d = 0; + Reg16_d -= (Regs[src] & 0xF); + FlagH = Reg16_d.Bit(4); + Regs[src] = ans; + FlagN = true; + Flag3 = (ans & 0x08) != 0; + Flag5 = (ans & 0x20) != 0; + } + + public void RRD_Func(ushort dest, ushort src) + { + ushort temp1 = Regs[src]; + ushort temp2 = Regs[dest]; + Regs[dest] = (ushort)(((temp1 & 0x0F) << 4) + ((temp2 & 0xF0) >> 4)); + Regs[src] = (ushort)((temp1 & 0xF0) + (temp2 & 0x0F)); + + temp1 = Regs[src]; + FlagS = temp1 > 127; + FlagZ = temp1 == 0; + FlagH = false; + FlagP = TableParity[temp1]; + FlagN = false; + Flag3 = (temp1 & 0x08) != 0; + Flag5 = (temp1 & 0x20) != 0; + } + + public void RLD_Func(ushort dest, ushort src) + { + ushort temp1 = Regs[src]; + ushort temp2 = Regs[dest]; + Regs[dest] = (ushort)((temp1 & 0x0F) + ((temp2 & 0x0F) << 4)); + Regs[src] = (ushort)((temp1 & 0xF0) + ((temp2 & 0xF0) >> 4)); + + temp1 = Regs[src]; + FlagS = temp1 > 127; + FlagZ = temp1 == 0; + FlagH = false; + FlagP = TableParity[temp1]; + FlagN = false; + Flag3 = (temp1 & 0x08) != 0; + Flag5 = (temp1 & 0x20) != 0; + } + + // sets flags for LD/R + public void SET_FL_LD_Func() + { + FlagP = (Regs[C] | (Regs[B] << 8)) != 0; + FlagH = false; + FlagN = false; + Flag5 = ((Regs[ALU] + Regs[A]) & 0x02) != 0; + Flag3 = ((Regs[ALU] + Regs[A]) & 0x08) != 0; + } + + // set flags for CP/R + public void SET_FL_CP_Func() + { + int Reg8_d = Regs[A]; + int Reg8_s = Regs[ALU]; + + // get half carry flag + byte temp = (byte)((Reg8_d & 0xF) - (Reg8_s & 0xF)); + FlagH = temp.Bit(4); + + temp = (byte)(Reg8_d - Reg8_s); + FlagN = true; + FlagZ = temp == 0; + FlagS = temp > 127; + FlagP = (Regs[C] | (Regs[B] << 8)) != 0; + + temp = (byte)(Reg8_d - Reg8_s - (FlagH ? 1 : 0)); + Flag5 = (temp & 0x02) != 0; + Flag3 = (temp & 0x08) != 0; + } + + // set flags for LD A, I/R + public void SET_FL_IR_Func(ushort dest) + { + if (dest == A) + { + FlagN = false; + FlagH = false; + FlagZ = Regs[A] == 0; + FlagS = Regs[A] > 127; + FlagP = iff2; + Flag5 = (Regs[A] & 0x02) != 0; + Flag3 = (Regs[A] & 0x08) != 0; + } + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/ReadMe.txt b/BizHawk.Emulation.Cores/CPUs/Z80A/ReadMe.txt new file mode 100644 index 0000000000..d11f79b637 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/ReadMe.txt @@ -0,0 +1,8 @@ +TODO: + +Mode 0 and 2 interrupts +Check T-cycle level memory access timing +Check R register +new tests for WZ Registers +Memory refresh - IR is pushed onto the address bus at instruction start, does anything need this? +Data Bus - For mode zero and 2 interrupts, need a system that uses it to test diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs new file mode 100644 index 0000000000..628243c19e --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs @@ -0,0 +1,132 @@ +using System.Runtime.InteropServices; +using System; + +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public partial class Z80A + { + // registers + // note these are not constants. When shadows are used, they will be changed accordingly + public ushort PCl = 0; + public ushort PCh = 1; + public ushort SPl = 2; + public ushort SPh = 3; + public ushort A = 4; + public ushort F = 5; + public ushort B = 6; + public ushort C = 7; + public ushort D = 8; + public ushort E = 9; + public ushort H = 10; + public ushort L = 11; + public ushort W = 12; + public ushort Z = 13; + public ushort Aim = 14; // use this indicator for RLCA etc., since the Z flag is reset on those + public ushort Ixl = 15; + public ushort Ixh = 16; + public ushort Iyl = 17; + public ushort Iyh = 18; + public ushort Int = 19; + public ushort R = 20; + public ushort I = 21; + public ushort ZERO = 22; // it is convenient to have a register that is always zero, to reuse instructions + public ushort ALU = 23; // This will be temporary arthimatic storage + // shadow registers + public ushort A_s = 24; + public ushort F_s = 25; + public ushort B_s = 26; + public ushort C_s = 27; + public ushort D_s = 28; + public ushort E_s = 29; + public ushort H_s = 30; + public ushort L_s = 31; + + public ushort[] Regs = new ushort[36]; + + public bool FlagI; + + public bool FlagC + { + get { return (Regs[5] & 0x01) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x01) | (value ? 0x01 : 0x00)); } + } + + public bool FlagN + { + get { return (Regs[5] & 0x02) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x02) | (value ? 0x02 : 0x00)); } + } + + public bool FlagP + { + get { return (Regs[5] & 0x04) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x04) | (value ? 0x04 : 0x00)); } + } + + public bool Flag3 + { + get { return (Regs[5] & 0x08) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x08) | (value ? 0x08 : 0x00)); } + } + + public bool FlagH + { + get { return (Regs[5] & 0x10) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x10) | (value ? 0x10 : 0x00)); } + } + + public bool Flag5 + { + get { return (Regs[5] & 0x20) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x20) | (value ? 0x20 : 0x00)); } + } + + public bool FlagZ + { + get { return (Regs[5] & 0x40) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x40) | (value ? 0x40 : 0x00)); } + } + + public bool FlagS + { + get { return (Regs[5] & 0x80) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x80) | (value ? 0x80 : 0x00)); } + } + + public ushort RegPC + { + get { return (ushort)(Regs[0] | (Regs[1] << 8)); } + set + { + Regs[0] = (ushort)(value & 0xFF); + Regs[1] = (ushort)((value >> 8) & 0xFF); + } + } + + private void ResetRegisters() + { + for (int i=0; i < 36; i++) + { + Regs[i] = 0; + } + } + + private bool[] TableParity; + private void InitTableParity() + { + TableParity = new bool[256]; + for (int i = 0; i < 256; ++i) + { + int Bits = 0; + for (int j = 0; j < 8; ++j) + { + Bits += (i >> j) & 1; + } + TableParity[i] = (Bits & 1) == 0; + } + } + + + + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs new file mode 100644 index 0000000000..71b39d6018 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -0,0 +1,572 @@ +using System; + +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public partial class Z80A + { + // this contains the vectors of instrcution operations + // NOTE: This list is NOT confirmed accurate for each individual cycle + + private void NOP_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + OP }; + } + + // NOTE: In a real Z80, this operation just flips a switch to choose between 2 registers + // but it's simpler to emulate just by exchanging the register with it's shadow + private void EXCH_() + { + cur_instr = new ushort[] + {EXCH, + IDLE, + IDLE, + OP }; + } + + private void EXX_() + { + cur_instr = new ushort[] + {EXX, + IDLE, + IDLE, + OP }; + } + + // this exchanges 2 16 bit registers + private void EXCH_16_(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {EXCH_16, dest_l, dest_h, src_l, src_h, + IDLE, + IDLE, + OP }; + } + + private void INC_16(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + INC16, src_l, src_h, + IDLE, + OP }; + } + + + private void DEC_16(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + DEC16, src_l, src_h, + IDLE, + IDLE, + OP }; + } + + // this is done in two steps technically, but the flags don't work out using existing funcitons + // so let's use a different function since it's an internal operation anyway + private void ADD_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + TR16, Z, W, dest_l, dest_h, + INC16, Z, W, + IDLE, + IDLE, + ADD16, dest_l, dest_h, src_l, src_h, + IDLE, + IDLE, + OP }; + } + + private void REG_OP(ushort operation, ushort dest, ushort src) + { + cur_instr = new ushort[] + {operation, dest, src, + IDLE, + IDLE, + OP }; + } + + // Operations using the I and R registers take one T-cycle longer + private void REG_OP_IR(ushort operation, ushort dest, ushort src) + { + cur_instr = new ushort[] + {operation, dest, src, + IDLE, + IDLE, + SET_FL_IR, dest, + OP }; + } + + // note: do not use DEC here since no flags are affected by this operation + private void DJNZ_() + { + if ((Regs[B] - 1) != 0) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + ASGN, B, (ushort)((Regs[B] - 1) & 0xFF), + IDLE, + RD, Z, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + ASGN, W, 0, + IDLE, + ADDS, PCl, PCh, Z, W, + TR16, Z, W, PCl, PCh, + OP }; + } + else + { + cur_instr = new ushort[] + {IDLE, + ASGN, B, (ushort)((Regs[B] - 1) & 0xFF), + IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + OP }; + } + } + + private void HALT_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + HALT }; + } + + private void JR_COND(bool cond) + { + if (cond) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, PCl, PCh, + INC16, PCl, PCh, + IDLE, + IDLE, + ASGN, W, 0, + IDLE, + ADDS, PCl, PCh, Z, W, + TR16, Z, W, PCl, PCh, + IDLE, + OP }; + } + else + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + OP }; + } + } + + private void JP_COND(bool cond) + { + if (cond) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, PCl, PCh, + INC16, PCl, PCh, + RD, W, PCl, PCh, + IDLE, + INC16, PCl, PCh, + TR16, PCl, PCh, Z, W, + IDLE, + OP }; + } + else + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, PCl, PCh, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + INC16, PCl, PCh, + IDLE, + IDLE, + OP }; + } + } + + private void RET_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, SPl, SPh, + INC16, SPl, SPh, + IDLE, + IDLE, + RD, W, SPl, SPh, + INC16, SPl, SPh, + TR16, PCl, PCh, Z, W, + OP }; + } + + private void RETI_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, SPl, SPh, + INC16, SPl, SPh, + IDLE, + IDLE, + RD, W, SPl, SPh, + INC16, SPl, SPh, + TR16, PCl, PCh, Z, W, + OP }; + } + + private void RETN_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, SPl, SPh, + INC16, SPl, SPh, + IDLE, + RD, W, SPl, SPh, + INC16, SPl, SPh, + EI_RETN, + TR16, PCl, PCh, Z, W, + OP }; + } + + + private void RET_COND(bool cond) + { + if (cond) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, SPl, SPh, + INC16, SPl, SPh, + IDLE, + IDLE, + RD, W, SPl, SPh, + INC16, SPl, SPh, + IDLE, + TR16, PCl, PCh, Z, W, + OP }; + } + else + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + IDLE, + OP }; + } + } + + private void CALL_COND(bool cond) + { + if (cond) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, PCl, PCh, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + INC16, PCl, PCh, + IDLE, + DEC16, SPl, SPh, + IDLE, + WR, SPl, SPh, PCh, + DEC16, SPl, SPh, + WR, SPl, SPh, PCl, + IDLE, + TR, PCl, Z, + TR, PCh, W, + OP }; + } + else + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + IDLE, + INC16, PCl, PCh, + OP }; + } + } + + private void INT_OP(ushort operation, ushort src) + { + cur_instr = new ushort[] + {operation, src, + IDLE, + IDLE, + OP }; + } + + private void BIT_OP(ushort operation, ushort bit, ushort src) + { + cur_instr = new ushort[] + {operation, bit, src, + IDLE, + IDLE, + OP }; + } + + private void PUSH_(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + DEC16, SPl, SPh, + IDLE, + WR, SPl, SPh, src_h, + IDLE, + DEC16, SPl, SPh, + IDLE, + WR, SPl, SPh, src_l, + IDLE, + OP }; + } + + + private void POP_(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + RD, src_l, SPl, SPh, + IDLE, + INC16, SPl, SPh, + IDLE, + RD, src_h, SPl, SPh, + IDLE, + INC16, SPl, SPh, + IDLE, + OP }; + } + + private void RST_(ushort n) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + DEC16, SPl, SPh, + WR, SPl, SPh, PCh, + DEC16, SPl, SPh, + WR, SPl, SPh, PCl, + IDLE, + ASGN, Z, n, + ASGN, W, 0, + TR16, PCl, PCh, Z, W, + OP }; + } + + private void PREFIX_(ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + PREFIX, src}; + } + + private void PREFETCH_(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {TR16, Z, W, src_l, src_h, + ADDS, Z, W, ALU, ZERO, + IDLE, + PREFIX, IXYprefetch }; + } + + private void DI_() + { + cur_instr = new ushort[] + {DI, + IDLE, + IDLE, + OP }; + } + + private void EI_() + { + cur_instr = new ushort[] + {EI, + IDLE, + IDLE, + OP }; + } + + private void JP_16(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {TR, PCl, src_l, + IDLE, + TR, PCh, src_h, + OP }; + } + + private void LD_SP_16(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + TR, SPl, src_l, + TR, SPh, src_h, + IDLE, + OP }; + } + + private void OUT_() + { + cur_instr = new ushort[] + {IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + TR, W, A, + OUT, ALU, A, + TR, Z, ALU, + INC16, Z, ALU, + IDLE, + IDLE, + OP}; + } + + private void OUT_REG_(ushort dest, ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + OUT, dest, src, + IDLE, + TR16, Z, W, C, B, + INC16, Z, W, + IDLE, + OP}; + } + + private void IN_() + { + cur_instr = new ushort[] + {IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + TR, W, A, + IN, A, ALU, + TR, Z, ALU, + INC16, Z, W, + IDLE, + IDLE, + OP}; + } + + private void IN_REG_(ushort dest, ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IN, dest, src, + IDLE, + TR16, Z, W, C, B, + INC16, Z, W, + IDLE, + OP}; + } + + private void REG_OP_16_(ushort op, ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + TR16, Z, W, dest_l, dest_h, + INC16, Z, W, + IDLE, + IDLE, + op, dest_l, dest_h, src_l, src_h, + IDLE, + IDLE, + OP}; + } + + private void INT_MODE_(ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + INT_MODE, src, + OP }; + } + + private void RRD_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + TR16, Z, W, L, H, + IDLE, + RD, ALU, Z, W, + IDLE, + RRD, ALU, A, + IDLE, + WR, Z, W, ALU, + IDLE, + INC16, Z, W, + IDLE, + IDLE, + OP }; + } + + private void RLD_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + TR16, Z, W, L, H, + IDLE, + RD, ALU, Z, W, + IDLE, + RLD, ALU, A, + IDLE, + WR, Z, W, ALU, + IDLE, + INC16, Z, W, + IDLE, + IDLE, + OP }; + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs new file mode 100644 index 0000000000..4a1c46cc03 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -0,0 +1,478 @@ +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public partial class Z80A + { + private void INT_OP_IND(ushort operation, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + operation, ALU, + IDLE, + WR, src_l, src_h, ALU, + IDLE, + IDLE, + OP }; + } + + private void BIT_OP_IND(ushort operation, ushort bit, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + operation, bit, ALU, + IDLE, + WR, src_l, src_h, ALU, + IDLE, + IDLE, + OP }; + } + + // Note that this operation uses I_BIT, same as indexed BIT. + // This is where the strange behaviour in Flag bits 3 and 5 come from. + // normally WZ contain I* + n when doing I_BIT ops, but here we use that code path + // even though WZ is not assigned to, letting it's value from other operations show through + private void BIT_TE_IND(ushort operation, ushort bit, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + I_BIT, bit, ALU, + IDLE, + OP }; + } + + private void REG_OP_IND_INC(ushort operation, ushort dest, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + operation, dest, ALU, + INC16, src_l, src_h, + OP }; + } + + private void REG_OP_IND(ushort operation, ushort dest, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + TR16, Z, W, src_l, src_h, + RD, ALU, Z, W, + INC16, Z, W, + operation, dest, ALU, + OP }; + } + + private void LD_16_IND_nn(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + RD, Z, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + WR, Z, W, src_l, + IDLE, + INC16, Z, W, + IDLE, + WR, Z, W, src_h, + IDLE, + OP }; + } + + private void LD_IND_16_nn(ushort dest_l, ushort dest_h) + { + cur_instr = new ushort[] + {IDLE, + RD, Z, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, dest_l, Z, W, + IDLE, + INC16, Z, W, + IDLE, + RD, dest_h, Z, W, + IDLE, + OP }; + } + + private void LD_8_IND_nn(ushort src) + { + cur_instr = new ushort[] + {IDLE, + RD, Z, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + WR, Z, W, src, + INC16, Z, W, + TR, W, A, + OP }; + } + + private void LD_IND_8_nn(ushort dest) + { + cur_instr = new ushort[] + {IDLE, + RD, Z, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, dest, Z, W, + IDLE, + INC16, Z, W, + OP }; + } + + private void LD_8_IND(ushort dest_l, ushort dest_h, ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + TR16, Z, W, dest_l, dest_h, + WR, Z, W, src, + INC16, Z, W, + TR, W, A, + OP }; + } + + private void LD_8_IND_IND(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + INC16, src_l, src_h, + IDLE, + WR, dest_l, dest_h, ALU, + IDLE, + OP }; + } + + private void LD_IND_8_INC(ushort dest, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, dest, src_l, src_h, + IDLE, + INC16, src_l, src_h, + OP }; + } + + private void LD_IND_8_DEC(ushort dest, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, dest, src_l, src_h, + IDLE, + DEC16, src_l, src_h, + IDLE, + OP }; + } + + private void LD_IND_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, dest_l, src_l, src_h, + IDLE, + INC16, src_l, src_h, + RD, dest_h, src_l, src_h, + IDLE, + INC16, src_l, src_h, + OP }; + } + + private void INC_8_IND(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + INC8, ALU, + IDLE, + WR, src_l, src_h, ALU, + IDLE, + IDLE, + OP }; + } + + private void DEC_8_IND(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + DEC8, ALU, + IDLE, + WR, src_l, src_h, ALU, + IDLE, + IDLE, + OP }; + } + + // NOTE: WZ implied for the wollowing 3 functions + private void I_INT_OP(ushort operation, ushort dest) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, Z, W, + IDLE, + operation, ALU, + IDLE, + WR, Z, W, ALU, + IDLE, + TR, dest, ALU, + IDLE, + OP }; + } + + private void I_BIT_OP(ushort operation, ushort bit, ushort dest) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, Z, W, + IDLE, + operation, bit, ALU, + IDLE, + WR, Z, W, ALU, + IDLE, + TR, dest, ALU, + IDLE, + OP }; + } + + private void I_BIT_TE(ushort bit) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, Z, W, + IDLE, + I_BIT, bit, ALU, + IDLE, + OP }; + } + + private void I_OP_n(ushort operation, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, PCl, PCh, + INC16, PCl, PCh, + IDLE, + TR16, Z, W, src_l, src_h, + IDLE, + ADDS, Z, W, ALU, ZERO, + IDLE, + RD, ALU, Z, W, + IDLE, + IDLE, + operation, ALU, + IDLE, + IDLE, + IDLE, + WR, Z, W, ALU, + IDLE, + OP }; + } + + private void I_OP_n_n(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, PCl, PCh, + INC16, PCl, PCh, + IDLE, + TR16, Z, W, src_l, src_h, + IDLE, + ADDS, Z, W, ALU, ZERO, + IDLE, + RD, ALU, PCl, PCh, + INC16, PCl, PCh, + IDLE, + WR, Z, W, ALU, + IDLE, + OP }; + } + + private void I_REG_OP_IND_n(ushort operation, ushort dest, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + TR16, Z, W, src_l, src_h, + IDLE, + ADDS, Z, W, ALU, ZERO, + IDLE, + RD, ALU, Z, W, + IDLE, + operation, dest, ALU, + IDLE, + OP }; + } + + private void I_LD_8_IND_n(ushort dest_l, ushort dest_h, ushort src) + { + cur_instr = new ushort[] + {IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + TR16, Z, W, dest_l, dest_h, + IDLE, + ADDS, Z, W, ALU, ZERO, + IDLE, + WR, Z, W, src, + IDLE, + IDLE, + IDLE, + IDLE, + OP }; + } + + private void LD_OP_R(ushort operation, ushort repeat_instr) + { + cur_instr = new ushort[] + {RD, ALU, L, H, + IDLE, + WR, E, D, ALU, + IDLE, + operation, L, H, + IDLE, + operation, E, D, + IDLE, + DEC16, C, B, + SET_FL_LD, + IDLE, + OP_R, 0, operation, repeat_instr }; + } + + private void CP_OP_R(ushort operation, ushort repeat_instr) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, L, H, + operation, L, H, + IDLE, + IDLE, + DEC16, C, B, + SET_FL_CP, + IDLE, + operation, Z, W, + IDLE, + OP_R, 1, operation, repeat_instr }; + } + + private void IN_OP_R(ushort operation, ushort repeat_instr) + { + cur_instr = new ushort[] + {IN, ALU, C, + IDLE, + WR, L, H, ALU, + IDLE, + operation, L, H, + IDLE, + TR16, Z, W, C, B, + operation, Z, W, + IDLE, + DEC8, B, + IDLE, + OP_R, 2, operation, repeat_instr }; + } + + private void OUT_OP_R(ushort operation, ushort repeat_instr) + { + cur_instr = new ushort[] + {RD, ALU, L, H, + IDLE, + OUT, C, ALU, + IDLE, + IDLE, + operation, L, H, + DEC8, B, + IDLE, + TR16, Z, W, C, B, + operation, Z, W, + IDLE, + OP_R, 3, operation, repeat_instr }; + } + + // this is an indirect change of a a 16 bit register with memory + private void EXCH_16_IND_(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, dest_l, dest_h, + IDLE, + IDLE, + I_RD, W, dest_l, dest_h, 1, + IDLE, + IDLE, + WR, dest_l, dest_h, src_l, + IDLE, + IDLE, + I_WR, dest_l, dest_h, 1, src_h, + IDLE, + IDLE, + TR16, src_l, src_h, Z, W, + IDLE, + IDLE, + IDLE, + OP }; + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs new file mode 100644 index 0000000000..6cb1a36617 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -0,0 +1,688 @@ +using System; +using System.Globalization; +using System.IO; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Common.NumberExtensions; + +// Z80A CPU +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public sealed partial class Z80A + { + // operations that can take place in an instruction + public const ushort IDLE = 0; + public const ushort OP = 1; + public const ushort OP_R = 2; // used for repeating operations + public const ushort HALT = 3; + public const ushort RD = 4; + public const ushort WR = 5; + public const ushort I_RD = 6; + public const ushort I_WR = 7; + public const ushort TR = 8; + public const ushort TR16 = 9; + public const ushort ADD16 = 10; + public const ushort ADD8 = 11; + public const ushort SUB8 = 12; + public const ushort ADC8 = 13; + public const ushort SBC8 = 14; + public const ushort SBC16 = 15; + public const ushort ADC16 = 16; + public const ushort INC16 = 17; + public const ushort INC8 = 18; + public const ushort DEC16 = 19; + public const ushort DEC8 = 20; + public const ushort RLC = 21; + public const ushort RL = 22; + public const ushort RRC = 23; + public const ushort RR = 24; + public const ushort CPL = 25; + public const ushort DA = 26; + public const ushort SCF = 27; + public const ushort CCF = 28; + public const ushort AND8 = 29; + public const ushort XOR8 = 30; + public const ushort OR8 = 31; + public const ushort CP8 = 32; + public const ushort SLA = 33; + public const ushort SRA = 34; + public const ushort SRL = 35; + public const ushort SLL = 36; + public const ushort BIT = 37; + public const ushort RES = 38; + public const ushort SET = 39; + public const ushort EI = 40; + public const ushort DI = 41; + public const ushort EXCH = 42; + public const ushort EXX = 43; + public const ushort EXCH_16 = 44; + public const ushort PREFIX = 45; + public const ushort PREFETCH = 46; + public const ushort ASGN = 47; + public const ushort ADDS = 48; // signed 16 bit operation used in 2 instructions + public const ushort INT_MODE = 49; + public const ushort EI_RETN = 50; + public const ushort EI_RETI = 51; // reti has no delay in interrupt enable + public const ushort OUT = 52; + public const ushort IN = 53; + public const ushort NEG = 54; + public const ushort RRD = 55; + public const ushort RLD = 56; + public const ushort SET_FL_LD = 57; + public const ushort SET_FL_CP = 58; + public const ushort SET_FL_IR = 59; + public const ushort I_BIT = 60; + public const ushort HL_BIT = 61; + + public byte temp_R; + + public Z80A() + { + Reset(); + InitTableParity(); + } + + public void Reset() + { + ResetRegisters(); + ResetInterrupts(); + TotalExecutedCycles = 0; + cur_instr = new ushort[] { OP }; + instr_pntr = 0; + NO_prefix = true; + } + + public IMemoryCallbackSystem MemoryCallbacks { get; set; } + + // Memory Access + public Func FetchMemory; + public Func ReadMemory; + public Action WriteMemory; + public Func PeekMemory; + public Func DummyReadMemory; + + // Hardware I/O Port Access + public Func ReadHardware; + public Action WriteHardware; + + //this only calls when the first byte of an instruction is fetched. + public Action OnExecFetch; + + public void UnregisterMemoryMapper() + { + ReadMemory = null; + WriteMemory = null; + PeekMemory = null; + DummyReadMemory = null; + ReadHardware = null; + WriteHardware = null; + } + + public void SetCallbacks + ( + Func ReadMemory, + Func DummyReadMemory, + Func PeekMemory, + Action WriteMemory, + Func ReadHardware, + Action WriteHardware + ) + { + this.ReadMemory = ReadMemory; + this.DummyReadMemory = DummyReadMemory; + this.PeekMemory = PeekMemory; + this.WriteMemory = WriteMemory; + this.ReadHardware = ReadHardware; + this.WriteHardware = WriteHardware; + } + + // Execute instructions + public void ExecuteOne() + { + if (Regs[A] > 255) { Console.WriteLine(RegPC); } + switch (cur_instr[instr_pntr++]) + { + case IDLE: + // do nothing + break; + case OP: + // Read the opcode of the next instruction + if (EI_pending > 0) + { + EI_pending--; + if (EI_pending == 0) { IFF1 = IFF2 = true; } + } + + // Process interrupt requests. + if (nonMaskableInterruptPending) + { + nonMaskableInterruptPending = false; + + if (TraceCallback != null) + { + TraceCallback(new TraceInfo{Disassembly = "====NMI====", RegisterInfo = ""}); + } + + iff2 = iff1; + iff1 = false; + NMI_(); + NMICallback(); + } + else if (iff1 && FlagI) + { + iff1 = iff2 = false; + EI_pending = 0; + + if (TraceCallback != null) + { + TraceCallback(new TraceInfo{Disassembly = "====IRQ====", RegisterInfo = ""}); + } + + switch (interruptMode) + { + case 0: + // Requires something to be pushed onto the data bus + // we'll assume it's a zero for now + INTERRUPT_0(0); + break; + case 1: + INTERRUPT_1(); + break; + case 2: + // Low byte of interrupt vector comes from data bus + // We'll assume it's zero for now + INTERRUPT_2(0); + break; + } + IRQCallback(); + } + else + { + if (OnExecFetch != null) OnExecFetch(RegPC); + if (TraceCallback != null) TraceCallback(State()); + FetchInstruction(FetchMemory(RegPC++)); + } + instr_pntr = 0; + + temp_R = (byte)(Regs[R] & 0x7F); + temp_R++; + temp_R &= 0x7F; + Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); + break; + case OP_R: + // determine if we repeat based on what operation we are doing + // single execution versions also come here, but never repeat + ushort temp1 = cur_instr[instr_pntr++]; + ushort temp2 = cur_instr[instr_pntr++]; + ushort temp3 = cur_instr[instr_pntr++]; + + bool repeat = false; + int Reg16_d = Regs[C] | (Regs[B] << 8); + switch (temp1) + { + case 0: + repeat = Reg16_d != 0; + break; + case 1: + repeat = (Reg16_d != 0) && !FlagZ; + break; + case 2: + repeat = Regs[B] != 0; + break; + case 3: + repeat = Regs[B] != 0; + break; + } + + // if we repeat, we do a 5 cycle refresh which decrements PC by 2 + // if we don't repeat, continue on as a normal opcode fetch + if (repeat && temp3 > 0) + { + cur_instr = new ushort[] + {IDLE, + DEC16, PCl, PCh, + IDLE, + DEC16, PCl, PCh, + OP }; + + // adjust WZ register accordingly + switch (temp1) + { + case 0: + // TEST: PC before or after the instruction? + Regs[Z] = Regs[PCl]; + Regs[W] = Regs[PCh]; + INC16_Func(Z, W); + break; + case 1: + // TEST: PC before or after the instruction? + Regs[Z] = Regs[PCl]; + Regs[W] = Regs[PCh]; + INC16_Func(Z, W); + break; + case 2: + // Nothing + break; + case 3: + // Nothing + break; + } + } + else + { + // Interrupts can occur at this point, so process them accordingly + // Read the opcode of the next instruction + if (EI_pending > 0) + { + EI_pending--; + if (EI_pending == 0) { IFF1 = IFF2 = true; } + } + + // Process interrupt requests. + if (nonMaskableInterruptPending) + { + nonMaskableInterruptPending = false; + + if (TraceCallback != null) + { + TraceCallback(new TraceInfo{Disassembly = "====NMI====", RegisterInfo = ""}); + } + + iff2 = iff1; + iff1 = false; + NMI_(); + NMICallback(); + } + else if (iff1 && FlagI) + { + iff1 = iff2 = false; + EI_pending = 0; + + if (TraceCallback != null) + { + TraceCallback(new TraceInfo{Disassembly = "====IRQ====", RegisterInfo = ""}); + } + + switch (interruptMode) + { + case 0: + // Requires something to be pushed onto the data bus + // we'll assume it's a zero for now + INTERRUPT_0(0); + break; + case 1: + INTERRUPT_1(); + break; + case 2: + // Low byte of interrupt vector comes from data bus + // We'll assume it's zero for now + INTERRUPT_2(0); + break; + } + IRQCallback(); + } + else + { + if (OnExecFetch != null) OnExecFetch(RegPC); + if (TraceCallback != null) TraceCallback(State()); + FetchInstruction(FetchMemory(RegPC++)); + } + + temp_R = (byte)(Regs[R] & 0x7F); + temp_R++; + temp_R &= 0x7F; + Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); + } + instr_pntr = 0; + break; + + case HALT: + halted = true; + if (EI_pending > 0) + { + EI_pending--; + if (EI_pending == 0) { IFF1 = IFF2 = true; } + } + + // Process interrupt requests. + if (nonMaskableInterruptPending) + { + nonMaskableInterruptPending = false; + + if (TraceCallback != null) + { + TraceCallback(new TraceInfo{Disassembly = "====NMI====", RegisterInfo = ""}); + } + + iff2 = iff1; + iff1 = false; + NMI_(); + NMICallback(); + halted = false; + } + else if (iff1 && FlagI) + { + iff1 = iff2 = false; + EI_pending = 0; + + if (TraceCallback != null) + { + TraceCallback(new TraceInfo{Disassembly = "====IRQ====", RegisterInfo = ""}); + } + + switch (interruptMode) + { + case 0: + // Requires something to be pushed onto the data bus + // we'll assume it's a zero for now + INTERRUPT_0(0); + break; + case 1: + INTERRUPT_1(); + break; + case 2: + // Low byte of interrupt vector comes from data bus + // We'll assume it's zero for now + INTERRUPT_2(0); + break; + } + IRQCallback(); + halted = false; + } + else + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + HALT }; + } + temp_R = (byte)(Regs[R] & 0x7F); + temp_R++; + temp_R &= 0x7F; + Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); + + instr_pntr = 0; + break; + case RD: + Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case WR: + Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case I_RD: + I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case I_WR: + I_Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case TR: + TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case TR16: + TR16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADD16: + ADD16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADD8: + ADD8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SUB8: + SUB8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADC8: + ADC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADC16: + ADC_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SBC8: + SBC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SBC16: + SBC_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case INC16: + INC16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case INC8: + INC8_Func(cur_instr[instr_pntr++]); + break; + case DEC16: + DEC16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case DEC8: + DEC8_Func(cur_instr[instr_pntr++]); + break; + case RLC: + RLC_Func(cur_instr[instr_pntr++]); + break; + case RL: + RL_Func(cur_instr[instr_pntr++]); + break; + case RRC: + RRC_Func(cur_instr[instr_pntr++]); + break; + case RR: + RR_Func(cur_instr[instr_pntr++]); + break; + case CPL: + CPL_Func(cur_instr[instr_pntr++]); + break; + case DA: + DA_Func(cur_instr[instr_pntr++]); + break; + case SCF: + SCF_Func(cur_instr[instr_pntr++]); + break; + case CCF: + CCF_Func(cur_instr[instr_pntr++]); + break; + case AND8: + AND8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case XOR8: + XOR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case OR8: + OR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case CP8: + CP8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SLA: + SLA_Func(cur_instr[instr_pntr++]); + break; + case SRA: + SRA_Func(cur_instr[instr_pntr++]); + break; + case SRL: + SRL_Func(cur_instr[instr_pntr++]); + break; + case SLL: + SLL_Func(cur_instr[instr_pntr++]); + break; + case BIT: + BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case I_BIT: + I_BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case RES: + RES_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SET: + SET_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case EI: + EI_pending = 2; + break; + case DI: + IFF1 = IFF2 = false; + break; + case EXCH: + EXCH_16_Func(F_s, A_s, F, A); + break; + case EXX: + EXCH_16_Func(C_s, B_s, C, B); + EXCH_16_Func(E_s, D_s, E, D); + EXCH_16_Func(L_s, H_s, L, H); + break; + case EXCH_16: + EXCH_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case PREFIX: + ushort prefix_src = cur_instr[instr_pntr++]; + NO_prefix = false; + if (prefix_src == CBpre) { CB_prefix = true; } + if (prefix_src == EXTDpre) { EXTD_prefix = true; } + if (prefix_src == IXpre) { IX_prefix = true; } + if (prefix_src == IYpre) { IY_prefix = true; } + if (prefix_src == IXCBpre) { IXCB_prefix = true; IXCB_prefetch = true; } + if (prefix_src == IYCBpre) { IYCB_prefix = true; IYCB_prefetch = true; } + + FetchInstruction(FetchMemory(RegPC++)); + instr_pntr = 0; + // only the first prefix in a double prefix increases R, although I don't know how / why + if (prefix_src < 4) + { + temp_R = (byte)(Regs[R] & 0x7F); + temp_R++; + temp_R &= 0x7F; + Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); + } + break; + case ASGN: + ASGN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADDS: + ADDS_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case EI_RETI: + // NOTE: This is needed for systems using multiple interrupt sources, it triggers the next interrupt + // Not currently implemented here + iff1 = iff2; + break; + case EI_RETN: + iff1 = iff2; + break; + case OUT: + OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case IN: + IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case NEG: + NEG_8_Func(cur_instr[instr_pntr++]); + break; + case INT_MODE: + interruptMode = cur_instr[instr_pntr++]; + break; + case RRD: + RRD_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case RLD: + RLD_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SET_FL_LD: + SET_FL_LD_Func(); + break; + case SET_FL_CP: + SET_FL_CP_Func(); + break; + case SET_FL_IR: + SET_FL_IR_Func(cur_instr[instr_pntr++]); + break; + } + totalExecutedCycles++; + } + + // tracer stuff + public Action TraceCallback; + + public string TraceHeader + { + get { return "Z80A: PC, machine code, mnemonic, operands, registers (AF, BC, DE, HL, IX, IY, SP, Cy), flags (CNP3H5ZS)"; } + } + + public TraceInfo State(bool disassemble = true) + { + ushort bytes_read = 0; + + string disasm = disassemble ? Disassemble(RegPC, ReadMemory, out bytes_read) : "---"; + string byte_code = null; + + for (ushort i = 0; i < bytes_read; i++) + { + byte_code += ReadMemory((ushort)(RegPC + i)).ToHexString(2); + if (i < (bytes_read - 1)) + { + byte_code += " "; + } + } + + return new TraceInfo + { + Disassembly = string.Format( + "{0:X4}: {1} {2}", + RegPC, + byte_code.PadRight(12), + disasm.PadRight(26)), + RegisterInfo = string.Format( + "AF:{0:X4} BC:{1:X4} DE:{2:X4} HL:{3:X4} IX:{4:X4} IY:{5:X4} SP:{6:X4} Cy:{7} {8}{9}{10}{11}{12}{13}{14}{15}{16}", + (Regs[A] << 8) + Regs[F], + (Regs[B] << 8) + Regs[C], + (Regs[D] << 8) + Regs[E], + (Regs[H] << 8) + Regs[L], + (Regs[Ixh] << 8) + Regs[Ixl], + (Regs[Iyh] << 8) + Regs[Iyl], + Regs[SPl] | (Regs[SPh] << 8), + TotalExecutedCycles, + FlagC ? "C" : "c", + FlagN ? "N" : "n", + FlagP ? "P" : "p", + Flag3 ? "3" : "-", + FlagH ? "H" : "h", + Flag5 ? "5" : "-", + FlagZ ? "Z" : "z", + FlagS ? "S" : "s", + FlagI ? "E" : "e") + }; + } + // State Save/Load + + public void SyncState(Serializer ser) + { + ser.BeginSection("Z80A"); + ser.Sync("Regs", ref Regs, false); + ser.Sync("NMI", ref nonMaskableInterrupt); + ser.Sync("NMIPending", ref nonMaskableInterruptPending); + ser.Sync("IM", ref interruptMode); + ser.Sync("IFF1", ref iff1); + ser.Sync("IFF2", ref iff2); + ser.Sync("Halted", ref halted); + ser.Sync("ExecutedCycles", ref totalExecutedCycles); + ser.Sync("EI_pending", ref EI_pending); + + ser.Sync("instruction_pointer", ref instr_pntr); + ser.Sync("current instruction", ref cur_instr, false); + ser.Sync("opcode", ref opcode); + ser.Sync("FlagI", ref FlagI); + + ser.Sync("NO Preifx", ref NO_prefix); + ser.Sync("CB Preifx", ref CB_prefix); + ser.Sync("IX_prefix", ref IX_prefix); + ser.Sync("IY_prefix", ref IY_prefix); + ser.Sync("IXCB_prefix", ref IXCB_prefix); + ser.Sync("IYCB_prefix", ref IYCB_prefix); + ser.Sync("EXTD_prefix", ref EXTD_prefix); + ser.Sync("IXCB_prefetch", ref IXCB_prefetch); + ser.Sync("IYCB_prefetch", ref IYCB_prefetch); + ser.Sync("PF", ref PF); + + ser.EndSection(); + } + } +} diff --git a/BizHawk.Emulation.Cores/Calculator/TI83.IDebuggable.cs b/BizHawk.Emulation.Cores/Calculator/TI83.IDebuggable.cs index ab88799f79..c5d795fcd5 100644 --- a/BizHawk.Emulation.Cores/Calculator/TI83.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Calculator/TI83.IDebuggable.cs @@ -12,36 +12,36 @@ namespace BizHawk.Emulation.Cores.Calculators { return new Dictionary { - ["A"] = _cpu.RegisterA, - ["AF"] = _cpu.RegisterAF, - ["B"] = _cpu.RegisterB, - ["BC"] = _cpu.RegisterBC, - ["C"] = _cpu.RegisterC, - ["D"] = _cpu.RegisterD, - ["DE"] = _cpu.RegisterDE, - ["E"] = _cpu.RegisterE, - ["F"] = _cpu.RegisterF, - ["H"] = _cpu.RegisterH, - ["HL"] = _cpu.RegisterHL, - ["I"] = _cpu.RegisterI, - ["IX"] = _cpu.RegisterIX, - ["IY"] = _cpu.RegisterIY, - ["L"] = _cpu.RegisterL, - ["PC"] = _cpu.RegisterPC, - ["R"] = _cpu.RegisterR, - ["Shadow AF"] = _cpu.RegisterShadowAF, - ["Shadow BC"] = _cpu.RegisterShadowBC, - ["Shadow DE"] = _cpu.RegisterShadowDE, - ["Shadow HL"] = _cpu.RegisterShadowHL, - ["SP"] = _cpu.RegisterSP, - ["Flag C"] = _cpu.RegisterF.Bit(0), - ["Flag N"] = _cpu.RegisterF.Bit(1), - ["Flag P/V"] = _cpu.RegisterF.Bit(2), - ["Flag 3rd"] = _cpu.RegisterF.Bit(3), - ["Flag H"] = _cpu.RegisterF.Bit(4), - ["Flag 5th"] = _cpu.RegisterF.Bit(5), - ["Flag Z"] = _cpu.RegisterF.Bit(6), - ["Flag S"] = _cpu.RegisterF.Bit(7) + ["A"] = _cpu.Regs[_cpu.A], + ["AF"] = _cpu.Regs[_cpu.F] + (_cpu.Regs[_cpu.A] << 8), + ["B"] = _cpu.Regs[_cpu.B], + ["BC"] = _cpu.Regs[_cpu.C] + (_cpu.Regs[_cpu.B] << 8), + ["C"] = _cpu.Regs[_cpu.C], + ["D"] = _cpu.Regs[_cpu.D], + ["DE"] = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8), + ["E"] = _cpu.Regs[_cpu.E], + ["F"] = _cpu.Regs[_cpu.F], + ["H"] = _cpu.Regs[_cpu.H], + ["HL"] = _cpu.Regs[_cpu.L] + (_cpu.Regs[_cpu.H] << 8), + ["I"] = _cpu.Regs[_cpu.I], + ["IX"] = _cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8), + ["IY"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8), + ["L"] = _cpu.Regs[_cpu.L], + ["PC"] = _cpu.Regs[_cpu.PCl] + (_cpu.Regs[_cpu.PCh] << 8), + ["R"] = _cpu.Regs[_cpu.R], + ["Shadow AF"] = _cpu.Regs[_cpu.F_s] + (_cpu.Regs[_cpu.A_s] << 8), + ["Shadow BC"] = _cpu.Regs[_cpu.C_s] + (_cpu.Regs[_cpu.B_s] << 8), + ["Shadow DE"] = _cpu.Regs[_cpu.E_s] + (_cpu.Regs[_cpu.D_s] << 8), + ["Shadow HL"] = _cpu.Regs[_cpu.L_s] + (_cpu.Regs[_cpu.H_s] << 8), + ["SP"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8), + ["Flag C"] = _cpu.FlagC, + ["Flag N"] = _cpu.FlagN, + ["Flag P/V"] = _cpu.FlagP, + ["Flag 3rd"] = _cpu.Flag3, + ["Flag H"] = _cpu.FlagH, + ["Flag 5th"] = _cpu.Flag5, + ["Flag Z"] = _cpu.FlagZ, + ["Flag S"] = _cpu.FlagS }; } @@ -49,78 +49,90 @@ namespace BizHawk.Emulation.Cores.Calculators { switch (register) { - default: - throw new InvalidOperationException(); - case "A": - _cpu.RegisterA = (byte)value; - break; - case "AF": - _cpu.RegisterAF = (byte)value; - break; - case "B": - _cpu.RegisterB = (byte)value; - break; - case "BC": - _cpu.RegisterBC = (byte)value; - break; - case "C": - _cpu.RegisterC = (byte)value; - break; - case "D": - _cpu.RegisterD = (byte)value; - break; - case "DE": - _cpu.RegisterDE = (byte)value; - break; - case "E": - _cpu.RegisterE = (byte)value; - break; - case "F": - _cpu.RegisterF = (byte)value; - break; - case "H": - _cpu.RegisterH = (byte)value; - break; - case "HL": - _cpu.RegisterHL = (byte)value; - break; - case "I": - _cpu.RegisterI = (byte)value; - break; - case "IX": - _cpu.RegisterIX = (byte)value; - break; - case "IY": - _cpu.RegisterIY = (byte)value; - break; - case "L": - _cpu.RegisterL = (byte)value; - break; - case "PC": - _cpu.RegisterPC = (ushort)value; - break; - case "R": - _cpu.RegisterR = (byte)value; - break; - case "Shadow AF": - _cpu.RegisterShadowAF = (byte)value; - break; - case "Shadow BC": - _cpu.RegisterShadowBC = (byte)value; - break; - case "Shadow DE": - _cpu.RegisterShadowDE = (byte)value; - break; - case "Shadow HL": - _cpu.RegisterShadowHL = (byte)value; - break; - case "SP": - _cpu.RegisterSP = (byte)value; + default: + throw new InvalidOperationException(); + case "A": + _cpu.Regs[_cpu.A] = (ushort)value; + break; + case "AF": + _cpu.Regs[_cpu.F] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.A] = (ushort)(value & 0xFF00); + break; + case "B": + _cpu.Regs[_cpu.B] = (ushort)value; + break; + case "BC": + _cpu.Regs[_cpu.C] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.B] = (ushort)(value & 0xFF00); + break; + case "C": + _cpu.Regs[_cpu.C] = (ushort)value; + break; + case "D": + _cpu.Regs[_cpu.D] = (ushort)value; + break; + case "DE": + _cpu.Regs[_cpu.E] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.D] = (ushort)(value & 0xFF00); + break; + case "E": + _cpu.Regs[_cpu.E] = (ushort)value; + break; + case "F": + _cpu.Regs[_cpu.F] = (ushort)value; + break; + case "H": + _cpu.Regs[_cpu.H] = (ushort)value; + break; + case "HL": + _cpu.Regs[_cpu.L] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.H] = (ushort)(value & 0xFF00); + break; + case "I": + _cpu.Regs[_cpu.I] = (ushort)value; + break; + case "IX": + _cpu.Regs[_cpu.Ixl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.Ixh] = (ushort)(value & 0xFF00); + break; + case "IY": + _cpu.Regs[_cpu.Iyl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.Iyh] = (ushort)(value & 0xFF00); + break; + case "L": + _cpu.Regs[_cpu.L] = (ushort)value; + break; + case "PC": + _cpu.Regs[_cpu.PCl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.PCh] = (ushort)(value & 0xFF00); + break; + case "R": + _cpu.Regs[_cpu.R] = (ushort)value; + break; + case "Shadow AF": + _cpu.Regs[_cpu.F_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.A_s] = (ushort)(value & 0xFF00); + break; + case "Shadow BC": + _cpu.Regs[_cpu.C_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.B_s] = (ushort)(value & 0xFF00); + break; + case "Shadow DE": + _cpu.Regs[_cpu.E_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.D_s] = (ushort)(value & 0xFF00); + break; + case "Shadow HL": + _cpu.Regs[_cpu.L_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.H_s] = (ushort)(value & 0xFF00); + break; + case "SP": + _cpu.Regs[_cpu.SPl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.SPh] = (ushort)(value & 0xFF00); break; } } - public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(); + public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" }); [FeatureNotImplemented] public void Step(StepType type) diff --git a/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs b/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs index f1de9171dd..622664bcc7 100644 --- a/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs @@ -13,21 +13,42 @@ namespace BizHawk.Emulation.Cores.Calculators _controller = controller; _lagged = true; - _cpu.Debug = _tracer.Enabled; - - if (_cpu.Debug && _cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first + if (_tracer.Enabled) { - _cpu.Logger = s => _tracer.Put(s); + _cpu.TraceCallback = s => _tracer.Put(s); + } + else + { + _cpu.TraceCallback = null; } - // I eyeballed this speed - for (int i = 0; i < 5; i++) - { - _onPressed = controller.IsPressed("ON"); + _onPressed = controller.IsPressed("ON"); - // and this was derived from other emus - _cpu.ExecuteCycles(10000); - _cpu.Interrupt = true; + if (_onPressed && ON_key_int_EN && !ON_key_int) + { + ON_key_int = true; + _cpu.FlagI = true; + } + + // see: http://wikiti.brandonw.net/index.php?title=83:Ports:04 + // for timer interrupt frequency + + // CPU frequency is 6MHz + for (int i = 0; i < 100000; i++) + { + _cpu.ExecuteOne(); + + TIM_count++; + if (TIM_count >= TIM_hit) + { + TIM_count = 0; + + if (TIM_1_int_EN) + { + TIM_1_int = true; + _cpu.FlagI = true; + } + } } Frame++; diff --git a/BizHawk.Emulation.Cores/Calculator/TI83.IStatable.cs b/BizHawk.Emulation.Cores/Calculator/TI83.IStatable.cs index e6927d9962..d2bd9192ca 100644 --- a/BizHawk.Emulation.Cores/Calculator/TI83.IStatable.cs +++ b/BizHawk.Emulation.Cores/Calculator/TI83.IStatable.cs @@ -7,55 +7,52 @@ namespace BizHawk.Emulation.Cores.Calculators { public partial class TI83 : IStatable { - private byte[] _stateBuffer; + public bool BinarySaveStatesPreferred + { + get { return true; } + } - public bool BinarySaveStatesPreferred => false; + public void SaveStateText(TextWriter writer) + { + SyncState(new Serializer(writer)); + } + + public void LoadStateText(TextReader reader) + { + SyncState(new Serializer(reader)); + } public void SaveStateBinary(BinaryWriter bw) { - SyncState(Serializer.CreateBinaryWriter(bw)); + SyncState(new Serializer(bw)); } public void LoadStateBinary(BinaryReader br) { - SyncState(Serializer.CreateBinaryReader(br)); - } - - public void SaveStateText(TextWriter tw) - { - SyncState(Serializer.CreateTextWriter(tw)); - } - - public void LoadStateText(TextReader tr) - { - SyncState(Serializer.CreateTextReader(tr)); + SyncState(new Serializer(br)); } public byte[] SaveStateBinary() { - if (_stateBuffer == null) - { - var stream = new MemoryStream(); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - _stateBuffer = stream.ToArray(); - writer.Close(); - return _stateBuffer; - } - else - { - var stream = new MemoryStream(_stateBuffer); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - writer.Close(); - return _stateBuffer; - } + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + return ms.ToArray(); } private void SyncState(Serializer ser) { - ser.BeginSection("TI83"); + byte[] core = null; + if (ser.IsWriter) + { + var ms = new MemoryStream(); + ms.Close(); + core = ms.ToArray(); + } _cpu.SyncState(ser); + + ser.BeginSection("TI83"); ser.Sync("RAM", ref _ram, false); ser.Sync("romPageLow3Bits", ref _romPageLow3Bits); ser.Sync("romPageHighBit", ref _romPageHighBit); @@ -72,6 +69,15 @@ namespace BizHawk.Emulation.Cores.Calculators ser.Sync("Frame", ref _frame); ser.Sync("LagCount", ref _lagCount); ser.Sync("IsLag", ref _isLag); + ser.Sync("ON_key_int", ref ON_key_int); + ser.Sync("ON_key_int_EN", ref ON_key_int_EN); + ser.Sync("TIM_1_int", ref TIM_1_int); + ser.Sync("TIM_1_int_EN", ref TIM_1_int_EN); + ser.Sync("TIM_frq", ref TIM_frq); + ser.Sync("TIM_mult", ref TIM_mult); + ser.Sync("TIM_count", ref TIM_count); + ser.Sync("TIM_hit", ref TIM_hit); + ser.EndSection(); if (ser.IsReader) diff --git a/BizHawk.Emulation.Cores/Calculator/TI83.cs b/BizHawk.Emulation.Cores/Calculator/TI83.cs index 53a69072b6..cfe82f74eb 100644 --- a/BizHawk.Emulation.Cores/Calculator/TI83.cs +++ b/BizHawk.Emulation.Cores/Calculator/TI83.cs @@ -2,7 +2,7 @@ using System; using System.Globalization; using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Components.Z80; +using BizHawk.Emulation.Cores.Components.Z80A; // http://www.ticalc.org/pub/text/calcinfo/ namespace BizHawk.Emulation.Cores.Calculators @@ -23,6 +23,7 @@ namespace BizHawk.Emulation.Cores.Calculators PutSettings((TI83Settings)settings ?? new TI83Settings()); CoreComm = comm; + _cpu.FetchMemory = ReadMemory; _cpu.ReadMemory = ReadMemory; _cpu.WriteMemory = WriteMemory; _cpu.ReadHardware = ReadHardware; @@ -34,21 +35,13 @@ namespace BizHawk.Emulation.Cores.Calculators _rom = rom; LinkPort = new TI83LinkPort(this); - // different calculators (different revisions?) have different initPC. we track this in the game database by rom hash - // if( *(unsigned long *)(m_pRom + 0x6ce) == 0x04D3163E ) m_Regs.PC.W = 0x6ce; //KNOWN - // else if( *(unsigned long *)(m_pRom + 0x6f6) == 0x04D3163E ) m_Regs.PC.W = 0x6f6; //UNKNOWN - if (game["initPC"]) - { - _startPC = ushort.Parse(game.OptionValue("initPC"), NumberStyles.HexNumber); - } - HardReset(); SetupMemoryDomains(); _tracer = new TraceBuffer { Header = _cpu.TraceHeader }; ser.Register(_tracer); - ser.Register(new Disassembler()); + ser.Register(_cpu); } private readonly TraceBuffer _tracer; @@ -57,8 +50,6 @@ namespace BizHawk.Emulation.Cores.Calculators private readonly byte[] _rom; // configuration - private readonly ushort _startPC; - private IController _controller; private byte[] _ram; @@ -75,6 +66,10 @@ namespace BizHawk.Emulation.Cores.Calculators private bool _cursorMoved; private int _frame; + public bool ON_key_int, ON_key_int_EN; + public bool TIM_1_int, TIM_1_int_EN; + public int TIM_frq, TIM_mult, TIM_count, TIM_hit; + // Link Cable public TI83LinkPort LinkPort { get; } @@ -151,7 +146,7 @@ namespace BizHawk.Emulation.Cores.Calculators if (LinkActive) { // Prevent rom calls from disturbing link port activity - if (LinkActive && _cpu.RegisterPC < 0x4000) + if (LinkActive && _cpu.RegPC < 0x4000) { return; } @@ -169,7 +164,60 @@ namespace BizHawk.Emulation.Cores.Calculators _romPageLow3Bits = value & 0x7; break; case 3: // PORT_STATUS - _maskOn = (byte)(value & 1); + // controls ON key interrupts + if ((value & 0x1) == 0) + { + ON_key_int = false; + ON_key_int_EN = false; + } + else + { + ON_key_int_EN = true; + } + + // controls first timer interrupts + if ((value & 0x2) == 0) + { + TIM_1_int = false; + TIM_1_int_EN = false; + } + else + { + TIM_1_int_EN = true; + } + + // controls second timer, not yet implemented and unclear how to differentiate + if ((value & 0x4) == 0) + { + } + else + { + } + + // controls low power mode, not yet implemeneted + if ((value & 0x8) == 0) + { + } + else + { + } + break; + case 4: // PORT_INTCTRL + // controls ON key interrupts + TIM_frq = value & 6; + + TIM_mult = ((value & 0x10) == 0x10) ? 1800 : 1620; + + TIM_hit = (int)Math.Floor((double)TIM_mult / (3 + TIM_frq * 2)); + + TIM_hit = (int)Math.Floor((double)6000000 / TIM_hit); + + // Bit 0 is some form of memory mapping + + // Bit 5 controls reset + + // Bit 6-7 controls battery power compare (not implemented, will always return full power) + break; case 16: // PORT_DISPCTRL ////Console.WriteLine("write PORT_DISPCTRL {0}",value); @@ -198,22 +246,23 @@ namespace BizHawk.Emulation.Cores.Calculators { // Console.WriteLine("read PORT_STATUS"); // Bits: - // 0 - Set if ON key is down and ON key is trapped + // 0 - Set if ON key Interrupt generated // 1 - Update things (keyboard etc) // 2 - Unknown, but used // 3 - Set if ON key is up // 4-7 - Unknown - ////if (onPressed && maskOn) ret |= 1; - ////if (!onPressed) ret |= 0x8; - return (byte)((_controller.IsPressed("ON") ? _maskOn : 8) | (LinkActive ? 0 : 2)); + + return (byte)((_controller.IsPressed("ON") ? 0 : 8) | + (TIM_1_int ? 2 : 0) | + (ON_key_int ? 1 : 0)); } case 4: // PORT_INTCTRL - ////Console.WriteLine("read PORT_INTCTRL"); - return 0xFF; + // returns mirror of link port + return (byte)((_romPageHighBit << 4) | (LinkState << 2) | LinkOutput); case 16: // PORT_DISPCTRL - ////Console.WriteLine("read DISPCTRL"); + // Console.WriteLine("read DISPCTRL"); break; case 17: // PORT_DISPDATA @@ -428,13 +477,13 @@ namespace BizHawk.Emulation.Cores.Calculators private void IRQCallback() { - // Console.WriteLine("IRQ with vec {0} and cpu.InterruptMode {1}", cpu.RegisterI, cpu.InterruptMode); - _cpu.Interrupt = false; + //Console.WriteLine("IRQ with vec {0} and cpu.InterruptMode {1}", _cpu.Regs[_cpu.I], _cpu.InterruptMode); + _cpu.FlagI = false; } private void NMICallback() { - Console.WriteLine("NMI"); + //Console.WriteLine("NMI"); _cpu.NonMaskableInterrupt = false; } @@ -447,7 +496,7 @@ namespace BizHawk.Emulation.Cores.Calculators _ram[i] = 0xFF; } - _cpu.RegisterPC = _startPC; + _cpu.RegPC = 0; _cpu.IFF1 = false; _cpu.IFF2 = false; @@ -463,4 +512,4 @@ namespace BizHawk.Emulation.Cores.Calculators _displayX = _displayY = 0; } } -} \ No newline at end of file +} diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IDebuggable.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IDebuggable.cs index 601bc3f0cc..f36cef6f8a 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IDebuggable.cs @@ -73,7 +73,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII } } - public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(); + public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" }); public bool CanStep(StepType type) { diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs index 7c86c1e8eb..e67abf06ef 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs @@ -183,9 +183,9 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII private void SetCallbacks() { - _machine.Memory.ReadCallback = MemoryCallbacks.CallReads; - _machine.Memory.WriteCallback = MemoryCallbacks.CallWrites; - _machine.Memory.ExecuteCallback = MemoryCallbacks.CallExecutes; + _machine.Memory.ReadCallback = (addr) => MemoryCallbacks.CallReads(addr, "System Bus"); + _machine.Memory.WriteCallback = (addr) => MemoryCallbacks.CallWrites(addr, "System Bus"); + _machine.Memory.ExecuteCallback = (addr) => MemoryCallbacks.CallExecutes(addr, "System Bus"); _machine.Memory.InputCallback = InputCallbacks.Call; } } diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.cs index ebc7cf25ec..0e17385256 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.cs @@ -32,7 +32,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 Init(SyncSettings.VicType, Settings.BorderType, SyncSettings.SidType, SyncSettings.TapeDriveType, SyncSettings.DiskDriveType); _cyclesPerFrame = _board.Vic.CyclesPerFrame; - _memoryCallbacks = new MemoryCallbackSystem(); + _memoryCallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); HardReset(); diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Chip6510.IDebuggable.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Chip6510.IDebuggable.cs index fc94e3c286..b64b70cb3e 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Chip6510.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Chip6510.IDebuggable.cs @@ -148,6 +148,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS private const byte JsrSize = 3; - IMemoryCallbackSystem IDebuggable.MemoryCallbacks { get; } = new MemoryCallbackSystem(); + IMemoryCallbackSystem IDebuggable.MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" }); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs index bbfdb5e569..e6fa2f8307 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs @@ -21,7 +21,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 private IController _controller; private int _frame; private int _lastAddress; - private bool _frameStartPending = true; private bool _leftDifficultySwitchPressed; private bool _rightDifficultySwitchPressed; @@ -34,6 +33,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 internal byte[] Rom { get; } internal int DistinctAccessCount { get; private set; } + // keeps track of tia cycles, 3 cycles per CPU cycle + private int cyc_counter; + private static MapperBase SetMultiCartMapper(int romLength, int gameTotal) { switch (romLength / gameTotal) @@ -134,7 +136,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _mapper.Bit13 = addr.Bit(13); var temp = _mapper.ReadMemory((ushort)(addr & 0x1FFF)); _tia.BusState = temp; - MemoryCallbacks.CallReads(addr); + MemoryCallbacks.CallReads(addr, "System Bus"); return temp; } @@ -155,7 +157,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _mapper.WriteMemory((ushort)(addr & 0x1FFF), value); - MemoryCallbacks.CallWrites(addr); + MemoryCallbacks.CallWrites(addr, "System Bus"); } internal void PokeMemory(ushort addr, byte value) @@ -165,7 +167,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 private void ExecFetch(ushort addr) { - MemoryCallbacks.CallExecutes(addr); + MemoryCallbacks.CallExecutes(addr, "System Bus"); } private void RebootCore() @@ -319,17 +321,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _m6532 = new M6532(this); - // Set up the system state here. for instance.. - // Read from the reset vector for where to start - Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC + HardReset(); // Show mapper class on romstatusdetails CoreComm.RomStatusDetails = $"{this._game.Name}\r\nSHA1:{Rom.HashSHA1()}\r\nMD5:{Rom.HashMD5()}\r\nMapper Impl \"{_mapper.GetType()}\""; - - // as it turns out, the stack pointer cannot be set to 0 for some games as they do not initilize it themselves. - // some documentation seems to indicate it should beset to FD, but currently there is no documentation of the 6532 - // executing a reset sequence at power on, but it's needed so let's hard code it for now - Cpu.S = 0xFD; } private bool _pal; @@ -349,96 +344,28 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 }; _tia.Reset(); - _m6532 = new M6532(this); - Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC - - // as it turns out, the stack pointer cannot be set to 0 for some games as they do not initilize it themselves. - // some documentation seems to indicate it should beset to FD, but currently there is no documentation of the 6532 - // executing a reset sequence at power on, but it's needed so let's hard code it for now - Cpu.S = 0xFD; - SetupMemoryDomains(); - } - - private void VFrameAdvance() // advance up to 500 lines looking for end of video frame - // after vsync falling edge, continues to end of next line - { - bool frameend = false; - _tia.FrameEndCallBack = (n) => frameend = true; - for (int i = 0; i < 500 && !frameend; i++) - { - ScanlineAdvance(); - } - - _tia.FrameEndCallBack = null; - } - - private void StartFrameCond() - { - if (_frameStartPending) - { - _frame++; - _islag = true; - - if (_controller.IsPressed("Power")) - { - HardReset(); - } - - if (_controller.IsPressed("Toggle Left Difficulty") && !_leftDifficultySwitchHeld) - { - _leftDifficultySwitchPressed ^= true; - _leftDifficultySwitchHeld = true; - } - else if (!_controller.IsPressed("Toggle Left Difficulty")) - { - _leftDifficultySwitchHeld = false; - } - - if (_controller.IsPressed("Toggle Right Difficulty") && !_rightDifficultySwitchHeld) - { - _rightDifficultySwitchPressed ^= true; - _rightDifficultySwitchHeld = true; - } - else if (!_controller.IsPressed("Toggle Right Difficulty")) - { - _rightDifficultySwitchHeld = false; - } - - _tia.BeginAudioFrame(); - _frameStartPending = false; - } - } - - private void FinishFrameCond() - { - if (_tia.LineCount >= _tia.NominalNumScanlines) - { - _tia.CompleteAudioFrame(); - if (_islag) - { - _lagcount++; - } - - _tia.LineCount = 0; - _frameStartPending = true; - } + cyc_counter = 0; } private void Cycle() { - _tia.Execute(1); - _tia.Execute(1); - _tia.Execute(1); - _m6532.Timer.Tick(); - if (Tracer.Enabled) + _tia.Execute(); + cyc_counter++; + if (cyc_counter == 3) { - Tracer.Put(Cpu.TraceState()); - } + _m6532.Timer.Tick(); + if (Tracer.Enabled) + { + Tracer.Put(Cpu.TraceState()); + } - Cpu.ExecuteOne(); - _mapper.ClockCpu(); + Cpu.ExecuteOne(); + _mapper.ClockCpu(); + + cyc_counter = 0; + } } internal byte ReadControls1(bool peek) diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IDebuggable.cs index cf7ae45ba1..75c16f62ff 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IDebuggable.cs @@ -56,101 +56,22 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } } - public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(); + public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" }); public bool CanStep(StepType type) { - switch (type) - { - case StepType.Into: - case StepType.Out: - case StepType.Over: - return true; - default: - return false; - } + return false; } [FeatureNotImplemented] public void Step(StepType type) { - switch (type) - { - case StepType.Into: - StepInto(); - break; - case StepType.Out: - StepOut(); - break; - case StepType.Over: - StepOver(); - break; - } + throw new NotImplementedException(); } + public int TotalExecutedCycles => Cpu.TotalExecutedCycles; - private void StepInto() - { - do - { - CycleAdvance(); - } while (!Cpu.AtStart); - } - - private void StepOver() - { - var instruction = Cpu.PeekMemory(Cpu.PC); - - if (instruction == JSR) - { - var destination = Cpu.PC + opsize[JSR]; - while (Cpu.PC != destination) - { - StepInto(); - } - } - else - { - StepInto(); - } - } - - private void StepOut() - { - var instruction = Cpu.PeekMemory(Cpu.PC); - - JSRCount = instruction == JSR ? 1 : 0; - - var bailOutFrame = Frame + 1; - while (true) - { - StepInto(); - var instr = Cpu.PeekMemory(Cpu.PC); - if (instr == JSR) - { - JSRCount++; - } - else if (instr == RTS && JSRCount <= 0) - { - StepInto(); - JSRCount = 0; - break; - } - else if (instr == RTS) - { - JSRCount--; - } - else // Emergency bail out logic - { - if (Frame == bailOutFrame) - { - break; - } - } - } - } - private int JSRCount = 0; private const byte JSR = 0x20; @@ -212,22 +133,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 #region Currently Unused Debug hooks - private void ScanlineAdvance() - { - StartFrameCond(); - int currentLine = _tia.LineCount; - while (_tia.LineCount == currentLine) - Cycle(); - FinishFrameCond(); - } - - private void CycleAdvance() - { - StartFrameCond(); - Cycle(); - FinishFrameCond(); - } - private int CurrentScanLine { get { return _tia.LineCount; } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs index 65d910b1c1..13164fdd0f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs @@ -1,4 +1,5 @@ using BizHawk.Emulation.Common; +using System; namespace BizHawk.Emulation.Cores.Atari.Atari2600 { @@ -12,18 +13,56 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 { _controller = controller; - StartFrameCond(); - while (_tia.LineCount < _tia.NominalNumScanlines) + _frame++; + _islag = true; + + // Handle all the console controls here + if (_controller.IsPressed("Power")) + { + HardReset(); + } + + if (_controller.IsPressed("Toggle Left Difficulty") && !_leftDifficultySwitchHeld) + { + _leftDifficultySwitchPressed ^= true; + _leftDifficultySwitchHeld = true; + } + else if (!_controller.IsPressed("Toggle Left Difficulty")) + { + _leftDifficultySwitchHeld = false; + } + + if (_controller.IsPressed("Toggle Right Difficulty") && !_rightDifficultySwitchHeld) + { + _rightDifficultySwitchPressed ^= true; + _rightDifficultySwitchHeld = true; + } + else if (!_controller.IsPressed("Toggle Right Difficulty")) + { + _rightDifficultySwitchHeld = false; + } + + int count = 0; + while (!_tia.New_Frame) { Cycle(); + count++; + if (count > 1000000) { throw new Exception("ERROR: Unable to resolve Frame. Please Report."); } } + _tia.New_Frame = false; + if (rendersound == false) { _tia.AudioClocks = 0; // we need this here since the async sound provider won't check in this case } - FinishFrameCond(); + if (_islag) + { + _lagcount++; + } + + _tia.LineCount = 0; } public int Frame => _frame; diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IStatable.cs index aa6d4e78b4..dcff99f432 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IStatable.cs @@ -46,7 +46,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 ser.Sync("Lag", ref _lagcount); ser.Sync("Frame", ref _frame); ser.Sync("IsLag", ref _islag); - ser.Sync("frameStartPending", ref _frameStartPending); + ser.Sync("cyc_counter", ref cyc_counter); ser.Sync("leftDifficultySwitchPressed", ref _leftDifficultySwitchPressed); ser.Sync("rightDifficultySwitchPressed", ref _rightDifficultySwitchPressed); ser.Sync("leftDifficultySwitchHeld", ref _leftDifficultySwitchHeld); diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs index 5a7d466c6f..311cd55e13 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs @@ -41,7 +41,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } if (Rom.HashSHA1() == "3A77DB43B6583E8689435F0F14AA04B9E57BDDED" || - Rom.HashSHA1() == "E986E1818E747BEB9B33CE4DFF1CDC6B55BDB620") + Rom.HashSHA1() == "E986E1818E747BEB9B33CE4DFF1CDC6B55BDB620" || + Rom.HashSHA1() == "982B8016B393A9AA7DD110295A53C4612ECF2141") { game.RemoveOption("m"); game.AddOption("m", "F8_sega"); @@ -102,18 +103,25 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 // give the emu a minimal of input\output connections so it doesn't crash var comm = new CoreComm(null, null); + + // here we advance past start up irregularities to see how long a frame is based on calls to Vsync + // we run 72 frames, then run 270 scanlines worth of cycles. + // if we don't hit a new frame, we can be pretty confident we are in PAL using (Atari2600 emu = new Atari2600(new CoreComm(null, null), newgame, rom, null, null)) { - List framecounts = new List(); - emu._tia.FrameEndCallBack = (i) => framecounts.Add(i); - for (int i = 0; i < 71; i++) // run for 71 * 262 lines, since we're in NTSC mode + for (int i = 0; i < 72; i++) { emu.FrameAdvance(NullController.Instance, false, false); } - int numpal = framecounts.Count((i) => i > 287); - bool pal = numpal >= 25; - Console.WriteLine("PAL Detection: {0} lines, {1}", numpal, pal); + for (int i = 0; i < 61560; i++) + { + emu.Cycle(); + } + + bool pal = !emu._tia.New_Frame; + + Console.WriteLine("PAL Detection: {0}", pal); return pal; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs index 1fd27cd171..af5ea5f124 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs @@ -35,6 +35,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _spf = _vsyncNum / (double)_vsyncDen > 55.0 ? 735 : 882; } + // indicates to the core where a new frame is starting + public bool New_Frame = false; + private const int BackColor = unchecked((int)0xff000000); private const int ScreenWidth = 160; private const int MaxScreenHeight = 312; @@ -161,11 +164,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 /// public int LineCount { get; set; } - /// - /// Gets or sets a callback that is called at the end of a video frame. used internally - /// - public Action FrameEndCallBack { private get; set; } - public void Reset() { _hsyncCnt = 0; @@ -229,11 +227,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } // Execute TIA cycles - public void Execute(int cycles) + public void Execute() { - // Still ignoring cycles... - - // delay vblank latch + // Handle all of the Latch delays that occur in the TIA if (_vblankDelay > 0) { _vblankDelay++; @@ -244,7 +240,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } } - // delay latch to new playfield register if (_pf0Updater) { _pf0DelayClock++; @@ -275,7 +270,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } } - // delay latch to missile enable if (_enam0Delay > 0) { _enam0Delay++; @@ -296,7 +290,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } } - // delay latch to ball enable if (_enambDelay > 0) { _enambDelay++; @@ -307,7 +300,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } } - // delay latch to player graphics registers if (_prg0Delay > 0) { _prg0Delay++; @@ -333,7 +325,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } } - // HMP write delay if (_hmp0Delay > 0) { _hmp0Delay++; @@ -773,9 +764,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 // do the audio sampling if (_hsyncCnt == 36 || _hsyncCnt == 148) { - LocalAudioCycles[AudioClocks] += (short)(AUD[0].Cycle() / 2); - LocalAudioCycles[AudioClocks] += (short)(AUD[1].Cycle() / 2); - AudioClocks++; + if (AudioClocks < 2000) + { + LocalAudioCycles[AudioClocks] += (short)(AUD[0].Cycle() / 2); + LocalAudioCycles[AudioClocks] += (short)(AUD[1].Cycle() / 2); + AudioClocks++; + } } // Increment the hsync counter @@ -796,7 +790,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 int topLine = _pal ? _core.Settings.PALTopLine : _core.Settings.NTSCTopLine; int bottomLine = _pal ? _core.Settings.PALBottomLine : _core.Settings.NTSCBottomLine; - // if vsync occured unexpectedly early, black out the remainer + // if vsync occured unexpectedly early, black out the remainder for (; validlines < bottomLine; validlines++) { for (int i = 0; i < 160; i++) @@ -972,7 +966,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 // write to frame buffer OutputFrame(_currentScanLine); - FrameEndCallBack?.Invoke(_currentScanLine); + New_Frame = true; // Clear all from last frame _currentScanLine = 0; @@ -1337,17 +1331,5 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 { AUDC, AUDF, AUDV } - - private int _frameStartCycles, _frameEndCycles; - - public void BeginAudioFrame() - { - _frameStartCycles = _core.Cpu.TotalExecutedCycles; - } - - public void CompleteAudioFrame() - { - _frameEndCycles = _core.Cpu.TotalExecutedCycles; - } } } \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/Tia.SyncState.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/Tia.SyncState.cs index 00aa6e7669..1f3807247a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/Tia.SyncState.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/Tia.SyncState.cs @@ -62,10 +62,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 ser.Sync("vblankEnabled", ref _vblankEnabled); ser.Sync("vsyncEnabled", ref _vsyncEnabled); ser.Sync("CurrentScanLine", ref _currentScanLine); - ser.Sync("scanlinebuffer", ref _scanlinebuffer, false); ser.Sync("AudioClocks", ref AudioClocks); - ser.Sync("FrameStartCycles", ref _frameStartCycles); - ser.Sync("FrameEndCycles", ref _frameEndCycles); + ser.Sync("New_Frame", ref New_Frame); ser.BeginSection("Player0"); _player0.SyncState(ser); diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IDebuggable.cs index 0a83661f8a..afdc4168bd 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IDebuggable.cs @@ -54,7 +54,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk } } - public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(); + public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" }); public bool CanStep(StepType type) { diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs index 9a15b34da5..6f2ce9b238 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs @@ -268,7 +268,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk private void ExecFetch(ushort addr) { - MemoryCallbacks.CallExecutes(addr); + MemoryCallbacks.CallExecutes(addr, "System Bus"); } private void Reset_Mapper(string m) diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/MemoryMap.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/MemoryMap.cs index 553613d004..94f9f476c4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/MemoryMap.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/MemoryMap.cs @@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk { public byte ReadMemory(ushort addr) { - MemoryCallbacks.CallReads(addr); + MemoryCallbacks.CallReads(addr, "System Bus"); if ((addr & 0xFCE0) == 0) { @@ -100,7 +100,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk public void WriteMemory(ushort addr, byte value) { - MemoryCallbacks.CallWrites(addr); + MemoryCallbacks.CallWrites(addr, "System Bus"); if ((addr & 0xFCE0) == 0) { diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs b/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs index f8db8a4b7c..e234ae4455 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs @@ -169,7 +169,7 @@ namespace BizHawk.Emulation.Cores.Atari.Lynx BoolButtons = { "Up", "Down", "Left", "Right", "A", "B", "Option 1", "Option 2", "Pause", "Power" }, }; - public ControllerDefinition ControllerDefinition { get { return LynxTroller; } } + public ControllerDefinition ControllerDefinition => LynxTroller; private LibLynx.Buttons GetButtons(IController controller) { diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllerDeck.cs index 2ad8b5cd5b..97a45d4e9b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllerDeck.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllerDeck.cs @@ -30,6 +30,10 @@ namespace BizHawk.Emulation.Cores.ColecoVision Name = "ColecoVision Basic Controller", BoolButtons = Port1.Definition.BoolButtons .Concat(Port2.Definition.BoolButtons) + .Concat(new[] + { + "Power", "Reset" + }) .ToList() }; diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllers.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllers.cs index a44baeb679..bf018db6b5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllers.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllers.cs @@ -38,7 +38,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision public byte Read(IController c, bool left_mode, int wheel) { - return 0; // needs checking + return 0x7F; // needs checking } public ControllerDefinition Definition { get; } diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IDebuggable.cs index 1c4e048e64..c48bbabf8f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IDebuggable.cs @@ -12,36 +12,36 @@ namespace BizHawk.Emulation.Cores.ColecoVision { return new Dictionary { - ["A"] = _cpu.RegisterA, - ["AF"] = _cpu.RegisterAF, - ["B"] = _cpu.RegisterB, - ["BC"] = _cpu.RegisterBC, - ["C"] = _cpu.RegisterC, - ["D"] = _cpu.RegisterD, - ["DE"] = _cpu.RegisterDE, - ["E"] = _cpu.RegisterE, - ["F"] = _cpu.RegisterF, - ["H"] = _cpu.RegisterH, - ["HL"] = _cpu.RegisterHL, - ["I"] = _cpu.RegisterI, - ["IX"] = _cpu.RegisterIX, - ["IY"] = _cpu.RegisterIY, - ["L"] = _cpu.RegisterL, - ["PC"] = _cpu.RegisterPC, - ["R"] = _cpu.RegisterR, - ["Shadow AF"] = _cpu.RegisterShadowAF, - ["Shadow BC"] = _cpu.RegisterShadowBC, - ["Shadow DE"] = _cpu.RegisterShadowDE, - ["Shadow HL"] = _cpu.RegisterShadowHL, - ["SP"] = _cpu.RegisterSP, - ["Flag C"] = _cpu.RegisterF.Bit(0), - ["Flag N"] = _cpu.RegisterF.Bit(1), - ["Flag P/V"] = _cpu.RegisterF.Bit(2), - ["Flag 3rd"] = _cpu.RegisterF.Bit(3), - ["Flag H"] = _cpu.RegisterF.Bit(4), - ["Flag 5th"] = _cpu.RegisterF.Bit(5), - ["Flag Z"] = _cpu.RegisterF.Bit(6), - ["Flag S"] = _cpu.RegisterF.Bit(7) + ["A"] = _cpu.Regs[_cpu.A], + ["AF"] = _cpu.Regs[_cpu.F] + (_cpu.Regs[_cpu.A] << 8), + ["B"] = _cpu.Regs[_cpu.B], + ["BC"] = _cpu.Regs[_cpu.C] + (_cpu.Regs[_cpu.B] << 8), + ["C"] = _cpu.Regs[_cpu.C], + ["D"] = _cpu.Regs[_cpu.D], + ["DE"] = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8), + ["E"] = _cpu.Regs[_cpu.E], + ["F"] = _cpu.Regs[_cpu.F], + ["H"] = _cpu.Regs[_cpu.H], + ["HL"] = _cpu.Regs[_cpu.L] + (_cpu.Regs[_cpu.H] << 8), + ["I"] = _cpu.Regs[_cpu.I], + ["IX"] = _cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8), + ["IY"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8), + ["L"] = _cpu.Regs[_cpu.L], + ["PC"] = _cpu.Regs[_cpu.PCl] + (_cpu.Regs[_cpu.PCh] << 8), + ["R"] = _cpu.Regs[_cpu.R], + ["Shadow AF"] = _cpu.Regs[_cpu.F_s] + (_cpu.Regs[_cpu.A_s] << 8), + ["Shadow BC"] = _cpu.Regs[_cpu.C_s] + (_cpu.Regs[_cpu.B_s] << 8), + ["Shadow DE"] = _cpu.Regs[_cpu.E_s] + (_cpu.Regs[_cpu.D_s] << 8), + ["Shadow HL"] = _cpu.Regs[_cpu.L_s] + (_cpu.Regs[_cpu.H_s] << 8), + ["SP"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8), + ["Flag C"] = _cpu.FlagC, + ["Flag N"] = _cpu.FlagN, + ["Flag P/V"] = _cpu.FlagP, + ["Flag 3rd"] = _cpu.Flag3, + ["Flag H"] = _cpu.FlagH, + ["Flag 5th"] = _cpu.Flag5, + ["Flag Z"] = _cpu.FlagZ, + ["Flag S"] = _cpu.FlagS }; } @@ -52,70 +52,82 @@ namespace BizHawk.Emulation.Cores.ColecoVision default: throw new InvalidOperationException(); case "A": - _cpu.RegisterA = (byte)value; + _cpu.Regs[_cpu.A] = (ushort)value; break; case "AF": - _cpu.RegisterAF = (byte)value; + _cpu.Regs[_cpu.F] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.A] = (ushort)(value & 0xFF00); break; case "B": - _cpu.RegisterB = (byte)value; + _cpu.Regs[_cpu.B] = (ushort)value; break; case "BC": - _cpu.RegisterBC = (byte)value; + _cpu.Regs[_cpu.C] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.B] = (ushort)(value & 0xFF00); break; case "C": - _cpu.RegisterC = (byte)value; + _cpu.Regs[_cpu.C] = (ushort)value; break; case "D": - _cpu.RegisterD = (byte)value; + _cpu.Regs[_cpu.D] = (ushort)value; break; case "DE": - _cpu.RegisterDE = (byte)value; + _cpu.Regs[_cpu.E] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.D] = (ushort)(value & 0xFF00); break; case "E": - _cpu.RegisterE = (byte)value; + _cpu.Regs[_cpu.E] = (ushort)value; break; case "F": - _cpu.RegisterF = (byte)value; + _cpu.Regs[_cpu.F] = (ushort)value; break; case "H": - _cpu.RegisterH = (byte)value; + _cpu.Regs[_cpu.H] = (ushort)value; break; case "HL": - _cpu.RegisterHL = (byte)value; + _cpu.Regs[_cpu.L] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.H] = (ushort)(value & 0xFF00); break; case "I": - _cpu.RegisterI = (byte)value; + _cpu.Regs[_cpu.I] = (ushort)value; break; case "IX": - _cpu.RegisterIX = (byte)value; + _cpu.Regs[_cpu.Ixl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.Ixh] = (ushort)(value & 0xFF00); break; case "IY": - _cpu.RegisterIY = (byte)value; + _cpu.Regs[_cpu.Iyl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.Iyh] = (ushort)(value & 0xFF00); break; case "L": - _cpu.RegisterL = (byte)value; + _cpu.Regs[_cpu.L] = (ushort)value; break; case "PC": - _cpu.RegisterPC = (ushort)value; + _cpu.Regs[_cpu.PCl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.PCh] = (ushort)(value & 0xFF00); break; case "R": - _cpu.RegisterR = (byte)value; + _cpu.Regs[_cpu.R] = (ushort)value; break; case "Shadow AF": - _cpu.RegisterShadowAF = (byte)value; + _cpu.Regs[_cpu.F_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.A_s] = (ushort)(value & 0xFF00); break; case "Shadow BC": - _cpu.RegisterShadowBC = (byte)value; + _cpu.Regs[_cpu.C_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.B_s] = (ushort)(value & 0xFF00); break; case "Shadow DE": - _cpu.RegisterShadowDE = (byte)value; + _cpu.Regs[_cpu.E_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.D_s] = (ushort)(value & 0xFF00); break; case "Shadow HL": - _cpu.RegisterShadowHL = (byte)value; + _cpu.Regs[_cpu.L_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.H_s] = (ushort)(value & 0xFF00); break; case "SP": - _cpu.RegisterSP = (byte)value; + _cpu.Regs[_cpu.SPl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.SPh] = (ushort)(value & 0xFF00); break; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs index 68d8493693..22e67db446 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs @@ -12,16 +12,30 @@ namespace BizHawk.Emulation.Cores.ColecoVision public void FrameAdvance(IController controller, bool render, bool renderSound) { _controller = controller; - _cpu.Debug = _tracer.Enabled; + + // NOTE: Need to research differences between reset and power cycle + if (_controller.IsPressed("Power")) + { + HardReset(); + } + + if (_controller.IsPressed("Reset")) + { + SoftReset(); + } + _frame++; _isLag = true; PSG.BeginFrame(_cpu.TotalExecutedCycles); - if (_cpu.Debug && _cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first + if (_tracer.Enabled) { - _cpu.Logger = (s) => _tracer.Put(s); + _cpu.TraceCallback = s => _tracer.Put(s); + } + else + { + _cpu.TraceCallback = null; } - byte tempRet1 = ControllerDeck.ReadPort1(controller, true, true); byte tempRet2 = ControllerDeck.ReadPort2(controller, true, true); diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IStatable.cs index 62b5297675..d079fa50f4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IStatable.cs @@ -7,53 +7,52 @@ namespace BizHawk.Emulation.Cores.ColecoVision { public partial class ColecoVision : IStatable { - public bool BinarySaveStatesPreferred => false; + public bool BinarySaveStatesPreferred + { + get { return true; } + } + + public void SaveStateText(TextWriter writer) + { + SyncState(new Serializer(writer)); + } + + public void LoadStateText(TextReader reader) + { + SyncState(new Serializer(reader)); + } public void SaveStateBinary(BinaryWriter bw) { - SyncState(Serializer.CreateBinaryWriter(bw)); + SyncState(new Serializer(bw)); } public void LoadStateBinary(BinaryReader br) { - SyncState(Serializer.CreateBinaryReader(br)); - } - - public void SaveStateText(TextWriter tw) - { - SyncState(Serializer.CreateTextWriter(tw)); - } - - public void LoadStateText(TextReader tr) - { - SyncState(Serializer.CreateTextReader(tr)); + SyncState(new Serializer(br)); } public byte[] SaveStateBinary() { - if (_stateBuffer == null) - { - var stream = new MemoryStream(); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - _stateBuffer = stream.ToArray(); - writer.Close(); - return _stateBuffer; - } - else - { - var stream = new MemoryStream(_stateBuffer); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - writer.Close(); - return _stateBuffer; - } + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + return ms.ToArray(); } private void SyncState(Serializer ser) { - ser.BeginSection("Coleco"); + byte[] core = null; + if (ser.IsWriter) + { + var ms = new MemoryStream(); + ms.Close(); + core = ms.ToArray(); + } _cpu.SyncState(ser); + + ser.BeginSection("Coleco"); _vdp.SyncState(ser); PSG.SyncState(ser); ser.Sync("RAM", ref _ram, false); diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.cs index 21f5bb535c..070c8a2655 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.cs @@ -1,6 +1,6 @@ using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Components; -using BizHawk.Emulation.Cores.Components.Z80; +using BizHawk.Emulation.Cores.Components.Z80A; namespace BizHawk.Emulation.Cores.ColecoVision { @@ -17,13 +17,14 @@ namespace BizHawk.Emulation.Cores.ColecoVision { var ser = new BasicServiceProvider(this); ServiceProvider = ser; - MemoryCallbacks = new MemoryCallbackSystem(); + MemoryCallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); CoreComm = comm; _syncSettings = (ColecoSyncSettings)syncSettings ?? new ColecoSyncSettings(); bool skipbios = _syncSettings.SkipBiosIntro; _cpu = new Z80A { + FetchMemory = ReadMemory, ReadMemory = ReadMemory, WriteMemory = WriteMemory, ReadHardware = ReadPort, @@ -53,7 +54,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision SetupMemoryDomains(); _tracer.Header = _cpu.TraceHeader; - ser.Register(new Disassembler()); + ser.Register(_cpu); ser.Register(_tracer); } @@ -223,5 +224,17 @@ namespace BizHawk.Emulation.Cores.ColecoVision ////Console.WriteLine("Unhandled write at {0:X4}:{1:X2}", addr, value); } + + private void HardReset() + { + PSG.Reset(); + _cpu.Reset(); + } + + private void SoftReset() + { + PSG.Reset(); + _cpu.Reset(); + } } -} \ No newline at end of file +} diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/TMS9918A.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/TMS9918A.cs index 1e5abd1445..c86bd515c1 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/TMS9918A.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/TMS9918A.cs @@ -2,7 +2,7 @@ using BizHawk.Common; using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Components.Z80; +using BizHawk.Emulation.Cores.Components.Z80A; namespace BizHawk.Emulation.Cores.ColecoVision { @@ -54,14 +54,17 @@ namespace BizHawk.Emulation.Cores.ColecoVision Cpu.NonMaskableInterrupt = true; } - Cpu.ExecuteCycles(228); - - Cpu.Interrupt = false; + for (int i = 0; i < 228; i++) + { + Cpu.ExecuteOne(); + } + + Cpu.FlagI = false; if (Int_pending && scanLine==50) { if (EnableInterrupts) { - Cpu.Interrupt = true; + Cpu.FlagI = true; Int_pending = false; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IDebuggable.cs index 972d08018f..c80c5832a2 100644 --- a/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IDebuggable.cs @@ -82,7 +82,7 @@ namespace BizHawk.Emulation.Cores.Intellivision } } - public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(); + public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" }); public bool CanStep(StepType type) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IDebuggable.cs index fab17f6458..2b9424e729 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IDebuggable.cs @@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA return false; } - private readonly MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(); + private readonly MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); public IMemoryCallbackSystem MemoryCallbacks => _memorycallbacks; [FeatureNotImplemented] diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs index 23af5c9a48..676210608f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs @@ -166,9 +166,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA void InitCallbacks() { padcb = new LibVBANext.StandardCallback(() => InputCallbacks.Call()); - fetchcb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallExecutes(addr)); - readcb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallReads(addr)); - writecb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallWrites(addr)); + fetchcb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallExecutes(addr, "System Bus")); + readcb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallReads(addr, "System Bus")); + writecb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallWrites(addr, "System Bus")); tracecb = new LibVBANext.TraceCallback((addr, opcode) => Tracer.Put(Trace(addr, opcode))); _inputCallbacks.ActiveChanged += SyncPadCallback; _memorycallbacks.ActiveChanged += SyncMemoryCallbacks; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IDebuggable.cs index 91af62e606..8423fd437b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IDebuggable.cs @@ -56,7 +56,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy private LibGambatte.MemoryCallback _writecb; private LibGambatte.MemoryCallback _execcb; - private MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(); + private MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); /// /// for use in dual core @@ -68,9 +68,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy private void InitMemoryCallbacks() { - _readcb = addr => MemoryCallbacks.CallReads(addr); - _writecb = addr => MemoryCallbacks.CallWrites(addr); - _execcb = addr => MemoryCallbacks.CallExecutes(addr); + _readcb = addr => MemoryCallbacks.CallReads(addr, "System Bus"); + _writecb = addr => MemoryCallbacks.CallWrites(addr, "System Bus"); + _execcb = addr => MemoryCallbacks.CallExecutes(addr, "System Bus"); _memorycallbacks.ActiveChanged += RefreshMemoryCallbacks; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ILinkable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ILinkable.cs new file mode 100644 index 0000000000..05066dfed8 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ILinkable.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.Gameboy +{ + public partial class Gameboy : ILinkable + { + public bool LinkConnected { get; private set; } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs index 87a9c4272e..fcfa9a0486 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy [ServiceNotApplicable(typeof(IDriveLight), typeof(IDriveLight))] public partial class Gameboy : IEmulator, IVideoProvider, ISoundProvider, ISaveRam, IStatable, IInputPollable, ICodeDataLogger, IBoardInfo, IDebuggable, ISettable, - IGameboyCommon, ICycleTiming + IGameboyCommon, ICycleTiming, ILinkable { [CoreConstructor("GB", "GBC")] public Gameboy(CoreComm comm, GameInfo game, byte[] file, object settings, object syncSettings, bool deterministic) @@ -513,9 +513,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy if (callback != null) { printer = new GambattePrinter(this, callback); + LinkConnected = true; } else { + LinkConnected = false; printer.Disconnect(); printer = null; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IDebuggable.cs index 0d76029738..d6b4d8d276 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IDebuggable.cs @@ -50,6 +50,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy get { throw new NotImplementedException(); } } - private readonly MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(); + private readonly MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs index 5ae284dce9..59a3c7aa7c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs @@ -64,7 +64,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy { Filename = "sameboy.wbx", SbrkHeapSizeKB = 192, - InvisibleHeapSizeKB = 4, + InvisibleHeapSizeKB = 12, SealedHeapSizeKB = 9 * 1024, PlainHeapSizeKB = 4, MmapHeapSizeKB = 1024 @@ -300,6 +300,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy protected override void LoadStateBinaryInternal(BinaryReader reader) { UpdateCoreScanlineCallback(false); + _core.SetPrinterCallback(_printerCallback); } public bool IsCGBMode() => _cgb; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.IDebuggable.cs index ce533b74b6..5aadf2b2d5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.IDebuggable.cs @@ -82,7 +82,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64 get { return _memorycallbacks; } } - private readonly MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(); + private readonly MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); public bool CanStep(StepType type) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusCoreApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusCoreApi.cs index bdda7421fe..bda67a2da4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusCoreApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusCoreApi.cs @@ -759,13 +759,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi switch (_breakparams._type) { case BreakType.Read: - _breakparams._mcs.CallReads(_breakparams._addr); + _breakparams._mcs.CallReads(_breakparams._addr, "System Bus"); break; case BreakType.Write: - _breakparams._mcs.CallWrites(_breakparams._addr); + _breakparams._mcs.CallWrites(_breakparams._addr, "System Bus"); break; case BreakType.Execute: - _breakparams._mcs.CallExecutes(_breakparams._addr); + _breakparams._mcs.CallExecutes(_breakparams._addr, "System Bus"); break; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs index f45b8719a1..72cbcba367 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs @@ -20,13 +20,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { public sealed class APU { - public static bool CFG_DECLICK = true; - - public int Square1V = 376; - public int Square2V = 376; - public int TriangleV = 426; - public int NoiseV = 247; - public int DMCV = 167; + public int m_vol = 1; public int dmc_dma_countdown = -1; public bool call_from_write; @@ -53,11 +47,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES pulse[1] = new PulseUnit(this, 1); if (old != null) { - Square1V = old.Square1V; - Square2V = old.Square2V; - TriangleV = old.TriangleV; - NoiseV = old.NoiseV; - DMCV = old.DMCV; + m_vol = old.m_vol; } } @@ -1338,8 +1328,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } SyncIRQ(); - nes.irq_apu = irq_pending; - + // since the units run concurrently, the APU frame sequencer is ran last because // it can change the ouput values of the pulse/triangle channels // we want the changes to affect it on the *next* cycle. @@ -1419,7 +1408,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES float output = pulse_out + tnd_out; // output = output * 2 - 1; // this needs to leave enough headroom for straying DC bias due to the DMC unit getting stuck outputs. smb3 is bad about that. - int mix = (int)(20000 * output); + int mix = (int)(20000 * output * (1 + m_vol/5)); dlist.Add(new Delta(sampleclock, mix - oldmix)); oldmix = mix; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MLT-ACTION52.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MLT-ACTION52.cs index f51293921e..09583ef19c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MLT-ACTION52.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MLT-ACTION52.cs @@ -1,5 +1,6 @@ using BizHawk.Common; using BizHawk.Common.NumberExtensions; +using System; namespace BizHawk.Emulation.Cores.Nintendo.NES { @@ -108,6 +109,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { cheetahmen = true; } + else + { + prg_bank_mask_16k = 0x1F; + prg_bank_mask_32k = 0xF; + } AutoMapperProps.Apply(this); @@ -155,6 +161,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //$8000-FFFF: [.... ..CC] Low 2 bits of CHR //A~[..MH HPPP PPO. CCCC] + addr += 0x8000; + if (addr.Bit(13)) { SetMirrorType(EMirrorType.Horizontal); @@ -173,7 +181,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES switch (chip) { case 0: - chip_offset = 0; + chip_offset = 0x0; break; case 1: chip_offset = 0x80000; @@ -201,7 +209,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (prg_mode == false) { int bank = (prg_reg >> 1) & prg_bank_mask_32k; - return ROM[(bank * 0x8000) + addr]; + return ROM[(bank * 0x8000) + addr + chip_offset]; } else { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper114.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper114.cs new file mode 100644 index 0000000000..5786a0042d --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper114.cs @@ -0,0 +1,107 @@ +using BizHawk.Common; +using System; + +namespace BizHawk.Emulation.Cores.Nintendo.NES +{ + // Mapper for Aladdin Super Game + public sealed class Mapper114 : MMC3Board_Base + { + private ByteBuffer EXPREGS = new ByteBuffer(2); + + private int prg_mask_16; + + private byte[] sec = { 0, 3, 1, 5, 6, 7, 2, 4 }; + + public override bool Configure(NES.EDetectionOrigin origin) + { + switch (Cart.board_type) + { + case "MAPPER114": + break; + default: + return false; + } + + BaseSetup(); + SetMirrorType(EMirrorType.Horizontal); + mmc3.MMC3Type = MMC3.EMMC3Type.MMC3A; + prg_mask_16 = Cart.prg_size / 16 - 1; + return true; + } + + public override void Dispose() + { + EXPREGS.Dispose(); + base.Dispose(); + } + + public override void SyncState(Serializer ser) + { + base.SyncState(ser); + ser.Sync("expregs", ref EXPREGS); + } + + public override void WriteEXP(int addr, byte value) + { + if ((addr & 0x7) == 0 && addr >= 0x1000) + { + EXPREGS[0] = value; + } + } + + public override void WriteWRAM(int addr, byte value) + { + if ((addr & 0x7) == 0) + { + EXPREGS[0] = value; + } + } + + public override void WritePRG(int addr, byte value) + { + switch (addr & 0x6000) + { + case 0x0000: //$8000 + base.SetMirrorType((value & 1) == 1 ? EMirrorType.Horizontal : EMirrorType.Vertical); + break; + case 0x2000: //$A000 + value = (byte)((value & 0xC0) | sec[value & 0x07]); + EXPREGS[1] = 1; + base.WritePRG(0, value); + break; + case 0x4000: //$C000 + if(EXPREGS[1] == 1) + { + EXPREGS[1] = 0; + base.WritePRG(1, value); + } + break; + case 0x6000: //$E000 + if (value > 0) + { + base.WritePRG(0x6001, value); + base.WritePRG(0x4000, value); + base.WritePRG(0x4001, value); + } + else + { + base.WritePRG(0x6000, value); + } + break; + } + } + + public override byte ReadPRG(int addr) + { + if ((EXPREGS[0] & 0x80) > 0) + { + var bank = EXPREGS[0] & 0x1F & prg_mask_16; + return ROM[(bank << 14) + (addr & 0x3FFF)]; + } + else + { + return base.ReadPRG(addr); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper116.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper116.cs index 243cd695b7..25f1526385 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper116.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper116.cs @@ -146,7 +146,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES void WriteModeControl(int addr, byte value) { - if (((addr & 0x4100) != 0x4100) || addr>=0x4200) return; + if ((addr & 0x4100) != 0x4100) return; mode = value & 3; bool chr_base = value.Bit(2); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/FDS.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/FDS.cs index 9f46fdf560..e649c730e5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/FDS.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/FDS.cs @@ -255,19 +255,29 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES case 0x0020: timerlatch &= 0xff00; timerlatch |= value; - //timerirq = false; break; case 0x0021: timerlatch &= 0x00ff; timerlatch |= value << 8; - //timerirq = false; break; case 0x0022: - timerreg = (byte)(value & 3); - timervalue = timerlatch; + if (diskenable) + { + timerreg = (byte)(value & 3); + if ((value & 0x02) == 0x02) + { + timervalue = timerlatch; + } + else + { + _timerirq = false; + } + } + break; case 0x0023: diskenable = (value & 1) != 0; + if (!diskenable) { _timerirq = false; } soundenable = (value & 2) != 0; break; case 0x0024: @@ -344,7 +354,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public override void ClockCPU() { - if ((timerreg & 2) != 0)// && timervalue > 0) + if ((timerreg & 2) != 0 && diskenable) { if (timervalue!=0) { @@ -352,22 +362,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } if (timervalue == 0) { - - /* - if ((timerreg & 1) != 0) - { - timervalue = timerlatch; - //timervalue = 0xFFFF; - } - else - { - timerreg &= unchecked((byte)~2); - timervalue = 0; - timerlatch = 0; - } - */ timervalue = timerlatch; timerirq = true; + if ((timerreg & 1) == 0) + { + timerreg -= 2; + } } } audio.Clock(); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/RamAdapter.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/RamAdapter.cs index 4861d49708..9c86f953e7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/RamAdapter.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/RamAdapter.cs @@ -67,14 +67,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES byte[] fileheader = br.ReadBytes(16); if (fileheader[0] != 0x03) { - throw new Exception("Corrupt FDS block 3"); + // Instead of exceptions, display strong warnings + Console.WriteLine("WARNING: INVALID FILE, BLOCK 3 ERROR"); + //throw new Exception("Corrupt FDS block 3"); } int filesize = fileheader[13] + fileheader[14] * 256; byte[] file = br.ReadBytes(filesize + 1); if (file[0] != 0x04) { - throw new Exception("Corrupt FDS block 4"); + Console.WriteLine("WARNING: INVALID FILE, BLOCK 4 ERROR"); + //throw new Exception("Corrupt FDS block 4"); } WriteBlock(ret, fileheader, 122); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs index 18752340e5..667f92a230 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs @@ -13,7 +13,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { //hardware/state public MOS6502X cpu; - int cpu_accumulate; //cpu timekeeper public PPU ppu; public APU apu; public byte[] ram; @@ -26,12 +25,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES int sprdma_countdown; bool _irq_apu; //various irq signals that get merged to the cpu irq pin - /// clock speed of the main cpu in hz + + /// clock speed of the main cpu in hz public int cpuclockrate { get; private set; } - //irq state management - public bool irq_apu { get { return _irq_apu; } set { _irq_apu = value; } } - //user configuration int[] palette_compiled = new int[64 * 8]; @@ -62,11 +59,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES private DisplayType _display_type = DisplayType.NTSC; //Sound config - public void SetSquare1(int v) { apu.Square1V = v; } - public void SetSquare2(int v) { apu.Square2V = v; } - public void SetTriangle(int v) { apu.TriangleV = v; } - public void SetNoise(int v) { apu.NoiseV = v; } - public void SetDMC(int v) { apu.DMCV = v; } + public void SetVol1(int v) { apu.m_vol = v; } /// /// for debugging only! @@ -366,7 +359,40 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES VS_coin_inserted &= 1; } - ppu.FrameAdvance(); + if (ppu.ppudead > 0) + { + while (ppu.ppudead > 0) + { + ppu.NewDeadPPU(); + } + } + else + { + ppu.ppu_init_frame(); + + ppu.do_vbl = true; + ppu.do_active_sl = true; + ppu.do_pre_vbl = true; + + // do the vbl ticks seperate, that will save us a few checks that don't happen in active region + while (ppu.do_vbl) + { + ppu.TickPPU_VBL(); + } + + // now do the rest of the frame + while (ppu.do_active_sl) + { + ppu.TickPPU_active(); + } + + // now do the pre-NMI lines + while (ppu.do_pre_vbl) + { + ppu.TickPPU_preVBL(); + } + } + if (lagged) { _lagcount++; @@ -386,7 +412,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } //PAL: - //0 15 30 45 60 -> 12 27 42 57 -> 9 24 39 54 -> 6 21 36 51 -> 3 18 33 48 -> 0 //sequence of ppu clocks per cpu clock: 3,3,3,3,4 //at least it should be, but something is off with that (start up time?) so it is 3,3,3,4,3 for now //NTSC: @@ -834,7 +859,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public void ExecFetch(ushort addr) { - MemoryCallbacks.CallExecutes(addr); + MemoryCallbacks.CallExecutes(addr, "System Bus"); } public byte ReadMemory(ushort addr) @@ -879,7 +904,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ret = sysbus_watch[addr].ApplyGameGenie(ret); } - MemoryCallbacks.CallReads(addr); + MemoryCallbacks.CallReads(addr, "System Bus"); DB = ret; return ret; @@ -934,7 +959,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES Board.WritePRG(addr - 0x8000, value); } - MemoryCallbacks.CallWrites(addr); + MemoryCallbacks.CallWrites(addr, "System Bus"); } // the palette for each VS game needs to be chosen explicitly since there are 6 different ones. diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ICodeDataLogger.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ICodeDataLogger.cs new file mode 100644 index 0000000000..c1f2a5b4fa --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ICodeDataLogger.cs @@ -0,0 +1,113 @@ +using System; +using System.IO; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.NES +{ + public sealed partial class NES : ICodeDataLogger + { + public void SetCDL(ICodeDataLog cdl) + { + CDL = cdl; + if (cdl == null) + { + cpu.ReadMemory = ReadMemory; + cpu.WriteMemory = WriteMemory; + cpu.PeekMemory = PeekMemory; + } + else + { + cpu.ReadMemory = ReadMemory_CDL; + cpu.WriteMemory = WriteMemory; + cpu.PeekMemory = FetchMemory_CDL; + } + } + + public void NewCDL(ICodeDataLog cdl) + { + cdl["RAM"] = new byte[_memoryDomains["RAM"].Size]; + + if (_memoryDomains.Has("Save RAM")) + { + cdl["Save RAM"] = new byte[_memoryDomains["Save RAM"].Size]; + } + + if (_memoryDomains.Has("Battery RAM")) + { + cdl["Battery RAM"] = new byte[_memoryDomains["Battery RAM"].Size]; + } + + if (_memoryDomains.Has("Battery RAM")) + { + cdl["Battery RAM"] = new byte[_memoryDomains["Battery RAM"].Size]; + } + + cdl.SubType = "NES"; + cdl.SubVer = 0; + } + + [FeatureNotImplemented] + public void DisassembleCDL(Stream s, ICodeDataLog cdl) + { + + } + + private enum CDLog_AddrType + { + None, + ROM, + MainRAM, + SaveRAM, + } + + [Flags] + private enum CDLog_Flags + { + ExecFirst = 0x01, + ExecOperand = 0x02, + Data = 0x04 + }; + + private struct CDLog_MapResults + { + public CDLog_AddrType Type; + public int Address; + } + + private delegate CDLog_MapResults MapMemoryDelegate(ushort addr, bool write); + private MapMemoryDelegate MapMemory; + private ICodeDataLog CDL; + + private void RunCDL(ushort address, CDLog_Flags flags) + { + if (MapMemory != null) + { + CDLog_MapResults results = MapMemory(address, false); + switch (results.Type) + { + case CDLog_AddrType.None: break; + case CDLog_AddrType.MainRAM: CDL["Main RAM"][results.Address] |= (byte)flags; break; + case CDLog_AddrType.SaveRAM: CDL["Save RAM"][results.Address] |= (byte)flags; break; + } + } + } + + /// + /// A wrapper for FetchMemory which inserts CDL logic + /// + private byte FetchMemory_CDL(ushort address) + { + RunCDL(address, CDLog_Flags.ExecFirst); + return PeekMemory(address); + } + + /// + /// A wrapper for ReadMemory which inserts CDL logic + /// + private byte ReadMemory_CDL(ushort address) + { + RunCDL(address, CDLog_Flags.Data); + return ReadMemory(address); + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ISettable.cs index 784b3b6fa5..40a8878a69 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ISettable.cs @@ -39,11 +39,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES SetPalette(Settings.Palette); - apu.Square1V = Settings.Square1; - apu.Square2V = Settings.Square2; - apu.TriangleV = Settings.Triangle; - apu.NoiseV = Settings.Noise; - apu.DMCV = Settings.DMC; + apu.m_vol = Settings.APU_vol; return false; } @@ -157,11 +153,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public byte[,] Palette; - public int Square1 = 376; - public int Square2 = 376; - public int Triangle = 426; - public int Noise = 247; - public int DMC = 167; + public int APU_vol = 1; public NESSettings Clone() { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs index e5ac4f54b9..e2dd212602 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs @@ -57,7 +57,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES cpu.SyncState(ser); ser.Sync("ram", ref ram, false); ser.Sync("CIRAM", ref CIRAM, false); - ser.Sync("cpu_accumulate", ref cpu_accumulate); ser.Sync("_irq_apu", ref _irq_apu); ser.Sync("sprdma_countdown", ref sprdma_countdown); ser.Sync("cpu_deadcounter", ref cpu_deadcounter); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs index 3549facdd3..f575a7c71e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs @@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES isPorted: false, isReleased: true)] public partial class NES : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, - IBoardInfo, ISettable + IBoardInfo, ISettable, ICodeDataLogger { [CoreConstructor("NES")] public NES(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings) @@ -36,7 +36,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ControllerSettings = SyncSettings.Controls; CoreComm = comm; - MemoryCallbacks = new MemoryCallbackSystem(); + MemoryCallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); BootGodDB.Initialize(); videoProvider = new MyVideoProvider(this); Init(game, rom, fdsbios); @@ -876,10 +876,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //todo //http://blog.ntrq.net/?p=428 -//cpu bus junk bits - -//UBER DOC -//http://nocash.emubase.de/everynes.htm //A VERY NICE board assignments list //http://personales.epsg.upv.es/~jogilmo1/nes/TEXTOS/ARXIUS/BOARDTABLE.TXT @@ -889,6 +885,3 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //a mappers list //http://tuxnes.sourceforge.net/nesmapper.txt - -//some ppu tests -//http://nesdev.parodius.com/bbs/viewtopic.php?p=4571&sid=db4c7e35316cc5d734606dd02f11dccb diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs index 4468e90dd2..320113d52f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs @@ -135,7 +135,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //when the ppu issues a write it goes through here and into the game board public void ppubus_write(int addr, byte value) { - if (ppur.status.sl == 241 || !PPUON) + if (ppur.status.sl >= 241 || !PPUON) nes.Board.AddressPPU(addr); nes.Board.WritePPU(addr, value); @@ -194,7 +194,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } //state - int ppudead; //measured in frames + public int ppudead; //measured in frames bool idleSynch; int NMI_PendingInstructions; byte PPUGenLatch; @@ -218,12 +218,22 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ser.Sync("VRAMBuffer", ref VRAMBuffer); ser.Sync("ppu_addr_temp", ref ppu_addr_temp); + ser.Sync("spr_true_count", ref spr_true_count); + ser.Sync("sprite_eval_write", ref sprite_eval_write); ser.Sync("Read_Value", ref read_value); ser.Sync("Prev_soam_index", ref soam_index_prev); ser.Sync("Spr_Zero_Go", ref sprite_zero_go); ser.Sync("Spr_zero_in_Range", ref sprite_zero_in_range); ser.Sync("Is_even_cycle", ref is_even_cycle); ser.Sync("soam_index", ref soam_index); + ser.Sync("soam_m_index", ref soam_m_index); + ser.Sync("oam_index", ref oam_index); + ser.Sync("oam_index_aux", ref oam_index_aux); + ser.Sync("soam_index_aux", ref soam_index_aux); + ser.Sync("yp", ref yp); + ser.Sync("target", ref target); + ser.Sync("ppu_was_on", ref ppu_was_on); + ser.Sync("spriteHeight", ref spriteHeight); ser.Sync("install_2006", ref install_2006); ser.Sync("race_2006", ref race_2006); ser.Sync("install_2001", ref install_2001); @@ -236,6 +246,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ser.Sync("glitchy_reads_2003", ref glitchy_reads_2003, false); ser.Sync("OAM", ref OAM, false); + ser.Sync("soam", ref soam, false); ser.Sync("PALRAM", ref PALRAM, false); ser.Sync("Reg2002_objoverflow", ref Reg2002_objoverflow); @@ -253,6 +264,59 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ser.Sync("xbuf", ref xbuf, false); ser.Sync("_totalCycles", ref _totalCycles); + + ser.Sync("do_vbl", ref do_vbl); + ser.Sync("do_active_sl", ref do_active_sl); + ser.Sync("do_pre_vbl", ref do_pre_vbl); + + ser.Sync("nmi_destiny", ref nmi_destiny); + ser.Sync("yp_shift", ref yp_shift); + ser.Sync("sprite_eval_cycle", ref sprite_eval_cycle); + ser.Sync("xt", ref xt); + ser.Sync("xp", ref xp); + ser.Sync("xstart", ref xstart); + ser.Sync("rasterpos", ref rasterpos); + ser.Sync("renderspritenow", ref renderspritenow); + ser.Sync("renderbgnow", ref renderbgnow); + ser.Sync("hit_pending", ref hit_pending); + ser.Sync("s", ref s); + ser.Sync("ppu_aux_index", ref ppu_aux_index); + ser.Sync("junksprite", ref junksprite); + ser.Sync("line", ref line); + ser.Sync("patternNumber", ref patternNumber); + ser.Sync("patternAddress", ref patternAddress); + ser.Sync("temp_addr", ref temp_addr); + ser.Sync("sl_sprites", ref sl_sprites, false); + + byte bg_byte; + for (int i = 0; i < 34; i++) + { + string str = "bgdata" + i.ToString() + "at"; + bg_byte = bgdata[i].at; ser.Sync(str, ref bg_byte); bgdata[i].at = bg_byte; + str = "bgdata" + i.ToString() + "nt"; + bg_byte = bgdata[i].nt; ser.Sync(str, ref bg_byte); bgdata[i].nt = bg_byte; + str = "bgdata" + i.ToString() + "pt0"; + bg_byte = bgdata[i].pt_0; ser.Sync(str, ref bg_byte); bgdata[i].pt_0 = bg_byte; + str = "bgdata" + i.ToString() + "pt1"; + bg_byte = bgdata[i].pt_1; ser.Sync(str, ref bg_byte); bgdata[i].pt_1 = bg_byte; + } + + byte oam_byte; + for (int i = 0; i < 64; i++) + { + string str = "oamdata" + i.ToString() + "y"; + oam_byte = t_oam[i].oam_y; ser.Sync(str, ref oam_byte); t_oam[i].oam_y = oam_byte; + str = "oamdata" + i.ToString() + "ind"; + oam_byte = t_oam[i].oam_ind; ; ser.Sync(str, ref oam_byte); t_oam[i].oam_ind = oam_byte; + str = "oamdata" + i.ToString() + "attr"; + oam_byte = t_oam[i].oam_attr; ser.Sync(str, ref oam_byte); t_oam[i].oam_attr = oam_byte; + str = "oamdata" + i.ToString() + "x"; + oam_byte = t_oam[i].oam_x; ser.Sync(str, ref oam_byte); t_oam[i].oam_x = oam_byte; + str = "oamdata" + i.ToString() + "p0"; + oam_byte = t_oam[i].patterns_0; ser.Sync(str, ref oam_byte); t_oam[i].patterns_0 = oam_byte; + str = "oamdata" + i.ToString() + "p1"; + oam_byte = t_oam[i].patterns_1; ser.Sync(str, ref oam_byte); t_oam[i].patterns_1 = oam_byte; + } } public void Reset() @@ -264,93 +328,91 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ppu_open_bus_decay_timer = new int[8]; } - void runppu(int x) + void runppu() { //run one ppu cycle at a time so we can interact with the ppu and clockPPU at high granularity - for (int i = 0; i < x; i++) + + race_2006 = false; + if (install_2006>0) { - race_2006 = false; - if (install_2006>0) + install_2006--; + if (install_2006==0) { - install_2006--; - if (install_2006==0) - { - ppur.install_latches(); + ppur.install_latches(); - //nes.LogLine("addr wrote vt = {0}, ht = {1}", ppur._vt, ppur._ht); - //normally the address isnt observed by the board till it gets clocked by a read or write. - //but maybe thats just because a ppu read/write shoves it on the address bus - //apparently this shoves it on the address bus, too, or else blargg's mmc3 tests dont pass - //ONLY if the ppu is not rendering - if (ppur.status.sl == 241 || !PPUON) - nes.Board.AddressPPU(ppur.get_2007access()); + //nes.LogLine("addr wrote vt = {0}, ht = {1}", ppur._vt, ppur._ht); + //normally the address isnt observed by the board till it gets clocked by a read or write. + //but maybe thats just because a ppu read/write shoves it on the address bus + //apparently this shoves it on the address bus, too, or else blargg's mmc3 tests dont pass + //ONLY if the ppu is not rendering + if (ppur.status.sl >= 241 || !PPUON) + nes.Board.AddressPPU(ppur.get_2007access()); - race_2006 = true; - } - } - - if (install_2001 > 0) - { - install_2001--; - if (install_2001 == 0) - { - show_bg_new = reg_2001.show_bg; - show_obj_new = reg_2001.show_obj; - } - } - - ppur.status.cycle++; - is_even_cycle = !is_even_cycle; - - if (PPUON && ppur.status.cycle >= 257 && ppur.status.cycle <= 320 && 0 <= ppur.status.sl && ppur.status.sl <= 240) - { - reg_2003 = 0; - } - - // Here we execute a CPU instruction if enough PPU cycles have passed - // also do other things that happen at instruction level granularity - cpu_stepcounter++; - if (cpu_stepcounter == nes.cpu_sequence[cpu_step]) - { - cpu_step++; - if (cpu_step == 5) cpu_step = 0; - cpu_stepcounter = 0; - - // this is where the CPU instruction is called - nes.RunCpuOne(); - - // decay the ppu bus, approximating real behaviour - PpuOpenBusDecay(DecayType.None); - - // Check for NMIs - if (NMI_PendingInstructions > 0) - { - NMI_PendingInstructions--; - if (NMI_PendingInstructions <= 0) - { - nes.cpu.NMI = true; - } - } - } - - if (Reg2002_vblank_active_pending) - { - Reg2002_vblank_active = 1; - Reg2002_vblank_active_pending = false; - } - - if (Reg2002_vblank_clear_pending) - { - Reg2002_vblank_active = 0; - Reg2002_vblank_clear_pending = false; - } - - if (HasClockPPU) - { - nes.Board.ClockPPU(); + race_2006 = true; } } - _totalCycles += x; - } + + if (install_2001 > 0) + { + install_2001--; + if (install_2001 == 0) + { + show_bg_new = reg_2001.show_bg; + show_obj_new = reg_2001.show_obj; + } + } + + ppur.status.cycle++; + is_even_cycle = !is_even_cycle; + + if (PPUON && ppur.status.cycle >= 257 && ppur.status.cycle <= 320 && ppur.status.sl <= 240) + { + reg_2003 = 0; + } + + // Here we execute a CPU instruction if enough PPU cycles have passed + // also do other things that happen at instruction level granularity + cpu_stepcounter++; + if (cpu_stepcounter == nes.cpu_sequence[cpu_step]) + { + cpu_step++; + if (cpu_step == 5) cpu_step = 0; + cpu_stepcounter = 0; + + // this is where the CPU instruction is called + nes.RunCpuOne(); + + // decay the ppu bus, approximating real behaviour + PpuOpenBusDecay(DecayType.None); + + // Check for NMIs + if (NMI_PendingInstructions > 0) + { + NMI_PendingInstructions--; + if (NMI_PendingInstructions <= 0) + { + nes.cpu.NMI = true; + } + } + } + + if (Reg2002_vblank_active_pending) + { + Reg2002_vblank_active = 1; + Reg2002_vblank_active_pending = false; + } + + if (Reg2002_vblank_clear_pending) + { + Reg2002_vblank_active = 0; + Reg2002_vblank_clear_pending = false; + } + + if (HasClockPPU) + { + nes.Board.ClockPPU(); + } + _totalCycles += 1; + } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs index 332e4ab220..a0aed3f502 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs @@ -1,10 +1,10 @@ //blargg: Reading from $2007 when the VRAM address is $3fxx will fill the internal read buffer with the contents at VRAM address $3fxx, in addition to reading the palette RAM. - //static const byte powerUpPalette[] = - //{ - // 0x3F,0x01,0x00,0x01, 0x00,0x02,0x02,0x0D, 0x08,0x10,0x08,0x24, 0x00,0x00,0x04,0x2C, - // 0x09,0x01,0x34,0x03, 0x00,0x04,0x00,0x14, 0x08,0x3A,0x00,0x02, 0x00,0x20,0x2C,0x08 - //}; +//static const byte powerUpPalette[] = +//{ +// 0x3F,0x01,0x00,0x01, 0x00,0x02,0x02,0x0D, 0x08,0x10,0x08,0x24, 0x00,0x00,0x04,0x2C, +// 0x09,0x01,0x34,0x03, 0x00,0x04,0x00,0x14, 0x08,0x3A,0x00,0x02, 0x00,0x20,0x2C,0x08 +//}; using System; using BizHawk.Common; @@ -90,8 +90,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ser.Sync("_ht", ref _ht); ser.Sync("fh", ref fh); ser.Sync("status.cycle", ref status.cycle); - int junk = 0; - ser.Sync("status.end_cycle", ref junk); ser.Sync("status.sl", ref status.sl); } @@ -148,7 +146,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES fh = 0; _fv = _v = _h = _vt = _ht = 0; status.cycle = 0; - status.sl = 241; + status.sl = 0; } public void install_latches() @@ -433,7 +431,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //otherwise we just write this value and move on to the next oam byte value &= 0xE3; } - if (0 <= ppur.status.sl && ppur.status.sl <= 240) + if (ppur.status.rendering) { // don't write to OAM if the screen is on and we are in the active display area // this impacts sprite evaluation @@ -587,7 +585,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ppur.increment2007(ppur.status.rendering && PPUON, reg_2000.vram_incr32 != 0); //see comments in $2006 - if (ppur.status.sl == 241 || !PPUON) + if (ppur.status.sl >= 241 || !PPUON) nes.Board.AddressPPU(ppur.get_2007access()); } byte read_2007() @@ -611,7 +609,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ppur.increment2007(ppur.status.rendering && PPUON, reg_2000.vram_incr32 != 0); //see comments in $2006 - if (ppur.status.sl == 241 || !PPUON) + if (ppur.status.sl >= 241 || !PPUON) nes.Board.AddressPPU(ppur.get_2007access()); // update open bus here diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs index 894df6d75b..768c95f13b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs @@ -8,15 +8,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { sealed partial class PPU { - const int kFetchTime = 2; - const int kLineTime = 341; - struct BGDataRecord { public byte nt, at; public byte pt_0, pt_1; }; + BGDataRecord[] bgdata = new BGDataRecord[34]; + public short[] xbuf = new short[256 * 240]; // values here are used in sprite evaluation @@ -27,8 +26,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public int soam_index_prev; public int soam_m_index; public int oam_index; - public byte read_value_aux; - public int soam_m_index_aux; public int oam_index_aux; public int soam_index_aux; public bool is_even_cycle; @@ -37,10 +34,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public int yp; public int target; public int spriteHeight; - public byte[] soam = new byte[512]; // in a real nes, this would only be 32, but we wish to allow more then 8 sprites per scanline - public bool reg_2001_color_disable_latch; // the value used here is taken + public byte[] soam = new byte[256]; // in a real nes, this would only be 32, but we wish to allow more then 8 sprites per scanline public bool ppu_was_on; - public byte[,] sl_sprites = new byte[3, 256]; + public byte[] sl_sprites = new byte[3 * 256]; // installing vram address is delayed after second write to 2006, set this up here public int install_2006; @@ -62,36 +58,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES TempOAM[] t_oam = new TempOAM[64]; int ppu_addr_temp; - void Read_bgdata(ref BGDataRecord bgdata) - { - for (int i = 0; i < 8; i++) - { - Read_bgdata(i, ref bgdata); - runppu(1); - - if (PPUON && i == 6) - { - ppu_was_on = true; - } - - if (PPUON && i == 7) - { - if (!race_2006) - ppur.increment_hsc(); - - if (ppur.status.cycle == 256 && !race_2006) - ppur.increment_vs(); - - ppu_was_on = false; - } - } - } // attempt to emulate graphics pipeline behaviour // experimental int pixelcolor_latch_1; int pixelcolor_latch_2; - void pipeline(int pixelcolor, int target, int row_check) + void pipeline(int pixelcolor, int row_check) { if (row_check > 1) { @@ -103,11 +75,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES xbuf[(target - 2)] = (short)(pixelcolor_latch_2 | reg_2001.intensity_lsl_6); } - if (row_check >= 1) - { - pixelcolor_latch_2 = pixelcolor_latch_1; - } - + pixelcolor_latch_2 = pixelcolor_latch_1; pixelcolor_latch_1 = pixelcolor; } @@ -151,53 +119,80 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } //switch(cycle) } - public unsafe void FrameAdvance() - { - BGDataRecord* bgdata = stackalloc BGDataRecord[34]; //one at the end is junk, it can never be rendered + // these are states for the ppu incrementer + public bool do_vbl; + public bool do_active_sl; + public bool do_pre_vbl; - //262 scanlines - if (ppudead != 0) - { - FrameAdvance_ppudead(); - return; - } + bool nmi_destiny; + int yp_shift; + int sprite_eval_cycle; + int xt; + int xp; + int xstart; + int rasterpos; + bool renderspritenow; + bool renderbgnow; + bool hit_pending; + int s; + int ppu_aux_index; + bool junksprite; + int line; + int patternNumber; + int patternAddress; + int temp_addr; + + public void ppu_init_frame() + { + ppur.status.sl = 241 + preNMIlines; + ppur.status.cycle = 0; + + // These things happen at the start of every frame Reg2002_vblank_active_pending = true; ppuphase = PPUPHASE.VBL; - ppur.status.sl = 241; + bgdata = new BGDataRecord[34]; + } - //Not sure if this is correct. According to Matt Conte and my own tests, it is. Timing is probably off, though. - //NOTE: Not having this here breaks a Super Donkey Kong game. - //if (PPUON) reg_2003 = 0; + public void TickPPU_VBL() + { + if (ppur.status.cycle == 3 && ppur.status.sl == 241 + preNMIlines) + { + nmi_destiny = reg_2000.vblank_nmi_gen && Reg2002_vblank_active; + } + else if (ppur.status.cycle == 6 && ppur.status.sl == 241 + preNMIlines) + { + if (nmi_destiny) { nes.cpu.NMI = true; } + nes.Board.AtVsyncNMI(); + } - //this was repeatedly finetuned from the fceux days thrugh the old cpu core and into the new one to pass 05-nmi_timing.nes - //note that there is still some leniency. for instance, 4,2 will pass in addition to 3,3 - const int delay = 6; - runppu(3); - bool nmi_destiny = reg_2000.vblank_nmi_gen && Reg2002_vblank_active; - runppu(3); - if (nmi_destiny) nes.cpu.NMI = true; + runppu(); // note cycle ticks inside runppu - nes.Board.AtVsyncNMI(); - runppu(postNMIlines * kLineTime - delay); - - //this seems to happen just before the dummy scanline begins - Reg2002_objhit = Reg2002_objoverflow = 0; - Reg2002_vblank_clear_pending = true; - - idleSynch ^= true; - - //render 241 scanlines (including 1 dummy at beginning) - for (int sl = 0; sl < 241; sl++) + if (ppur.status.cycle == 341) { ppur.status.cycle = 0; + ppur.status.sl++; + if (ppur.status.sl == 241 + preNMIlines + postNMIlines) + { + Reg2002_objhit = Reg2002_objoverflow = 0; + Reg2002_vblank_clear_pending = true; + idleSynch ^= true; - ppur.status.sl = sl; + do_vbl = false; + ppur.status.sl = 0; + } + } + } + + public void TickPPU_active() + { + if (ppur.status.cycle == 0) + { + ppur.status.cycle = 0; spr_true_count = 0; soam_index = 0; soam_m_index = 0; - soam_m_index_aux = 0; oam_index_aux = 0; oam_index = 0; is_even_cycle = true; @@ -206,12 +201,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES sprite_zero_in_range = false; - yp = sl - 1; + yp = ppur.status.sl - 1; ppuphase = PPUPHASE.BG; // "If PPUADDR is not less then 8 when rendering starts, the first 8 bytes in OAM are written to from // the current location of PPUADDR" - if (sl == 0 && PPUON && reg_2003 >= 8 && region == Region.NTSC) + if (ppur.status.sl == 0 && PPUON && reg_2003 >= 8 && region == Region.NTSC) { for (int i = 0; i < 8; i++) { @@ -222,504 +217,379 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (NTViewCallback != null && yp == NTViewCallback.Scanline) NTViewCallback.Callback(); if (PPUViewCallback != null && yp == PPUViewCallback.Scanline) PPUViewCallback.Callback(); - //ok, we're also going to draw here. - //unless we're on the first dummy scanline - if (sl != 0) + // set up intial values to use later + yp_shift = yp << 8; + xt = 0; + xp = 0; + + sprite_eval_cycle = 0; + + xstart = xt << 3; + target = yp_shift + xstart; + rasterpos = xstart; + + spriteHeight = reg_2000.obj_size_16 ? 16 : 8; + + //check all the conditions that can cause things to render in these 8px + renderspritenow = show_obj_new && (xt > 0 || reg_2001.show_obj_leftmost); + hit_pending = false; + + } + + if (ppur.status.cycle < 256) + { + if (ppur.status.sl != 0) { - //the main scanline rendering loop: - //32 times, we will fetch a tile and then render 8 pixels. - //two of those tiles were read in the last scanline. - int yp_shift = yp << 8; - for (int xt = 0; xt < 32; xt++) + ///////////////////////////////////////////// + // Sprite Evaluation Start + ///////////////////////////////////////////// + + if (sprite_eval_cycle <= 63 && !is_even_cycle) { - int xstart = xt << 3; + // the first 64 cycles of each scanline are used to initialize sceondary OAM + // the actual effect setting a flag that always returns 0xFF from a OAM read + // this is a bit of a shortcut to save some instructions + // data is read from OAM as normal but never used + soam[soam_index] = 0xFF; + soam_index++; + } + if (sprite_eval_cycle == 64) + { + soam_index = 0; + oam_index = reg_2003; + } + + // otherwise, scan through OAM and test if sprites are in range + // if they are, they get copied to the secondary OAM + if (sprite_eval_cycle >= 64) + { + if (oam_index >= 256) + { + oam_index = 0; + sprite_eval_write = false; + } + + if (is_even_cycle && oam_index < 256) + { + if ((oam_index + soam_m_index) < 256) + read_value = OAM[oam_index + soam_m_index]; + else + read_value = OAM[oam_index + soam_m_index - 256]; + } + else if (!sprite_eval_write) + { + // if we don't write sprites anymore, just scan through the oam + read_value = soam[0]; + oam_index += 4; + } + else if (sprite_eval_write) + { + //look for sprites + if (spr_true_count == 0 && soam_index < 8) + { + soam[soam_index * 4] = read_value; + } + + if (soam_index < 8) + { + if (yp >= read_value && yp < read_value + spriteHeight && spr_true_count == 0) + { + //a flag gets set if sprite zero is in range + if (oam_index == reg_2003) + sprite_zero_in_range = true; + + spr_true_count++; + soam_m_index++; + } + else if (spr_true_count > 0 && spr_true_count < 4) + { + soam[soam_index * 4 + soam_m_index] = read_value; + + soam_m_index++; + + spr_true_count++; + if (spr_true_count == 4) + { + oam_index += 4; + soam_index++; + if (soam_index == 8) + { + // oam_index could be pathologically misaligned at this point, so we have to find the next + // nearest actual sprite to work on >8 sprites per scanline option + oam_index_aux = (oam_index % 4) * 4; + } + + soam_m_index = 0; + spr_true_count = 0; + } + } + else + { + oam_index += 4; + } + } + else if (soam_index >= 8) + { + if (yp >= read_value && yp < read_value + spriteHeight && PPUON) + { + hit_pending = true; + //Reg2002_objoverflow = true; + } + + if (yp >= read_value && yp < read_value + spriteHeight && spr_true_count == 0) + { + spr_true_count++; + soam_m_index++; + } + else if (spr_true_count > 0 && spr_true_count < 4) + { + soam_m_index++; + + spr_true_count++; + if (spr_true_count == 4) + { + oam_index += 4; + soam_index++; + soam_m_index = 0; + spr_true_count = 0; + } + } + else + { + oam_index += 4; + if (soam_index == 8) + { + soam_m_index++; // glitchy increment + soam_m_index &= 3; + } + + } + + read_value = soam[0]; //writes change to reads + } + } + } + + ///////////////////////////////////////////// + // Sprite Evaluation End + ///////////////////////////////////////////// + + //process the current clock's worth of bg data fetching + //this needs to be split into 8 pieces or else exact sprite 0 hitting wont work + // due to the cpu not running while the sprite renders below + if (PPUON) { Read_bgdata(xp, ref bgdata[xt + 2]); } + + runppu(); + + if (PPUON && xp == 6) + { + ppu_was_on = true; + } + + if (PPUON && xp == 7) + { + if (!race_2006) + ppur.increment_hsc(); + + if (ppur.status.cycle == 256 && !race_2006) + ppur.increment_vs(); + + ppu_was_on = false; + } + + if (hit_pending) + { + hit_pending = false; + Reg2002_objoverflow = true; + } + + renderbgnow = show_bg_new && (xt > 0 || reg_2001.show_bg_leftmost); + //bg pos is different from raster pos due to its offsetability. + //so adjust for that here + int bgpos = rasterpos + ppur.fh; + int bgpx = bgpos & 7; + int bgtile = bgpos >> 3; + + int pixel = 0, pixelcolor = PALRAM[pixel]; + + //according to qeed's doc, use palette 0 or $2006's value if it is & 0x3Fxx + //at one point I commented this out to fix bottom-left garbage in DW4. but it's needed for full_nes_palette. + //solution is to only run when PPU is actually OFF (left-suppression doesnt count) + if (!PPUON) + { + // if there's anything wrong with how we're doing this, someone please chime in + int addr = ppur.get_2007access(); + if ((addr & 0x3F00) == 0x3F00) + { + pixel = addr & 0x1F; + } + pixelcolor = PALRAM[pixel]; + pixelcolor |= 0x8000; //whats this? i think its a flag to indicate a hidden background to be used by the canvas filling logic later + } + + //generate the BG data + if (renderbgnow) + { + byte pt_0 = bgdata[bgtile].pt_0; + byte pt_1 = bgdata[bgtile].pt_1; + int sel = 7 - bgpx; + pixel = ((pt_0 >> sel) & 1) | (((pt_1 >> sel) & 1) << 1); + if (pixel != 0) + pixel |= bgdata[bgtile].at; + pixelcolor = PALRAM[pixel]; + } + + if (!nes.Settings.DispBackground) + pixelcolor = 0x8000; //whats this? i think its a flag to indicate a hidden background to be used by the canvas filling logic later + + //check if the pixel has a sprite in it + if (sl_sprites[256 + xt * 8 + xp] != 0 && renderspritenow) + { + int s = sl_sprites[xt * 8 + xp]; + int spixel = sl_sprites[256 + xt * 8 + xp]; + int temp_attr = sl_sprites[512 + xt * 8 + xp]; + + //TODO - make sure we dont trigger spritehit if the edges are masked for either BG or OBJ + //spritehit: + //1. is it sprite#0? + //2. is the bg pixel nonzero? + //then, it is spritehit. + Reg2002_objhit |= (sprite_zero_go && s == 0 && pixel != 0 && rasterpos < 255 && show_bg_new && show_obj_new); + + //priority handling, if in front of BG: + bool drawsprite = !(((temp_attr & 0x20) != 0) && ((pixel & 3) != 0)); + if (drawsprite && nes.Settings.DispSprites) + { + //bring in the palette bits and palettize + spixel |= (temp_attr & 3) << 2; + //save it for use in the framebuffer + pixelcolor = PALRAM[0x10 + spixel]; + } + } //oamcount loop + + + pipeline(pixelcolor, xt * 8 + xp); + target++; + + // clear out previous sprites from scanline buffer + //sl_sprites[xt * 8 + xp] = 0; + sl_sprites[256 + xt * 8 + xp] = 0; + //sl_sprites[512 + xt * 8 + xp] = 0; + + // end of visible part of the scanline + sprite_eval_cycle++; + xp++; + rasterpos++; + + if (xp == 8) + { + xp = 0; + xt++; + + xstart = xt << 3; target = yp_shift + xstart; - int rasterpos = xstart; + rasterpos = xstart; spriteHeight = reg_2000.obj_size_16 ? 16 : 8; //check all the conditions that can cause things to render in these 8px - bool renderspritenow = show_obj_new && (xt > 0 || reg_2001.show_obj_leftmost); - bool renderbgnow; - bool hit_pending = false; + renderspritenow = show_obj_new && (xt > 0 || reg_2001.show_obj_leftmost); + hit_pending = false; - for (int xp = 0; xp < 8; xp++, rasterpos++) - { - ////////////////////////////////////////////////// - //Sprite Evaluation Start - ////////////////////////////////////////////////// - if (ppur.status.cycle <= 63 && !is_even_cycle) - { - // the first 64 cycles of each scanline are used to initialize sceondary OAM - // the actual effect setting a flag that always returns 0xFF from a OAM read - // this is a bit of a shortcut to save some instructions - // data is read from OAM as normal but never used - soam[soam_index] = 0xFF; - soam_index++; - } - if (ppur.status.cycle == 64) - { - soam_index = 0; - oam_index = reg_2003; - } - - // otherwise, scan through OAM and test if sprites are in range - // if they are, they get copied to the secondary OAM - if (ppur.status.cycle >= 64) - { - if (oam_index >= 256) - { - oam_index = 0; - sprite_eval_write = false; - } - - if (is_even_cycle && oam_index < 256) - { - if ((oam_index + soam_m_index) < 256) - read_value = OAM[oam_index + soam_m_index]; - else - read_value = OAM[oam_index + soam_m_index - 256]; - } - else if (!sprite_eval_write) - { - // if we don't write sprites anymore, just scan through the oam - read_value = soam[0]; - oam_index += 4; - } - else if (sprite_eval_write) - { - //look for sprites - if (spr_true_count == 0 && soam_index < 8) - { - soam[soam_index * 4] = read_value; - } - - if (soam_index < 8) - { - if (yp >= read_value && yp < read_value + spriteHeight && spr_true_count == 0) - { - //a flag gets set if sprite zero is in range - if (oam_index == reg_2003) - sprite_zero_in_range = true; - - spr_true_count++; - soam_m_index++; - } - else if (spr_true_count > 0 && spr_true_count < 4) - { - soam[soam_index * 4 + soam_m_index] = read_value; - - soam_m_index++; - - spr_true_count++; - if (spr_true_count == 4) - { - oam_index += 4; - soam_index++; - if (soam_index == 8) - { - // oam_index could be pathologically misaligned at this point, so we have to find the next - // nearest actual sprite to work on >8 sprites per scanline option - oam_index_aux = (oam_index % 4) * 4; - } - - soam_m_index = 0; - spr_true_count = 0; - } - } - else - { - oam_index += 4; - } - } - else if (soam_index >= 8) - { - if (yp >= read_value && yp < read_value + spriteHeight && PPUON) - { - hit_pending = true; - //Reg2002_objoverflow = true; - } - - if (yp >= read_value && yp < read_value + spriteHeight && spr_true_count == 0) - { - spr_true_count++; - soam_m_index++; - } - else if (spr_true_count > 0 && spr_true_count < 4) - { - soam_m_index++; - - spr_true_count++; - if (spr_true_count == 4) - { - oam_index += 4; - soam_index++; - soam_m_index = 0; - spr_true_count = 0; - } - } - else - { - oam_index += 4; - if (soam_index == 8) - { - soam_m_index++; // glitchy increment - soam_m_index &= 3; - } - - } - - read_value = soam[0]; //writes change to reads - } - - } - - } - - ////////////////////////////////////////////////// - //Sprite Evaluation End - ////////////////////////////////////////////////// - - //process the current clock's worth of bg data fetching - //this needs to be split into 8 pieces or else exact sprite 0 hitting wont work due to the cpu not running while the sprite renders below - - - if (PPUON) - Read_bgdata(xp, ref bgdata[xt + 2]); - - runppu(1); - - if (PPUON && xp == 6) - { - ppu_was_on = true; - } - - if (PPUON && xp == 7) - { - if (!race_2006) - ppur.increment_hsc(); - - if (ppur.status.cycle == 256 && !race_2006) - ppur.increment_vs(); - - ppu_was_on = false; - } - - if (hit_pending) - { - hit_pending = false; - Reg2002_objoverflow = true; - } - - renderbgnow = show_bg_new && (xt > 0 || reg_2001.show_bg_leftmost); - //bg pos is different from raster pos due to its offsetability. - //so adjust for that here - int bgpos = rasterpos + ppur.fh; - int bgpx = bgpos & 7; - int bgtile = bgpos >> 3; - - int pixel = 0, pixelcolor = PALRAM[pixel]; - - //according to qeed's doc, use palette 0 or $2006's value if it is & 0x3Fxx - //at one point I commented this out to fix bottom-left garbage in DW4. but it's needed for full_nes_palette. - //solution is to only run when PPU is actually OFF (left-suppression doesnt count) - if (!PPUON) - { - // if there's anything wrong with how we're doing this, someone please chime in - int addr = ppur.get_2007access(); - if ((addr & 0x3F00) == 0x3F00) - { - pixel = addr & 0x1F; - } - pixelcolor = PALRAM[pixel]; - pixelcolor |= 0x8000; //whats this? i think its a flag to indicate a hidden background to be used by the canvas filling logic later - } - - //generate the BG data - if (renderbgnow) - { - byte pt_0 = bgdata[bgtile].pt_0; - byte pt_1 = bgdata[bgtile].pt_1; - int sel = 7 - bgpx; - pixel = ((pt_0 >> sel) & 1) | (((pt_1 >> sel) & 1) << 1); - if (pixel != 0) - pixel |= bgdata[bgtile].at; - pixelcolor = PALRAM[pixel]; - } - - if (!nes.Settings.DispBackground) - pixelcolor = 0x8000; //whats this? i think its a flag to indicate a hidden background to be used by the canvas filling logic later - - //check if the pixel has a sprite in it - if (sl_sprites[1, xt * 8 + xp] != 0 && renderspritenow) - { - int s = sl_sprites[0, xt * 8 + xp]; - int spixel = sl_sprites[1, xt * 8 + xp]; - int temp_attr = sl_sprites[2, xt * 8 + xp]; - - //TODO - make sure we dont trigger spritehit if the edges are masked for either BG or OBJ - //spritehit: - //1. is it sprite#0? - //2. is the bg pixel nonzero? - //then, it is spritehit. - Reg2002_objhit |= (sprite_zero_go && s == 0 && pixel != 0 && rasterpos < 255 && show_bg_new && show_obj_new); - - //priority handling, if in front of BG: - bool drawsprite = !(((temp_attr & 0x20) != 0) && ((pixel & 3) != 0)); - if (drawsprite && nes.Settings.DispSprites) - { - //bring in the palette bits and palettize - spixel |= (temp_attr & 3) << 2; - //save it for use in the framebuffer - pixelcolor = PALRAM[0x10 + spixel]; - } - } //oamcount loop - - - pipeline(pixelcolor, target, xt * 8 + xp); - target++; - - // clear out previous sprites from scanline buffer - sl_sprites[0, xt * 8 + xp] = 0; - sl_sprites[1, xt * 8 + xp] = 0; - sl_sprites[2, xt * 8 + xp] = 0; - - - } //loop across 8 pixels - } //loop across 32 tiles - } - else - for (int xt = 0; xt < 32; xt++) - Read_bgdata(ref bgdata[xt + 2]); - - // normally only 8 sprites are allowed, but with a particular setting we can have more then that - // this extra bit takes care of it quickly - soam_index_aux = 8; - - if (nes.Settings.AllowMoreThanEightSprites) - { - while (oam_index_aux < 64 && soam_index_aux < 64) - { - //look for sprites - soam[soam_index_aux * 4] = OAM[oam_index_aux * 4]; - read_value_aux = OAM[oam_index_aux * 4]; - if (yp >= read_value_aux && yp < read_value_aux + spriteHeight) - { - soam[soam_index_aux * 4 + 1] = OAM[oam_index_aux * 4 + 1]; - soam[soam_index_aux * 4 + 2] = OAM[oam_index_aux * 4 + 2]; - soam[soam_index_aux * 4 + 3] = OAM[oam_index_aux * 4 + 3]; - soam_index_aux++; - oam_index_aux++; - } - else - { - oam_index_aux++; - } } } - - soam_index_prev = soam_index_aux; - - if (soam_index_prev > 8 && !nes.Settings.AllowMoreThanEightSprites) - soam_index_prev = 8; - - ppuphase = PPUPHASE.OBJ; - - spriteHeight = reg_2000.obj_size_16 ? 16 : 8; - - for (int s = 0; s < 8; s++) + else { - bool junksprite = (!PPUON); + // if scanline is the pre-render line, we just read BG data + Read_bgdata(xp, ref bgdata[xt + 2]); + + runppu(); + + if (PPUON && xp == 6) + { + ppu_was_on = true; + } + + if (PPUON && xp == 7) + { + if (!race_2006) + ppur.increment_hsc(); + + if (ppur.status.cycle == 256 && !race_2006) + ppur.increment_vs(); + + ppu_was_on = false; + } + + xp++; + + if (xp == 8) + { + xp = 0; + xt++; + } + } + } + else if (ppur.status.cycle < 320) + { + // after we are done with the visible part of the frame, we reach sprite transfer to temp OAM tables and such + if (ppur.status.cycle == 256) + { + // do the more then 8 sprites stuff here where it is convenient + // normally only 8 sprites are allowed, but with a particular setting we can have more then that + // this extra bit takes care of it quickly + soam_index_aux = 8; + + if (nes.Settings.AllowMoreThanEightSprites) + { + while (oam_index_aux < 64 && soam_index_aux < 64) + { + //look for sprites + soam[soam_index_aux * 4] = OAM[oam_index_aux * 4]; + if (yp >= OAM[oam_index_aux * 4] && yp < OAM[oam_index_aux * 4] + spriteHeight) + { + soam[soam_index_aux * 4 + 1] = OAM[oam_index_aux * 4 + 1]; + soam[soam_index_aux * 4 + 2] = OAM[oam_index_aux * 4 + 2]; + soam[soam_index_aux * 4 + 3] = OAM[oam_index_aux * 4 + 3]; + soam_index_aux++; + oam_index_aux++; + } + else + { + oam_index_aux++; + } + } + } + + soam_index_prev = soam_index_aux; + + if (soam_index_prev > 8 && !nes.Settings.AllowMoreThanEightSprites) + soam_index_prev = 8; + + ppuphase = PPUPHASE.OBJ; + + spriteHeight = reg_2000.obj_size_16 ? 16 : 8; + + s = 0; + ppu_aux_index = 0; + + junksprite = (!PPUON); t_oam[s].oam_y = soam[s * 4]; t_oam[s].oam_ind = soam[s * 4 + 1]; t_oam[s].oam_attr = soam[s * 4 + 2]; t_oam[s].oam_x = soam[s * 4 + 3]; - int line = yp - t_oam[s].oam_y; + line = yp - t_oam[s].oam_y; if ((t_oam[s].oam_attr & 0x80) != 0) //vflip line = spriteHeight - line - 1; - int patternNumber = t_oam[s].oam_ind; - int patternAddress; + patternNumber = t_oam[s].oam_ind; + } - //8x16 sprite handling: - if (reg_2000.obj_size_16) - { - int bank = (patternNumber & 1) << 12; - patternNumber = patternNumber & ~1; - patternNumber |= (line >> 3) & 1; - patternAddress = (patternNumber << 4) | bank; - } - else - patternAddress = (patternNumber << 4) | (reg_2000.obj_pattern_hi << 12); - - //offset into the pattern for the current line. - //tricky: tall sprites have already had lines>8 taken care of by getting a new pattern number above. - //so we just need the line offset for the second pattern - patternAddress += line & 7; - - //garbage nametable fetches + scroll resets - int garbage_todo = 2; - - ppubus_read(ppur.get_ntread(), true, true); - - if (PPUON) - { - if (sl == 0 && ppur.status.cycle == 304) - { - - read_value = t_oam[s].oam_y; - runppu(1); - - if (PPUON) ppur.install_latches(); - - read_value = t_oam[s].oam_ind; - runppu(1); - - - garbage_todo = 0; - } - if ((sl != 0) && ppur.status.cycle == 256) - { - - read_value = t_oam[s].oam_y; - - runppu(1); - - if (target <= 61441 && target > 0 && s == 0) - { - pipeline(0, target, 256); - target++; - } - - //at 257: 3d world runner is ugly if we do this at 256 - if (PPUON) ppur.install_h_latches(); - read_value = t_oam[s].oam_ind; - runppu(1); - - if (target <= 61441 && target > 0 && s == 0) - { - pipeline(0, target, 257); // last pipeline call option 1 of 2 - } - garbage_todo = 0; - } - } - - for (int i = 0; i < garbage_todo; i++) - { - if (i == 0) - read_value = t_oam[s].oam_y; - else - read_value = t_oam[s].oam_ind; - - runppu(1); - - if (i == 0) - { - if (target <= 61441 && target > 0 && s == 0) - { - pipeline(0, target, 256); - target++; - } - } - else - { - if (target <= 61441 && target > 0 && s == 0) - { - pipeline(0, target, 257); // last pipeline call option 2 of 2 - } - } - } - - ppubus_read(ppur.get_atread(), true, true); //at or nt? - - read_value = t_oam[s].oam_attr; - runppu(1); - - read_value = t_oam[s].oam_x; - runppu(1); - - // if the PPU is off, we don't put anything on the bus - if (junksprite) - { - ppubus_read(patternAddress, true, false); - ppubus_read(patternAddress, true, false); - runppu(kFetchTime * 2); - } - else - { - int addr = patternAddress; - t_oam[s].patterns_0 = ppubus_read(addr, true, true); - read_value = t_oam[s].oam_x; - runppu(kFetchTime); - - addr += 8; - t_oam[s].patterns_1 = ppubus_read(addr, true, true); - read_value = t_oam[s].oam_x; - runppu(kFetchTime); - - // hflip - if ((t_oam[s].oam_attr & 0x40) == 0) - { - t_oam[s].patterns_0 = BitReverse.Byte8[t_oam[s].patterns_0]; - t_oam[s].patterns_1 = BitReverse.Byte8[t_oam[s].patterns_1]; - } - - // if the sprites attribute is 0xFF, then this indicates a non-existent sprite - // I think the logic here is that bits 2-4 in OAM are disabled, but soam is initialized with 0xFF - // so the only way a sprite could have an 0xFF attribute is if it is not in the scope of the scanline - if (t_oam[s].oam_attr == 0xFF) - { - t_oam[s].patterns_0 = 0; - t_oam[s].patterns_1 = 0; - } - - } - - // now that we have a sprite, we can fill in the next scnaline's sprite pixels with it - // this saves quite a bit of processing compared to checking each pixel - - if (s < soam_index_prev) - { - int temp_x = t_oam[s].oam_x; - for (int i = 0; (temp_x + i) < 256 && i < 8; i++) - { - if (sl_sprites[1, temp_x + i] == 0) - { - if (t_oam[s].patterns_0.Bit(i) || t_oam[s].patterns_1.Bit(i)) - { - int spixel = t_oam[s].patterns_0.Bit(i) ? 1 : 0; - spixel |= (t_oam[s].patterns_1.Bit(i) ? 2 : 0); - - sl_sprites[0, temp_x + i] = (byte)s; - sl_sprites[1, temp_x + i] = (byte)spixel; - sl_sprites[2, temp_x + i] = t_oam[s].oam_attr; - - } - } - } - } - - } // sprite pattern fetch loop - - //now do the same for extra sprites, but without any cycles run - if (soam_index_aux > 8) + switch (ppu_aux_index) { - for (int s = 8; s < soam_index_aux; s++) - { - t_oam[s].oam_y = soam[s * 4]; - t_oam[s].oam_ind = soam[s * 4 + 1]; - t_oam[s].oam_attr = soam[s * 4 + 2]; - t_oam[s].oam_x = soam[s * 4 + 3]; - - int line = yp - t_oam[s].oam_y; - if ((t_oam[s].oam_attr & 0x80) != 0) //vflip - line = spriteHeight - line - 1; - - int patternNumber = t_oam[s].oam_ind; - int patternAddress; - + case 0: //8x16 sprite handling: if (reg_2000.obj_size_16) { @@ -736,91 +606,364 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //so we just need the line offset for the second pattern patternAddress += line & 7; - ppubus_read(ppur.get_ntread(), true, false); + ppubus_read(ppur.get_ntread(), true, true); - ppubus_read(ppur.get_atread(), true, false); //at or nt? - - int addr = patternAddress; - t_oam[s].patterns_0 = ppubus_read(addr, true, false); - - addr += 8; - t_oam[s].patterns_1 = ppubus_read(addr, true, false); - - // hflip - if ((t_oam[s].oam_attr & 0x40) == 0) + read_value = t_oam[s].oam_y; + runppu(); + break; + case 1: + if (PPUON && ppur.status.sl == 0 && ppur.status.cycle == 305) { - t_oam[s].patterns_0 = BitReverse.Byte8[t_oam[s].patterns_0]; - t_oam[s].patterns_1 = BitReverse.Byte8[t_oam[s].patterns_1]; - } + ppur.install_latches(); - // if the sprites attribute is 0xFF, then this indicates a non-existent sprite - // I think the logic here is that bits 2-4 in OAM are disabled, but soam is initialized with 0xFF - // so the only way a sprite could have an 0xFF attribute is if it is not in the scope of the scanline - if (t_oam[s].oam_attr == 0xFF) + read_value = t_oam[s].oam_ind; + runppu(); + + } + else if (PPUON && (ppur.status.sl != 0) && ppur.status.cycle == 257) { - t_oam[s].patterns_0 = 0; - t_oam[s].patterns_1 = 0; - } + if (target <= 61441 && target > 0 && s == 0) + { + pipeline(0, 256); + target++; + } + + //at 257: 3d world runner is ugly if we do this at 256 + if (PPUON) ppur.install_h_latches(); + read_value = t_oam[s].oam_ind; + runppu(); + + if (target <= 61441 && target > 0 && s == 0) + { + pipeline(0, 257); // last pipeline call option 1 of 2 + } + } + else + { + if (target <= 61441 && target > 0 && s == 0) + { + pipeline(0, 256); + target++; + } + + read_value = t_oam[s].oam_ind; + runppu(); + + if (target <= 61441 && target > 0 && s == 0) + { + pipeline(0, 257); // last pipeline call option 2 of 2 + } + } + break; + + case 2: + ppubus_read(ppur.get_atread(), true, true); //at or nt? + read_value = t_oam[s].oam_attr; + runppu(); + break; + + case 3: + read_value = t_oam[s].oam_x; + runppu(); + break; + + case 4: + // if the PPU is off, we don't put anything on the bus + if (junksprite) + { + ppubus_read(patternAddress, true, false); + runppu(); + } + else + { + temp_addr = patternAddress; + t_oam[s].patterns_0 = ppubus_read(temp_addr, true, true); + read_value = t_oam[s].oam_x; + runppu(); + } + break; + case 5: + // if the PPU is off, we don't put anything on the bus + if (junksprite) + { + runppu(); + } + else + { + runppu(); + } + break; + case 6: + // if the PPU is off, we don't put anything on the bus + if (junksprite) + { + ppubus_read(patternAddress, true, false); + runppu(); + } + else + { + temp_addr += 8; + t_oam[s].patterns_1 = ppubus_read(temp_addr, true, true); + read_value = t_oam[s].oam_x; + runppu(); + } + break; + case 7: + // if the PPU is off, we don't put anything on the bus + if (junksprite) + { + runppu(); + } + else + { + runppu(); + + // hflip + if ((t_oam[s].oam_attr & 0x40) == 0) + { + t_oam[s].patterns_0 = BitReverse.Byte8[t_oam[s].patterns_0]; + t_oam[s].patterns_1 = BitReverse.Byte8[t_oam[s].patterns_1]; + } + + // if the sprites attribute is 0xFF, then this indicates a non-existent sprite + // I think the logic here is that bits 2-4 in OAM are disabled, but soam is initialized with 0xFF + // so the only way a sprite could have an 0xFF attribute is if it is not in the scope of the scanline + if (t_oam[s].oam_attr == 0xFF) + { + t_oam[s].patterns_0 = 0; + t_oam[s].patterns_1 = 0; + } + + } + break; + } + + ppu_aux_index++; + if (ppu_aux_index == 8) + { + // now that we have a sprite, we can fill in the next scnaline's sprite pixels with it + // this saves quite a bit of processing compared to checking each pixel + + if (s < soam_index_prev) + { int temp_x = t_oam[s].oam_x; for (int i = 0; (temp_x + i) < 256 && i < 8; i++) { - if (sl_sprites[1, temp_x + i] == 0) + if (sl_sprites[256 + temp_x + i] == 0) { if (t_oam[s].patterns_0.Bit(i) || t_oam[s].patterns_1.Bit(i)) { int spixel = t_oam[s].patterns_0.Bit(i) ? 1 : 0; spixel |= (t_oam[s].patterns_1.Bit(i) ? 2 : 0); - sl_sprites[0, temp_x + i] = (byte)s; - sl_sprites[1, temp_x + i] = (byte)spixel; - sl_sprites[2, temp_x + i] = t_oam[s].oam_attr; - + sl_sprites[temp_x + i] = (byte)s; + sl_sprites[256 + temp_x + i] = (byte)spixel; + sl_sprites[512 + temp_x + i] = t_oam[s].oam_attr; } } } - } // sprite pattern fetch loop + } + ppu_aux_index = 0; + s++; + + if (s < 8) + { + junksprite = (!PPUON); + + t_oam[s].oam_y = soam[s * 4]; + t_oam[s].oam_ind = soam[s * 4 + 1]; + t_oam[s].oam_attr = soam[s * 4 + 2]; + t_oam[s].oam_x = soam[s * 4 + 3]; + + line = yp - t_oam[s].oam_y; + if ((t_oam[s].oam_attr & 0x80) != 0) //vflip + line = spriteHeight - line - 1; + + patternNumber = t_oam[s].oam_ind; + } + else + { + // repeat all the above steps for more then 8 sprites but don't run any cycles + if (soam_index_aux > 8) + { + for (int s = 8; s < soam_index_aux; s++) + { + t_oam[s].oam_y = soam[s * 4]; + t_oam[s].oam_ind = soam[s * 4 + 1]; + t_oam[s].oam_attr = soam[s * 4 + 2]; + t_oam[s].oam_x = soam[s * 4 + 3]; + + int line = yp - t_oam[s].oam_y; + if ((t_oam[s].oam_attr & 0x80) != 0) //vflip + line = spriteHeight - line - 1; + + int patternNumber = t_oam[s].oam_ind; + int patternAddress; + + //8x16 sprite handling: + if (reg_2000.obj_size_16) + { + int bank = (patternNumber & 1) << 12; + patternNumber = patternNumber & ~1; + patternNumber |= (line >> 3) & 1; + patternAddress = (patternNumber << 4) | bank; + } + else + patternAddress = (patternNumber << 4) | (reg_2000.obj_pattern_hi << 12); + + //offset into the pattern for the current line. + //tricky: tall sprites have already had lines>8 taken care of by getting a new pattern number above. + //so we just need the line offset for the second pattern + patternAddress += line & 7; + + ppubus_read(ppur.get_ntread(), true, false); + + ppubus_read(ppur.get_atread(), true, false); //at or nt? + + int addr = patternAddress; + t_oam[s].patterns_0 = ppubus_read(addr, true, false); + + addr += 8; + t_oam[s].patterns_1 = ppubus_read(addr, true, false); + + // hflip + if ((t_oam[s].oam_attr & 0x40) == 0) + { + t_oam[s].patterns_0 = BitReverse.Byte8[t_oam[s].patterns_0]; + t_oam[s].patterns_1 = BitReverse.Byte8[t_oam[s].patterns_1]; + } + + // if the sprites attribute is 0xFF, then this indicates a non-existent sprite + // I think the logic here is that bits 2-4 in OAM are disabled, but soam is initialized with 0xFF + // so the only way a sprite could have an 0xFF attribute is if it is not in the scope of the scanline + if (t_oam[s].oam_attr == 0xFF) + { + t_oam[s].patterns_0 = 0; + t_oam[s].patterns_1 = 0; + } + + int temp_x = t_oam[s].oam_x; + for (int i = 0; (temp_x + i) < 256 && i < 8; i++) + { + if (sl_sprites[256 + temp_x + i] == 0) + { + if (t_oam[s].patterns_0.Bit(i) || t_oam[s].patterns_1.Bit(i)) + { + int spixel = t_oam[s].patterns_0.Bit(i) ? 1 : 0; + spixel |= (t_oam[s].patterns_1.Bit(i) ? 2 : 0); + + sl_sprites[temp_x + i] = (byte)s; + sl_sprites[256 + temp_x + i] = (byte)spixel; + sl_sprites[512 + temp_x + i] = t_oam[s].oam_attr; + } + } + } + } + } + } } - - ppuphase = PPUPHASE.BG; - - // fetch BG: two tiles for next line - for (int xt = 0; xt < 2; xt++) + } + else + { + if (ppur.status.cycle == 320) { - Read_bgdata(ref bgdata[xt]); + ppuphase = PPUPHASE.BG; + xt = 0; + xp = 0; } - // this sequence is tuned to pass 10-even_odd_timing.nes - runppu(4); - bool evenOddDestiny = PPUON; + if (ppur.status.cycle < 336) + { + // if scanline is the pre-render line, we just read BG data + Read_bgdata(xp, ref bgdata[xt]); - // After memory access 170, the PPU simply rests for 4 cycles (or the - // equivelant of half a memory access cycle) before repeating the whole - // pixel/scanline rendering process. If the scanline being rendered is the very - // first one on every second frame, then this delay simply doesn't exist. - if (sl == 0 && idleSynch && evenOddDestiny && chopdot) - { } + runppu(); + + if (PPUON && xp == 6) + { + ppu_was_on = true; + } + + if (PPUON && xp == 7) + { + if (!race_2006) + ppur.increment_hsc(); + + if (ppur.status.cycle == 256 && !race_2006) + ppur.increment_vs(); + + ppu_was_on = false; + } + + xp++; + + if (xp == 8) + { + xp = 0; + xt++; + } + } + else if (ppur.status.cycle < 340) + { + runppu(); + } else - runppu(1); - } // scanline loop + { + bool evenOddDestiny = PPUON; - ppur.status.sl = 241; + // After memory access 170, the PPU simply rests for 4 cycles (or the + // equivelant of half a memory access cycle) before repeating the whole + // pixel/scanline rendering process. If the scanline being rendered is the very + // first one on every second frame, then this delay simply doesn't exist. + if (ppur.status.sl == 0 && idleSynch && evenOddDestiny && chopdot) + { ppur.status.cycle++; } // increment cycle without running ppu + else + { runppu(); } + } + } - //idle for pre NMI lines - runppu(preNMIlines * kLineTime); - } //FrameAdvance + if (ppur.status.cycle == 341) + { + ppur.status.cycle = 0; + ppur.status.sl++; - void FrameAdvance_ppudead() + if (ppur.status.sl == 241) + { + do_active_sl = false; + } + } + } + + public void TickPPU_preVBL() { - //not quite emulating all the NES power up behavior - //since it is known that the NES ignores writes to some - //register before around a full frame, but no games - //should write to those regs during that time, it needs - //to wait for vblank + runppu(); - runppu(241 * kLineTime - 3);// -8*3); - ppudead--; + if (ppur.status.cycle == 341) + { + ppur.status.cycle = 0; + ppur.status.sl++; + if (ppur.status.sl == 241 + preNMIlines) + { + do_pre_vbl = false; + } + } + } + + //not quite emulating all the NES power up behavior + //since it is known that the NES ignores writes to some + //register before around a full frame, but no games + //should write to those regs during that time, it needs + //to wait for vblank + public void NewDeadPPU() + { + runppu(); + + if (ppur.status.cycle == 241 * 341 - 3) + { + ppudead--; + } } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs index bec2f23068..c0fb578f40 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs @@ -427,6 +427,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES "ED8ACE4BDA8DAA9832E12D59911A942B8C105A46", // Jajamaru Ninpou Chou (J) [hM04] "123045D5E8CF038C2FD396BD266EEF96DAFF9BCD", // Jikuu Yuuden - Debias (J) [o1] "123045D5E8CF038C2FD396BD266EEF96DAFF9BCD", // Jikuu Yuuden - Debias (J) [!] + "76DB18B90FB2B76FA685D6462846ED3A92F5CBD4", // Joe and Mac (U) [!] + "7E1C9F23BF9BECB7831459598339A4DC9A3CECFC", // Joe and Mac (E) [!] "A654DE12A59D07BAFF30DD6CB5E1AD05EB20B2D7", // Jumpy Demo by Rwin (PD) "DE42818873470458DF29F515A193F536A0642EA8", // Kamikaze Mario DX Plus V1 "BFECB191CFD480B14B7169441DB3D389A4B634D2", // Kamikaze Mario DX Plus V1 diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi.cs index 76fd98c74c..4f61f1c23d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi.cs @@ -151,6 +151,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES public Action ReadHook, ExecHook; public Action WriteHook; + public Action ReadHook_SMP, ExecHook_SMP; + public Action WriteHook_SMP; + public enum eCDLog_AddrType { CARTROM, CARTRAM, WRAM, APURAM, diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi_BRK.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi_BRK.cs index ea281c0586..1a4d85e337 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi_BRK.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi_BRK.cs @@ -25,6 +25,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES WriteHook(_comm->addr, (byte)_comm->value); break; + case eMessage.eMessage_BRK_hook_exec_smp: + ExecHook_SMP(_comm->addr); + break; + case eMessage.eMessage_BRK_hook_read_smp: + ReadHook_SMP(_comm->addr); + break; + case eMessage.eMessage_BRK_hook_write_smp: + WriteHook_SMP(_comm->addr, (byte)_comm->value); + break; + //not supported yet case eMessage.eMessage_BRK_hook_nmi: break; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi_Enums.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi_Enums.cs index a21e05584f..440db2278a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi_Enums.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi_Enums.cs @@ -24,6 +24,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES eMessage_QUERY_state_hook_write, eMessage_QUERY_state_hook_nmi, eMessage_QUERY_state_hook_irq, + eMessage_QUERY_state_hook_exec_smp, + eMessage_QUERY_state_hook_read_smp, + eMessage_QUERY_state_hook_write_smp, eMessage_QUERY_enable_trace, eMessage_QUERY_enable_scanline, eMessage_QUERY_enable_audio, @@ -63,6 +66,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES eMessage_BRK_hook_write, eMessage_BRK_hook_nmi, eMessage_BRK_hook_irq, + eMessage_BRK_hook_exec_smp, + eMessage_BRK_hook_read_smp, + eMessage_BRK_hook_write_smp, eMessage_BRK_scanlineStart, }; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IDebuggable.cs index efc27e4288..92fa298885 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IDebuggable.cs @@ -55,7 +55,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES throw new NotImplementedException(); } - public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(); + public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" }); public bool CanStep(StepType type) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IMemoryDomains.cs index ebb2853714..874a443f03 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IMemoryDomains.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IMemoryDomains.cs @@ -71,8 +71,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES MakeMemoryDomain("SGB HRAM", LibsnesApi.SNES_MEMORY.SGB_HRAM, MemoryDomain.Endian.Little); MakeMemoryDomain("SGB CARTRAM", LibsnesApi.SNES_MEMORY.SGB_CARTRAM, MemoryDomain.Endian.Little); - - MakeMemoryDomain("WRAM", LibsnesApi.SNES_MEMORY.WRAM, MemoryDomain.Endian.Little); } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs index 3b82b711bf..94e6335b79 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs @@ -63,7 +63,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES { ReadHook = ReadHook, ExecHook = ExecHook, - WriteHook = WriteHook + WriteHook = WriteHook, + ReadHook_SMP = ReadHook_SMP, + ExecHook_SMP = ExecHook_SMP, + WriteHook_SMP = WriteHook_SMP, }; ScanlineHookManager = new MyScanlineHookManager(this); @@ -361,7 +364,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES private void ReadHook(uint addr) { - MemoryCallbacks.CallReads(addr); + MemoryCallbacks.CallReads(addr, "System Bus"); // we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point // EDIT: for now, theres some IPC re-entrancy problem // RefreshMemoryCallbacks(); @@ -369,7 +372,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES private void ExecHook(uint addr) { - MemoryCallbacks.CallExecutes(addr); + MemoryCallbacks.CallExecutes(addr, "System Bus"); // we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point // EDIT: for now, theres some IPC re-entrancy problem // RefreshMemoryCallbacks(); @@ -377,12 +380,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES private void WriteHook(uint addr, byte val) { - MemoryCallbacks.CallWrites(addr); + MemoryCallbacks.CallWrites(addr, "System Bus"); // we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point // EDIT: for now, theres some IPC re-entrancy problem // RefreshMemoryCallbacks(); } + private void ReadHook_SMP(uint addr) + { + MemoryCallbacks.CallReads(addr, "SMP"); + } + + private void ExecHook_SMP(uint addr) + { + MemoryCallbacks.CallExecutes(addr, "SMP"); + } + + private void WriteHook_SMP(uint addr, byte val) + { + MemoryCallbacks.CallWrites(addr, "SMP"); + } + private enum LoadParamType { Normal, SuperGameBoy @@ -557,9 +575,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES private void RefreshMemoryCallbacks(bool suppress) { var mcs = MemoryCallbacks; - Api.QUERY_set_state_hook_exec(!suppress && mcs.HasExecutes); - Api.QUERY_set_state_hook_read(!suppress && mcs.HasReads); - Api.QUERY_set_state_hook_write(!suppress && mcs.HasWrites); + Api.QUERY_set_state_hook_exec(!suppress && mcs.HasExecutesForScope("System Bus")); + Api.QUERY_set_state_hook_read(!suppress && mcs.HasReadsForScope("System Bus")); + Api.QUERY_set_state_hook_write(!suppress && mcs.HasWritesForScope("System Bus")); } //public byte[] snes_get_memory_data_read(LibsnesApi.SNES_MEMORY id) diff --git a/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.cs b/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.cs index 3eda6208b5..808a751862 100644 --- a/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.cs +++ b/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.cs @@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.PCEngine [CoreConstructor("PCE", "SGX")] public PCEngine(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings) { - MemoryCallbacks = new MemoryCallbackSystem(); + MemoryCallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); CoreComm = comm; switch (game.System) @@ -53,7 +53,7 @@ namespace BizHawk.Emulation.Cores.PCEngine public PCEngine(CoreComm comm, GameInfo game, Disc disc, object Settings, object syncSettings) { CoreComm = comm; - MemoryCallbacks = new MemoryCallbackSystem(); + MemoryCallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); DriveLightEnabled = true; SystemId = "PCECD"; Type = NecSystemType.TurboCD; diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/Compat.txt b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/Compat.txt index 128e46f9f8..122814b815 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/Compat.txt +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/Compat.txt @@ -9,10 +9,6 @@ Korean games currently not booting: * Desert Strike - you can enter the map screen but cannot leave. -- Light Gun emulation -- Paddle emulation -- Sports pad emulation? - ======= Game Gear compatibility issues ======= * Outrun has raster effect on the wrong line. I've been able to modify interrupt code to diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/EEPROM.93c46.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/EEPROM.93c46.cs new file mode 100644 index 0000000000..ec0acddec1 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/EEPROM.93c46.cs @@ -0,0 +1,233 @@ +using System; +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Sega.MasterSystem +{ + class EEPROM93c46 + { + enum EEPROMWriteMode + { + Instruction, + WriteData, + WriteAll, + Read + } + + enum EEPROMReadMode + { + ReadNew, + ReadOld, + Hold + } + + [Flags] + enum EEPROMFlags : byte + { + Ready = 1, + Clock = 2, + ChipSelect = 4 + } + + ushort Address = 0; + ushort Value = 0; + int BitsWritten = 0; + int BitsRead = 0; + bool WriteEnable = false; + EEPROMWriteMode WriteMode = EEPROMWriteMode.Instruction; + EEPROMReadMode ReadMode = EEPROMReadMode.Hold; + EEPROMFlags Flags = 0; + + public byte Read(byte[] saveRAM) + { + switch (ReadMode) + { + case EEPROMReadMode.ReadNew: + // A new value clocking out + + ReadMode = EEPROMReadMode.ReadOld; + byte ret = Read(saveRAM); + + if (++BitsRead == 8) + { + // Increment address + BitsRead = 0; + ++Address; + + if(Address % 2 == 0) + { + WriteMode = EEPROMWriteMode.Instruction; + ReadMode = EEPROMReadMode.Hold; + BitsWritten = 0; + Value = 0; + } + } + + return ret; + case EEPROMReadMode.ReadOld: + // repeat old value + + byte bit = (byte)((saveRAM[Address % saveRAM.Length] >> (7 - BitsRead)) & 1); + + return (byte)((byte)(Flags | EEPROMFlags.Clock) | bit); + default: + // ready/busy flag is always ready in this emulation + return (byte)(Flags | EEPROMFlags.Clock | EEPROMFlags.Ready); + } + } + + public void Write(byte bit, byte[] saveRAM) + { + // new instruction? + if ((bit & 4) == 0) + { + WriteMode = EEPROMWriteMode.Instruction; + ReadMode = EEPROMReadMode.Hold; + BitsWritten = 0; + Value = 0; + + Flags = (EEPROMFlags)bit & ~EEPROMFlags.Ready; + return; + } + + // clock low to high? + if ((bit & (byte)EEPROMFlags.Clock) != 0 && (Flags & EEPROMFlags.Clock) == 0) + { + // all modes shift in a larger value + Value = (ushort)((Value << 1) | (bit & 1)); + ++BitsWritten; + + switch (WriteMode) + { + case EEPROMWriteMode.Instruction: + // Process opcode including start bit + + // check start bit + if ((Value & 0x100) == 0) + return; + + byte op = (byte)Value; + Value = 0; + BitsWritten = 0; + + switch (op & 0xC0) + { + case 0x00: + // non-addressed commands + switch (op & 0xF0) + { + case 0x00: + // EWDS: write disable + WriteEnable = false; + return; + case 0x10: + // WRAL: write to all addresses (silly) + WriteMode = EEPROMWriteMode.WriteAll; + ReadMode = EEPROMReadMode.Hold; + return; + case 0x20: + // ERAL: erase all addresses + if (WriteEnable) + { + for (int i = 0; i < saveRAM.Length; ++i) + { + saveRAM[i] = 0xFF; + } + } + ReadMode = EEPROMReadMode.Hold; + return; + case 0x30: + // EWEN: write enable + WriteEnable = true; + return; + default: + // impossible + return; + } + case 0x40: + // WRITE + Address = (ushort)((op & 0x3F) << 1); + WriteMode = EEPROMWriteMode.WriteData; + ReadMode = EEPROMReadMode.Hold; + return; + case 0x80: + // READ + Address = (ushort)((op & 0x3F) << 1); + ReadMode = EEPROMReadMode.Hold; + WriteMode = EEPROMWriteMode.Read; + BitsRead = 0; + return; + case 0xC0: + // ERASE + Address = (ushort)((op & 0x3F) << 1); + if (WriteEnable) + { + saveRAM[Address % saveRAM.Length] = 0xFF; + saveRAM[(Address + 1) % saveRAM.Length] = 0xFF; + } + ReadMode = EEPROMReadMode.Hold; + return; + default: + // impossible + return; + } + case EEPROMWriteMode.WriteData: + // Write bits + + if (BitsWritten < 16) + return; + + if (WriteEnable) + { + saveRAM[Address % saveRAM.Length] = (byte)(Value >> 8); + saveRAM[(Address + 1) % saveRAM.Length] = (byte)Value; + } + WriteMode = EEPROMWriteMode.Instruction; + + Value = 0; + BitsWritten = 0; + return; + case EEPROMWriteMode.WriteAll: + // write to ALL addresses + + if (BitsWritten < 16) + return; + + Value = 0; + BitsWritten = 0; + + if (WriteEnable) + { + for (int i = 0; i < saveRAM.Length; i += 2) + { + saveRAM[i % saveRAM.Length] = (byte)Value; + saveRAM[(i + 1) % saveRAM.Length] = (byte)(Value >> 8); + } + } + WriteMode = EEPROMWriteMode.Instruction; + return; + case EEPROMWriteMode.Read: + // Clock a new value out + ReadMode = EEPROMReadMode.ReadNew; + + return; + } + } + + Flags = (EEPROMFlags)bit & ~EEPROMFlags.Ready; + } + + public void SyncState(Serializer ser) + { + ser.BeginSection("93c46"); + ser.Sync("Address", ref Address); + ser.Sync("Value", ref Value); + ser.Sync("BitsWritten", ref BitsWritten); + ser.Sync("BitsRead", ref BitsRead); + ser.Sync("WriteEnable", ref WriteEnable); + ser.SyncEnum("WriteMode", ref WriteMode); + ser.SyncEnum("ReadMode", ref ReadMode); + ser.SyncEnum("Flags", ref Flags); + ser.EndSection(); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.EEPROM.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.EEPROM.cs new file mode 100644 index 0000000000..2e5c544c11 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.EEPROM.cs @@ -0,0 +1,136 @@ +using System; + +namespace BizHawk.Emulation.Cores.Sega.MasterSystem +{ + public partial class SMS + { + // The 93c46-connected mapper is assumed to be equivalent to the Sega mapper except for $8000-.. + // The Sega memory mapper layout looks like so: + // $0000-$03FF - ROM (unpaged) + // $0400-$3FFF - ROM mapper slot 0 + // $4000-$7FFF - ROM mapper slot 1 + // $8000-$BFFF - ROM mapper slot 2 - OR - EEPROM + // $C000-$DFFF - System RAM + // $E000-$FFFF - System RAM (mirror) + // $FFFC - SaveRAM mapper control + // $FFFD - Mapper slot 0 control + // $FFFE - Mapper slot 1 control + // $FFFF - Mapper slot 2 control + + EEPROM93c46 EEPROM; + + byte ReadMemoryEEPROM(ushort address) + { + byte ret = 0xFF; + + if (address < 0xC000) + { + if ((Port3E & 0x48) == 0x48) // cart and bios disabled, return empty bus + ret = 0xFF; + else if (BiosMapped && BiosRom != null) + ret = BiosRom[address & 0x1FFF]; + else if (address < 1024) + ret = RomData[address]; + else if (address < 0x4000) + ret = RomData[(RomBank0 * BankSize) + address]; + else if (address < 0x8000) + ret = RomData[(RomBank1 * BankSize) + (address & BankSizeMask)]; + else + { + switch (SaveRamBank) + { + case 0: ret = RomData[(RomBank2 * BankSize) + (address & BankSizeMask)]; break; + case 1: if (SaveRAM != null && EEPROM != null) ret = EEPROM.Read(SaveRAM); break; + default: + ret = SystemRam[address & RamSizeMask]; + break; + } + } + } + else + { + ret = SystemRam[address & RamSizeMask]; + } + + return ret; + } + + CDLog_MapResults MapMemoryEEPROM(ushort address, bool write) + { + if (address < 0xC000) + { + if ((Port3E & 0x48) == 0x48) // cart and bios disabled, return empty bus + return new CDLog_MapResults(); + else if (BiosMapped && BiosRom != null) + return new CDLog_MapResults(); //bios tracking of CDL is not supported + else if (address < 1024) + return new CDLog_MapResults() { Type = CDLog_AddrType.ROM, Address = address }; + else if (address < 0x4000) + return new CDLog_MapResults() { Type = CDLog_AddrType.ROM, Address = (RomBank0 * BankSize) + address }; + else if (address < 0x8000) + return new CDLog_MapResults() { Type = CDLog_AddrType.ROM, Address = (RomBank1 * BankSize) + (address & BankSizeMask) }; + else + { + switch (SaveRamBank) + { + case 0: return new CDLog_MapResults() { Type = CDLog_AddrType.ROM, Address = (RomBank2 * BankSize) + (address & BankSizeMask) }; + case 1: return new CDLog_MapResults(); // a serial IO port + case 2: return new CDLog_MapResults(); // a serial IO port + default: + return new CDLog_MapResults() { Type = CDLog_AddrType.MainRAM, Address = address & RamSizeMask }; + } + } + } + else + { + return new CDLog_MapResults() { Type = CDLog_AddrType.MainRAM, Address = address & RamSizeMask }; + } + } + + void WriteMemoryEEPROM(ushort address, byte value) + { + if (address >= 0xC000) + SystemRam[address & RamSizeMask] = value; + + else if (address >= 0x8000) + { + if (SaveRAM != null) + { + SaveRamModified = true; + EEPROM.Write(value, SaveRAM); + return; + } + else System.Console.WriteLine("Game attempt to use SRAM but SRAM not present"); + } + + if (address >= 0xFFFC) + { + if (address == 0xFFFC) + { + if ((value & 8) != 0) + SaveRamBank = (byte)((value & 4) == 0 ? 1 : 2); // SaveRAM selected + else + SaveRamBank = 0; // ROM bank selected + + } + else if (address == 0xFFFD) RomBank0 = (byte)(value % RomBanks); + else if (address == 0xFFFE) RomBank1 = (byte)(value % RomBanks); + else if (address == 0xFFFF) RomBank2 = (byte)(value % RomBanks); + return; + } + } + + void InitEEPROMMapper() + { + ReadMemory = ReadMemoryEEPROM; + WriteMemory = WriteMemoryEEPROM; + MapMemory = MapMemoryEEPROM; + WriteMemoryEEPROM(0xFFFC, 0); + WriteMemoryEEPROM(0xFFFD, 0); + WriteMemoryEEPROM(0xFFFE, 1); + WriteMemoryEEPROM(0xFFFF, 2); + + EEPROM = new EEPROM93c46(); + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ICodeDataLogger.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ICodeDataLogger.cs index 3c5d438faf..888b0a3a2a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ICodeDataLogger.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ICodeDataLogger.cs @@ -94,9 +94,9 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem /// /// A wrapper for FetchMemory which inserts CDL logic /// - private byte FetchMemory_CDL(ushort address, bool first) + private byte FetchMemory_CDL(ushort address) { - RunCDL(address, first ? CDLog_Flags.ExecFirst : CDLog_Flags.ExecOperand); + RunCDL(address, CDLog_Flags.ExecFirst); return ReadMemory(address); } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IDebuggable.cs index 973f3e78b7..009cd5fd4c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IDebuggable.cs @@ -12,36 +12,36 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem { return new Dictionary { - ["A"] = Cpu.RegisterA, - ["AF"] = Cpu.RegisterAF, - ["B"] = Cpu.RegisterB, - ["BC"] = Cpu.RegisterBC, - ["C"] = Cpu.RegisterC, - ["D"] = Cpu.RegisterD, - ["DE"] = Cpu.RegisterDE, - ["E"] = Cpu.RegisterE, - ["F"] = Cpu.RegisterF, - ["H"] = Cpu.RegisterH, - ["HL"] = Cpu.RegisterHL, - ["I"] = Cpu.RegisterI, - ["IX"] = Cpu.RegisterIX, - ["IY"] = Cpu.RegisterIY, - ["L"] = Cpu.RegisterL, - ["PC"] = Cpu.RegisterPC, - ["R"] = Cpu.RegisterR, - ["Shadow AF"] = Cpu.RegisterShadowAF, - ["Shadow BC"] = Cpu.RegisterShadowBC, - ["Shadow DE"] = Cpu.RegisterShadowDE, - ["Shadow HL"] = Cpu.RegisterShadowHL, - ["SP"] = Cpu.RegisterSP, - ["Flag C"] = Cpu.RegisterF.Bit(0), - ["Flag N"] = Cpu.RegisterF.Bit(1), - ["Flag P/V"] = Cpu.RegisterF.Bit(2), - ["Flag 3rd"] = Cpu.RegisterF.Bit(3), - ["Flag H"] = Cpu.RegisterF.Bit(4), - ["Flag 5th"] = Cpu.RegisterF.Bit(5), - ["Flag Z"] = Cpu.RegisterF.Bit(6), - ["Flag S"] = Cpu.RegisterF.Bit(7) + ["A"] = Cpu.Regs[Cpu.A], + ["AF"] = Cpu.Regs[Cpu.F] + (Cpu.Regs[Cpu.A] << 8), + ["B"] = Cpu.Regs[Cpu.B], + ["BC"] = Cpu.Regs[Cpu.C] + (Cpu.Regs[Cpu.B] << 8), + ["C"] = Cpu.Regs[Cpu.C], + ["D"] = Cpu.Regs[Cpu.D], + ["DE"] = Cpu.Regs[Cpu.E] + (Cpu.Regs[Cpu.D] << 8), + ["E"] = Cpu.Regs[Cpu.E], + ["F"] = Cpu.Regs[Cpu.F], + ["H"] = Cpu.Regs[Cpu.H], + ["HL"] = Cpu.Regs[Cpu.L] + (Cpu.Regs[Cpu.H] << 8), + ["I"] = Cpu.Regs[Cpu.I], + ["IX"] = Cpu.Regs[Cpu.Ixl] + (Cpu.Regs[Cpu.Ixh] << 8), + ["IY"] = Cpu.Regs[Cpu.Iyl] + (Cpu.Regs[Cpu.Iyh] << 8), + ["L"] = Cpu.Regs[Cpu.L], + ["PC"] = Cpu.Regs[Cpu.PCl] + (Cpu.Regs[Cpu.PCh] << 8), + ["R"] = Cpu.Regs[Cpu.R], + ["Shadow AF"] = Cpu.Regs[Cpu.F_s] + (Cpu.Regs[Cpu.A_s] << 8), + ["Shadow BC"] = Cpu.Regs[Cpu.C_s] + (Cpu.Regs[Cpu.B_s] << 8), + ["Shadow DE"] = Cpu.Regs[Cpu.E_s] + (Cpu.Regs[Cpu.D_s] << 8), + ["Shadow HL"] = Cpu.Regs[Cpu.L_s] + (Cpu.Regs[Cpu.H_s] << 8), + ["SP"] = Cpu.Regs[Cpu.Iyl] + (Cpu.Regs[Cpu.Iyh] << 8), + ["Flag C"] = Cpu.FlagC, + ["Flag N"] = Cpu.FlagN, + ["Flag P/V"] = Cpu.FlagP, + ["Flag 3rd"] = Cpu.Flag3, + ["Flag H"] = Cpu.FlagH, + ["Flag 5th"] = Cpu.Flag5, + ["Flag Z"] = Cpu.FlagZ, + ["Flag S"] = Cpu.FlagS }; } @@ -52,70 +52,82 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem default: throw new InvalidOperationException(); case "A": - Cpu.RegisterA = (byte)value; + Cpu.Regs[Cpu.A] = (ushort)value; break; case "AF": - Cpu.RegisterAF = (byte)value; + Cpu.Regs[Cpu.F] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.A] = (ushort)(value & 0xFF00); break; case "B": - Cpu.RegisterB = (byte)value; + Cpu.Regs[Cpu.B] = (ushort)value; break; case "BC": - Cpu.RegisterBC = (byte)value; + Cpu.Regs[Cpu.C] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.B] = (ushort)(value & 0xFF00); break; case "C": - Cpu.RegisterC = (byte)value; + Cpu.Regs[Cpu.C] = (ushort)value; break; case "D": - Cpu.RegisterD = (byte)value; + Cpu.Regs[Cpu.D] = (ushort)value; break; case "DE": - Cpu.RegisterDE = (byte)value; + Cpu.Regs[Cpu.E] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.D] = (ushort)(value & 0xFF00); break; case "E": - Cpu.RegisterE = (byte)value; + Cpu.Regs[Cpu.E] = (ushort)value; break; case "F": - Cpu.RegisterF = (byte)value; + Cpu.Regs[Cpu.F] = (ushort)value; break; case "H": - Cpu.RegisterH = (byte)value; + Cpu.Regs[Cpu.H] = (ushort)value; break; case "HL": - Cpu.RegisterHL = (byte)value; + Cpu.Regs[Cpu.L] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.H] = (ushort)(value & 0xFF00); break; case "I": - Cpu.RegisterI = (byte)value; + Cpu.Regs[Cpu.I] = (ushort)value; break; case "IX": - Cpu.RegisterIX = (byte)value; + Cpu.Regs[Cpu.Ixl] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.Ixh] = (ushort)(value & 0xFF00); break; case "IY": - Cpu.RegisterIY = (byte)value; + Cpu.Regs[Cpu.Iyl] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.Iyh] = (ushort)(value & 0xFF00); break; case "L": - Cpu.RegisterL = (byte)value; + Cpu.Regs[Cpu.L] = (ushort)value; break; case "PC": - Cpu.RegisterPC = (ushort)value; + Cpu.Regs[Cpu.PCl] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.PCh] = (ushort)(value & 0xFF00); break; case "R": - Cpu.RegisterR = (byte)value; + Cpu.Regs[Cpu.R] = (ushort)value; break; case "Shadow AF": - Cpu.RegisterShadowAF = (byte)value; + Cpu.Regs[Cpu.F_s] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.A_s] = (ushort)(value & 0xFF00); break; case "Shadow BC": - Cpu.RegisterShadowBC = (byte)value; + Cpu.Regs[Cpu.C_s] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.B_s] = (ushort)(value & 0xFF00); break; case "Shadow DE": - Cpu.RegisterShadowDE = (byte)value; + Cpu.Regs[Cpu.E_s] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.D_s] = (ushort)(value & 0xFF00); break; case "Shadow HL": - Cpu.RegisterShadowHL = (byte)value; + Cpu.Regs[Cpu.L_s] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.H_s] = (ushort)(value & 0xFF00); break; case "SP": - Cpu.RegisterSP = (byte)value; + Cpu.Regs[Cpu.SPl] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.SPh] = (ushort)(value & 0xFF00); break; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs index ae2dd35788..e49a75ddad 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs @@ -1,84 +1,101 @@ -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Sega.MasterSystem -{ - public sealed partial class SMS : IEmulator - { - public IEmulatorServiceProvider ServiceProvider { get; } - - public ControllerDefinition ControllerDefinition - { - get - { - if (IsGameGear) - { - return GGController; - } - - return SmsController; - } - } - - public void FrameAdvance(IController controller, bool render, bool rendersound) - { - _controller = controller; - _lagged = true; - _frame++; - PSG.BeginFrame(Cpu.TotalExecutedCycles); - Cpu.Debug = Tracer.Enabled; - if (!IsGameGear) - { - PSG.StereoPanning = Settings.ForceStereoSeparation ? ForceStereoByte : (byte)0xFF; - } - - if (Cpu.Debug && Cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first - { - Cpu.Logger = s => Tracer.Put(s); - } - - if (IsGameGear == false) - { - Cpu.NonMaskableInterrupt = controller.IsPressed("Pause"); - } - - if (IsGame3D && Settings.Fix3D) - { - Vdp.ExecFrame((Frame & 1) == 0); - } - else - { - Vdp.ExecFrame(render); - } - - PSG.EndFrame(Cpu.TotalExecutedCycles); - if (_lagged) - { - _lagCount++; - _isLag = true; - } - else - { - _isLag = false; - } - } - - public int Frame => _frame; - - public string SystemId => "SMS"; - - public bool DeterministicEmulation => true; - - public void ResetCounters() - { - _frame = 0; - _lagCount = 0; - _isLag = false; - } - - public CoreComm CoreComm { get; } - - public void Dispose() - { - } - } -} +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Sega.MasterSystem +{ + public sealed partial class SMS : IEmulator + { + public IEmulatorServiceProvider ServiceProvider { get; } + + public ControllerDefinition ControllerDefinition + { + get + { + if (IsGameGear) + { + return GGController; + } + + switch(SyncSettings.ControllerType) + { + case "Paddle": + return SMSPaddleController; + case "Light Phaser": + // scale the vertical to the display mode + SMSLightPhaserController.FloatRanges[1] = new ControllerDefinition.FloatRange(0, Vdp.FrameHeight / 2, Vdp.FrameHeight - 1); + + return SMSLightPhaserController; + case "Sports Pad": + return SMSSportsPadController; + default: + return SmsController; + } + } + } + + public void FrameAdvance(IController controller, bool render, bool rendersound) + { + _controller = controller; + _lagged = true; + _frame++; + PSG.BeginFrame(Cpu.TotalExecutedCycles); + + if (!IsGameGear) + { + PSG.StereoPanning = Settings.ForceStereoSeparation ? ForceStereoByte : (byte)0xFF; + } + + if (Tracer.Enabled) + { + Cpu.TraceCallback = s => Tracer.Put(s); + } + else + { + Cpu.TraceCallback = null; + } + + if (IsGameGear == false) + { + Cpu.NonMaskableInterrupt = controller.IsPressed("Pause"); + } + + if (IsGame3D && Settings.Fix3D) + { + Vdp.ExecFrame((Frame & 1) == 0); + } + else + { + Vdp.ExecFrame(render); + } + + PSG.EndFrame(Cpu.TotalExecutedCycles); + if (_lagged) + { + _lagCount++; + _isLag = true; + } + else + { + _isLag = false; + } + } + + public int Frame => _frame; + + public string SystemId => "SMS"; + + public bool DeterministicEmulation => true; + + public void ResetCounters() + { + _frame = 0; + _lagCount = 0; + _isLag = false; + } + + public CoreComm CoreComm { get; } + + public void Dispose() + { + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs index 90331a7528..d2112e2dab 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs @@ -65,6 +65,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem public bool UseBIOS = true; public string ConsoleRegion = "Export"; public string DisplayType = "NTSC"; + public string ControllerType = "Standard"; public SMSSyncSettings Clone() { @@ -78,7 +79,8 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem x.AllowOverlock != y.AllowOverlock || x.UseBIOS != y.UseBIOS || x.ConsoleRegion != y.ConsoleRegion || - x.DisplayType != y.DisplayType; + x.DisplayType != y.DisplayType || + x.ControllerType != y.ControllerType; } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs index 961daa444b..87564dfe64 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs @@ -1,103 +1,105 @@ -using System.IO; - -using BizHawk.Common; -using BizHawk.Emulation.Common; - - -namespace BizHawk.Emulation.Cores.Sega.MasterSystem -{ - public sealed partial class SMS : IStatable - { - public bool BinarySaveStatesPreferred - { - get { return false; } - } - - public void SaveStateBinary(BinaryWriter bw) - { - SyncState(Serializer.CreateBinaryWriter(bw)); - } - - public void LoadStateBinary(BinaryReader br) - { - SyncState(Serializer.CreateBinaryReader(br)); - } - - public void SaveStateText(TextWriter tw) - { - SyncState(Serializer.CreateTextWriter(tw)); - } - - public void LoadStateText(TextReader tr) - { - SyncState(Serializer.CreateTextReader(tr)); - } - - public byte[] SaveStateBinary() - { - if (_stateBuffer == null) - { - var stream = new MemoryStream(); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - _stateBuffer = stream.ToArray(); - writer.Close(); - return _stateBuffer; - } - else - { - var stream = new MemoryStream(_stateBuffer); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - writer.Close(); - return _stateBuffer; - } - } - - private byte[] _stateBuffer; - - private void SyncState(Serializer ser) - { - ser.BeginSection("SMS"); - Cpu.SyncState(ser); - Vdp.SyncState(ser); - PSG.SyncState(ser); - ser.Sync("RAM", ref SystemRam, false); - ser.Sync("RomBank0", ref RomBank0); - ser.Sync("RomBank1", ref RomBank1); - ser.Sync("RomBank2", ref RomBank2); - ser.Sync("RomBank3", ref RomBank3); - ser.Sync("Port01", ref Port01); - ser.Sync("Port02", ref Port02); - ser.Sync("Port3E", ref Port3E); - ser.Sync("Port3F", ref Port3F); - - if (SaveRAM != null) - { - ser.Sync("SaveRAM", ref SaveRAM, false); - ser.Sync("SaveRamBank", ref SaveRamBank); - } - - if (ExtRam != null) - { - ser.Sync("ExtRAM", ref ExtRam, true); - } - - if (HasYM2413) - { - YM2413.SyncState(ser); - } - - ser.Sync("Frame", ref _frame); - ser.Sync("LagCount", ref _lagCount); - ser.Sync("IsLag", ref _isLag); - - ser.EndSection(); - - if (ser.IsReader) - { - SyncAllByteArrayDomains(); - } - } - } -} +using System.IO; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + + +namespace BizHawk.Emulation.Cores.Sega.MasterSystem +{ + public sealed partial class SMS : IStatable + { + public bool BinarySaveStatesPreferred + { + get { return true; } + } + + public void SaveStateText(TextWriter writer) + { + SyncState(new Serializer(writer)); + } + + public void LoadStateText(TextReader reader) + { + SyncState(new Serializer(reader)); + } + + public void SaveStateBinary(BinaryWriter bw) + { + SyncState(new Serializer(bw)); + } + + public void LoadStateBinary(BinaryReader br) + { + SyncState(new Serializer(br)); + } + + public byte[] SaveStateBinary() + { + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + return ms.ToArray(); + } + + private void SyncState(Serializer ser) + { + byte[] core = null; + if (ser.IsWriter) + { + var ms = new MemoryStream(); + ms.Close(); + core = ms.ToArray(); + } + Cpu.SyncState(ser); + + ser.BeginSection("SMS"); + Vdp.SyncState(ser); + PSG.SyncState(ser); + ser.Sync("RAM", ref SystemRam, false); + ser.Sync("RomBank0", ref RomBank0); + ser.Sync("RomBank1", ref RomBank1); + ser.Sync("RomBank2", ref RomBank2); + ser.Sync("RomBank3", ref RomBank3); + ser.Sync("Port01", ref Port01); + ser.Sync("Port02", ref Port02); + ser.Sync("Port3E", ref Port3E); + ser.Sync("Port3F", ref Port3F); + ser.Sync("Controller1SelectHigh", ref Controller1SelectHigh); + ser.Sync("ControllerSelect2High", ref Controller2SelectHigh); + ser.Sync("LatchLightPhaser", ref LatchLightPhaser); + + if (SaveRAM != null) + { + ser.Sync("SaveRAM", ref SaveRAM, false); + ser.Sync("SaveRamBank", ref SaveRamBank); + } + + if (ExtRam != null) + { + ser.Sync("ExtRAM", ref ExtRam, true); + } + + if (HasYM2413) + { + YM2413.SyncState(ser); + } + + if (EEPROM != null) + { + EEPROM.SyncState(ser); + } + + ser.Sync("Frame", ref _frame); + ser.Sync("LagCount", ref _lagCount); + ser.Sync("IsLag", ref _isLag); + + ser.EndSection(); + + if (ser.IsReader) + { + SyncAllByteArrayDomains(); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs index 06fa88e9ea..c76dab5789 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs @@ -1,19 +1,21 @@ -using BizHawk.Emulation.Common; +using System; + +using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.Sega.MasterSystem { public partial class SMS { public static readonly ControllerDefinition SmsController = new ControllerDefinition - { - Name = "SMS Controller", - BoolButtons = + { + Name = "SMS Controller", + BoolButtons = { "Reset", "Pause", "P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 B1", "P1 B2", "P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 B1", "P2 B2" } - }; + }; public static readonly ControllerDefinition GGController = new ControllerDefinition { @@ -25,21 +27,316 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } }; + public static readonly ControllerDefinition SMSPaddleController = new ControllerDefinition + { + Name = "SMS Paddle Controller", + BoolButtons = + { + "Reset", "Pause", + "P1 Left", "P1 Right", "P1 B1", + "P2 Left", "P2 Right", "P2 B1", + }, + FloatControls = + { + "P1 Paddle", + "P2 Paddle" + }, + FloatRanges = + { + new ControllerDefinition.FloatRange(0, 128, 255), + new ControllerDefinition.FloatRange(0, 128, 255) + } + }; + + public static readonly ControllerDefinition SMSLightPhaserController = new ControllerDefinition + { + Name = "SMS Light Phaser Controller", + BoolButtons = + { + "Reset", "Pause", + "P1 Trigger", + }, + FloatControls = + { + "P1 X", "P1 Y", + }, + FloatRanges = + { + new ControllerDefinition.FloatRange(0, 64, 127), + new ControllerDefinition.FloatRange(0, 500, 1000) + } + }; + + public static readonly ControllerDefinition SMSSportsPadController = new ControllerDefinition + { + Name = "SMS Sports Pad Controller", + BoolButtons = + { + "Reset", "Pause", + "P1 Left", "P1 Right", "P1 Up", "P1 Down", "P1 B1", "P1 B2", + "P2 Left", "P2 Right", "P2 Up", "P2 Down", "P2 B1", "P2 B2" + }, + FloatControls = + { + "P1 X", "P1 Y", + "P2 X", "P2 Y" + }, + FloatRanges = + { + new ControllerDefinition.FloatRange(-64, 0, 63), + new ControllerDefinition.FloatRange(-64, 0, 63), + new ControllerDefinition.FloatRange(-64, 0, 63), + new ControllerDefinition.FloatRange(-64, 0, 63) + } + }; + + const int PaddleMin = 0; + const int PaddleMax = 255; + const int SportsPadMin = -64; + const int SportsPadMax = 63; + + // The paddles and sports pads have data select states + bool Controller1SelectHigh = true; + bool Controller2SelectHigh = true; + + bool LatchLightPhaser = false; + + // further state value for sports pad, may be useful for other controllers in future + int Controller1State = 3; + int Controller2State = 3; + int ControllerTick = 0; // for timing in japan + private byte ReadControls1() { InputCallbacks.Call(); _lagged = false; byte value = 0xFF; - if (_controller.IsPressed("P1 Up")) value &= 0xFE; - if (_controller.IsPressed("P1 Down")) value &= 0xFD; - if (_controller.IsPressed("P1 Left")) value &= 0xFB; - if (_controller.IsPressed("P1 Right")) value &= 0xF7; - if (_controller.IsPressed("P1 B1")) value &= 0xEF; - if (_controller.IsPressed("P1 B2")) value &= 0xDF; + switch (SyncSettings.ControllerType) + { + case "Paddle": + { + // use analog values from a controller, see http://www.smspower.org/Development/Paddle - if (_controller.IsPressed("P2 Up")) value &= 0xBF; - if (_controller.IsPressed("P2 Down")) value &= 0x7F; + int paddle1Pos; + if (_controller.IsPressed("P1 Left")) + paddle1Pos = PaddleMin; + else if (_controller.IsPressed("P1 Right")) + paddle1Pos = PaddleMax; + else + paddle1Pos = (int)_controller.GetFloat("P1 Paddle"); + + int paddle2Pos; + if (_controller.IsPressed("P2 Left")) + paddle2Pos = PaddleMin; + else if (_controller.IsPressed("P2 Right")) + paddle2Pos = PaddleMax; + else + paddle2Pos = (int)_controller.GetFloat("P2 Paddle"); + + PresetControllerState(1); + // Hard-wired together? + Controller2SelectHigh = Controller1SelectHigh; + + if (Controller1SelectHigh) + { + if ((paddle1Pos & 0x10) == 0) value &= 0xFE; + if ((paddle1Pos & 0x20) == 0) value &= 0xFD; + if ((paddle1Pos & 0x40) == 0) value &= 0xFB; + if ((paddle1Pos & 0x80) == 0) value &= 0xF7; + } + else + { + if ((paddle1Pos & 0x01) == 0) value &= 0xFE; + if ((paddle1Pos & 0x02) == 0) value &= 0xFD; + if ((paddle1Pos & 0x04) == 0) value &= 0xFB; + if ((paddle1Pos & 0x08) == 0) value &= 0xF7; + } + + if (_controller.IsPressed("P1 B1")) value &= 0xEF; + if (!Controller1SelectHigh) value &= 0xDF; + + if (Controller2SelectHigh) + { + if ((paddle2Pos & 0x10) == 0) value &= 0xBF; + if ((paddle2Pos & 0x20) == 0) value &= 0x7F; + } + else + { + if ((paddle2Pos & 0x01) == 0) value &= 0xBF; + if ((paddle2Pos & 0x02) == 0) value &= 0x7F; + } + + PostsetControllerState(1); + } + break; + + case "Light Phaser": + if (_controller.IsPressed("P1 Trigger")) value &= 0xEF; + break; + + case "Sports Pad": + { + int p1X; + if (_controller.IsPressed("P1 Left")) + p1X = SportsPadMin; + else if (_controller.IsPressed("P1 Right")) + p1X = SportsPadMax; + else + p1X = (int)_controller.GetFloat("P1 X"); + + int p1Y; + if (_controller.IsPressed("P1 Up")) + p1Y = SportsPadMin; + else if (_controller.IsPressed("P1 Down")) + p1Y = SportsPadMax; + else + p1Y = (int)_controller.GetFloat("P1 Y"); + + int p2X; + if (_controller.IsPressed("P2 Left")) + p2X = SportsPadMin; + else if (_controller.IsPressed("P2 Right")) + p2X = SportsPadMax; + else + p2X = (int)_controller.GetFloat("P2 X"); + + int p2Y; + if (_controller.IsPressed("P2 Up")) + p2Y = SportsPadMin; + else if (_controller.IsPressed("P2 Down")) + p2Y = SportsPadMax; + else + p2Y = (int)_controller.GetFloat("P2 Y"); + + if(_region == "Japan") + { + p1X += 128; + p1Y += 128; + p2X += 128; + p2Y += 128; + } else + { + p1X *= -1; + p1Y *= -1; + p2X *= -1; + p2Y *= -1; + } + + PresetControllerState(1); + + // advance state + if (Controller1SelectHigh && (Controller1State % 2 == 0)) + { + ++Controller1State; + } + else if (!Controller1SelectHigh && (Controller1State % 2 == 1)) + { + if (++Controller1State == (_region == "Japan" ? 6 : 4)) + Controller1State = 0; + } + if (Controller2SelectHigh && (Controller2State % 2 == 0)) + { + ++Controller2State; + } + else if (!Controller2SelectHigh && (Controller2State % 2 == 1)) + { + if (++Controller2State == (_region == "Japan" ? 6 : 4)) + Controller2State = 0; + } + + switch (Controller1State) + { + case 0: + if ((p1X & 0x10) == 0) value &= 0xFE; + if ((p1X & 0x20) == 0) value &= 0xFD; + if ((p1X & 0x40) == 0) value &= 0xFB; + if ((p1X & 0x80) == 0) value &= 0xF7; + break; + case 1: + if ((p1X & 0x01) == 0) value &= 0xFE; + if ((p1X & 0x02) == 0) value &= 0xFD; + if ((p1X & 0x04) == 0) value &= 0xFB; + if ((p1X & 0x08) == 0) value &= 0xF7; + break; + case 2: + if ((p1Y & 0x10) == 0) value &= 0xFE; + if ((p1Y & 0x20) == 0) value &= 0xFD; + if ((p1Y & 0x40) == 0) value &= 0xFB; + if ((p1Y & 0x80) == 0) value &= 0xF7; + break; + case 3: + if ((p1Y & 0x01) == 0) value &= 0xFE; + if ((p1Y & 0x02) == 0) value &= 0xFD; + if ((p1Y & 0x04) == 0) value &= 0xFB; + if ((p1Y & 0x08) == 0) value &= 0xF7; + break; + case 4: + // specific to Japan: sync via TR + value &= 0xDF; + break; + case 5: + // specific to Japan: buttons + if (_controller.IsPressed("P1 B1")) value &= 0xFE; + if (_controller.IsPressed("P1 B2")) value &= 0xFD; + break; + } + + if (_region != "Japan") + { + // Buttons like normal in Export + if (_controller.IsPressed("P1 B1")) value &= 0xEF; + if (_controller.IsPressed("P1 B2")) value &= 0xDF; + } + else + { + // In Japan, it contains selectHigh + if (!Controller1SelectHigh) value &= 0xEF; + } + + switch (Controller2State) + { + case 0: + if ((p2X & 0x10) == 0) value &= 0xBF; + if ((p2X & 0x20) == 0) value &= 0x7F; + break; + case 1: + if ((p2X & 0x01) == 0) value &= 0xBF; + if ((p2X & 0x02) == 0) value &= 0x7F; + break; + case 2: + if ((p2Y & 0x10) == 0) value &= 0xBF; + if ((p2Y & 0x20) == 0) value &= 0x7F; + break; + case 3: + if ((p2Y & 0x01) == 0) value &= 0xBF; + if ((p2Y & 0x02) == 0) value &= 0x7F; + break; + case 5: + // specific to Japan: buttons + if (_controller.IsPressed("P2 B1")) value &= 0xBF; + if (_controller.IsPressed("P2 B2")) value &= 0x7F; + break; + } + + PostsetControllerState(1); + } + break; + + default: + // Normal controller + + if (_controller.IsPressed("P1 Up")) value &= 0xFE; + if (_controller.IsPressed("P1 Down")) value &= 0xFD; + if (_controller.IsPressed("P1 Left")) value &= 0xFB; + if (_controller.IsPressed("P1 Right")) value &= 0xF7; + if (_controller.IsPressed("P1 B1")) value &= 0xEF; + if (_controller.IsPressed("P1 B2")) value &= 0xDF; + + if (_controller.IsPressed("P2 Up")) value &= 0xBF; + if (_controller.IsPressed("P2 Down")) value &= 0x7F; + break; + } return value; } @@ -50,10 +347,132 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem _lagged = false; byte value = 0xFF; - if (_controller.IsPressed("P2 Left")) value &= 0xFE; - if (_controller.IsPressed("P2 Right")) value &= 0xFD; - if (_controller.IsPressed("P2 B1")) value &= 0xFB; - if (_controller.IsPressed("P2 B2")) value &= 0xF7; + switch (SyncSettings.ControllerType) + { + case "Paddle": + { + // use analog values from a controller, see http://www.smspower.org/Development/Paddle + + int paddle2Pos; + if (_controller.IsPressed("P2 Left")) + paddle2Pos = PaddleMin; + else if (_controller.IsPressed("P2 Right")) + paddle2Pos = PaddleMax; + else + paddle2Pos = (int)_controller.GetFloat("P2 Paddle"); + + PresetControllerState(2); + + if (Controller2SelectHigh) + { + if ((paddle2Pos & 0x40) == 0) value &= 0xFE; + if ((paddle2Pos & 0x80) == 0) value &= 0xFD; + } + else + { + if ((paddle2Pos & 0x04) == 0) value &= 0xFE; + if ((paddle2Pos & 0x08) == 0) value &= 0xFD; + } + + if (_controller.IsPressed("P2 B1")) value &= 0xFB; + if (!Controller2SelectHigh) value &= 0xF7; + + PostsetControllerState(2); + } + break; + + case "Light Phaser": + if (LatchLightPhaser) + { + value &= 0xBF; + LatchLightPhaser = false; + } + break; + + case "Sports Pad": + { + int p2X; + if (_controller.IsPressed("P2 Left")) + p2X = SportsPadMin; + else if (_controller.IsPressed("P2 Right")) + p2X = SportsPadMax; + else + p2X = (int)_controller.GetFloat("P2 X"); + + int p2Y; + if (_controller.IsPressed("P2 Down")) + p2Y = SportsPadMin; + else if (_controller.IsPressed("P2 Up")) + p2Y = SportsPadMax; + else + p2Y = (int)_controller.GetFloat("P2 Y"); + + if (_region == "Japan") + { + p2X += 128; + p2Y += 128; + } + else + { + p2X *= -1; + p2Y *= -1; + } + + PresetControllerState(2); + + if (Controller2SelectHigh && (Controller2State % 2 == 0)) + { + ++Controller2State; + } + else if (!Controller2SelectHigh && (Controller2State % 2 == 1)) + { + if (++Controller2State == (_region == "Japan" ? 6 : 4)) + Controller2State = 0; + } + + switch (Controller2State) + { + case 0: + if ((p2X & 0x40) == 0) value &= 0xFE; + if ((p2X & 0x80) == 0) value &= 0xFD; + break; + case 1: + if ((p2X & 0x04) == 0) value &= 0xFE; + if ((p2X & 0x08) == 0) value &= 0xFD; + break; + case 2: + if ((p2Y & 0x40) == 0) value &= 0xFE; + if ((p2Y & 0x80) == 0) value &= 0xFD; + break; + case 3: + if ((p2Y & 0x04) == 0) value &= 0xFE; + if ((p2Y & 0x08) == 0) value &= 0xFD; + break; + } + if (_region != "Japan") + { + // Buttons like normal in Export + if (_controller.IsPressed("P2 B1")) value &= 0xFB; + if (_controller.IsPressed("P2 B2")) value &= 0xF7; + } + else + { + if (!Controller2SelectHigh) value &= 0xF7; + } + + PostsetControllerState(2); + } + break; + + default: + // Normal controller + + if (_controller.IsPressed("P2 Left")) value &= 0xFE; + if (_controller.IsPressed("P2 Right")) value &= 0xFD; + if (_controller.IsPressed("P2 B1")) value &= 0xFB; + if (_controller.IsPressed("P2 B2")) value &= 0xF7; + break; + } if (_controller.IsPressed("Reset")) value &= 0xEF; @@ -75,6 +494,33 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem return value; } + internal void ProcessLineControls() + { + const int phaserRadius = 4; + + // specifically lightgun needs to do things on a per-line basis + if (SyncSettings.ControllerType == "Light Phaser") + { + byte phaserX = (byte)(_controller.GetFloat("P1 X") + 20); + int phaserY = (int)_controller.GetFloat("P1 Y"); + int scanline = Vdp.ScanLine; + + if (!LatchLightPhaser && phaserY >= scanline - phaserRadius && phaserY <= scanline + phaserRadius) + { + if (scanline >= Vdp.FrameHeight) + return; + + // latch HCounter via TH + Vdp.HCounter = phaserX; + LatchLightPhaser = true; + } + else + { + LatchLightPhaser = false; + } + } + } + byte ReadPort0() { if (IsGameGear == false) @@ -96,5 +542,49 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem return value; } + + private void PresetControllerState(int pin) + { + // The 3F port's TH slot is also used on games in some games in Export BIOS to clock the paddle state + // Re: the paddle: Yes it's silly considering the paddle was never released outside Japan but the games think otherwise + + if (_region != "Japan") + { + if ((Port3F & 0x02) == 0x00) + { + Controller1SelectHigh = (Port3F & 0x20) != 0; + + // resync + Controller2State = 3; + } + + if ((Port3F & 0x08) == 0x00) + { + Controller2SelectHigh = (Port3F & 0x80) != 0; + + // resync + Controller1State = 3; + } + } + } + + private void PostsetControllerState(int pin) + { + // for the benefit of the Japan region + if (_region == "Japan" && (++ControllerTick) == 2) + { + ControllerTick = 0; + + if (pin == 1) + { + Controller1SelectHigh ^= true; + } + else + { + Controller1SelectHigh = false; + Controller2SelectHigh ^= true; + } + } + } } } \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs index 974c0f73b3..b2ee955288 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs @@ -4,13 +4,12 @@ using BizHawk.Common.StringExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.Components; using BizHawk.Emulation.Cores.Components; -using BizHawk.Emulation.Cores.Components.Z80; +using BizHawk.Emulation.Cores.Components.Z80A; /***************************************************** TODO: - + HCounter + + HCounter (Manually set for light phaser emulation... should be only case it's polled) + Try to clean up the organization of the source code. - + Lightgun/Paddle/etc if I get really bored + Mode 1 not implemented in VDP TMS modes. (I dont have a test case in SG1000 or Coleco) **********************************************************/ @@ -33,7 +32,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem Settings = (SMSSettings)settings ?? new SMSSettings(); SyncSettings = (SMSSyncSettings)syncSettings ?? new SMSSyncSettings(); CoreComm = comm; - MemoryCallbacks = new MemoryCallbackSystem(); + MemoryCallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); IsGameGear = game.System == "GG"; IsSG1000 = game.System == "SG"; @@ -75,11 +74,13 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem HasYM2413 = true; } - Cpu = new Z80A + Cpu = new Z80A() { - RegisterSP = 0xDFF0, ReadHardware = ReadPort, WriteHardware = WritePort, + FetchMemory = ReadMemory, + ReadMemory = ReadMemory, + WriteMemory = WriteMemory, MemoryCallbacks = MemoryCallbacks }; @@ -113,6 +114,8 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem InitNemesisMapper(); else if (game["TerebiOekaki"]) InitTerebiOekaki(); + else if (game["EEPROM"]) + InitEEPROMMapper(); else InitSegaMapper(); @@ -160,7 +163,10 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } if (game["SRAM"]) + { SaveRAM = new byte[int.Parse(game.OptionValue("SRAM"))]; + Console.WriteLine(SaveRAM.Length); + } else if (game.NotInDatabase) SaveRAM = new byte[0x8000]; @@ -175,8 +181,11 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem var serviceProvider = ServiceProvider as BasicServiceProvider; serviceProvider.Register(Tracer); - serviceProvider.Register(new Disassembler()); + serviceProvider.Register(Cpu); Vdp.ProcessOverscan(); + + Cpu.ReadMemory = ReadMemory; + Cpu.WriteMemory = WriteMemory; } // Constants @@ -253,7 +262,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem /// /// A dummy FetchMemory that simply reads the memory /// - private byte FetchMemory_StubThunk(ushort address, bool first) + private byte FetchMemory_StubThunk(ushort address) { return ReadMemory(address); } @@ -281,7 +290,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem if ((port & 1) == 0) return Vdp.ReadVLineCounter(); else - return 0x50; // TODO Vdp.ReadHLineCounter(); + return Vdp.ReadHLineCounter(); } if (port < 0xC0) // VDP data/control ports { @@ -346,4 +355,4 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem private readonly string[] validRegions = { "Export", "Japan", "Auto" }; } -} \ No newline at end of file +} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/VDP.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/VDP.cs index 75d6d33625..adccda7fd3 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/VDP.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/VDP.cs @@ -4,7 +4,7 @@ using System.IO; using BizHawk.Common; using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Components.Z80; +using BizHawk.Emulation.Cores.Components.Z80A; namespace BizHawk.Emulation.Cores.Sega.MasterSystem @@ -47,6 +47,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem public int FrameHeight = 192; public int ScanLine; + public byte HCounter = 0x90; public int[] FrameBuffer = new int[256 * 192]; public int[] GameGearFrameBuffer = new int[160 * 144]; public int[] OverscanFrameBuffer = null; @@ -112,7 +113,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem StatusByte &= 0x1F; HIntPending = false; VIntPending = false; - Cpu.Interrupt = false; + Cpu.FlagI = false; return returnValue; } @@ -136,6 +137,11 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } } + public byte ReadHLineCounter() + { + return HCounter; + } + public void WriteVdpControl(byte value) { if (VdpWaitingForLatchByte) @@ -285,13 +291,13 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem { case 0: // Mode Control Register 1 CheckVideoMode(); - Cpu.Interrupt = (EnableLineInterrupts && HIntPending); - Cpu.Interrupt |= (EnableFrameInterrupts && VIntPending); + Cpu.FlagI = (EnableLineInterrupts && HIntPending); + Cpu.FlagI |= (EnableFrameInterrupts && VIntPending); break; case 1: // Mode Control Register 2 CheckVideoMode(); - Cpu.Interrupt = (EnableFrameInterrupts && VIntPending); - Cpu.Interrupt |= (EnableLineInterrupts && HIntPending); + Cpu.FlagI = (EnableFrameInterrupts && VIntPending); + Cpu.FlagI |= (EnableLineInterrupts && HIntPending); break; case 2: // Name Table Base Address NameTableBase = CalcNameTableBase(); @@ -341,7 +347,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem if (VIntPending && EnableFrameInterrupts) { - Cpu.Interrupt = true; + Cpu.FlagI = true; } } @@ -355,7 +361,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem HIntPending = true; if (EnableLineInterrupts) {; - Cpu.Interrupt = true; + Cpu.FlagI = true; } lineIntLinesRemaining = Registers[0x0A]; } @@ -375,8 +381,16 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem ProcessFrameInterrupt(); ProcessLineInterrupt(); + Sms.ProcessLineControls(); - Cpu.ExecuteCycles(IPeriod); + //Console.Write(Cpu.cur_instr.Length); + //Console.Write(" "); + //Console.WriteLine(Cpu.instr_pntr); + for (int j = 0; j < IPeriod; j++) + { + Cpu.ExecuteOne(); + } + if (ScanLine == scanlinesPerFrame - 1) { @@ -428,6 +442,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem ser.Sync("Registers", ref Registers, false); ser.Sync("CRAM", ref CRAM, false); ser.Sync("VRAM", ref VRAM, false); + ser.Sync("HCounter", ref HCounter); ser.EndSection(); if (ser.IsReader) diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IDebuggable.cs index 73dab4deaa..b619d2c85c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IDebuggable.cs @@ -52,7 +52,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx get { throw new NotImplementedException(); } } - private readonly MemoryCallbackSystem _memoryCallbacks = new MemoryCallbackSystem(); + private readonly MemoryCallbackSystem _memoryCallbacks = new MemoryCallbackSystem(new[] { "M68K BUS" }); private LibGPGX.mem_cb ExecCallback; private LibGPGX.mem_cb ReadCallback; @@ -61,9 +61,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx private void InitMemCallbacks() { - ExecCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallExecutes(a)); - ReadCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallReads(a)); - WriteCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallWrites(a)); + ExecCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallExecutes(a, "M68K BUS")); + ReadCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallReads(a, "M68K BUS")); + WriteCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallWrites(a, "M68K BUS")); _memoryCallbacks.ActiveChanged += RefreshMemCallbacks; } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISettable.cs index c44199e244..261a4418a3 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISettable.cs @@ -1,210 +1,325 @@ -using System.ComponentModel; - -using BizHawk.Common; -using BizHawk.Emulation.Common; -using Newtonsoft.Json; - - -namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx -{ - public partial class GPGX : ISettable - { - public GPGXSettings GetSettings() - { - return _settings.Clone(); - } - - public GPGXSyncSettings GetSyncSettings() - { - return _syncSettings.Clone(); - } - - public bool PutSettings(GPGXSettings o) - { - bool ret = GPGXSettings.NeedsReboot(_settings, o); - _settings = o; - Core.gpgx_set_draw_mask(_settings.GetDrawMask()); - return ret; - } - - public bool PutSyncSettings(GPGXSyncSettings o) - { - bool ret = GPGXSyncSettings.NeedsReboot(_syncSettings, o); - _syncSettings = o; - return ret; - } - - private GPGXSyncSettings _syncSettings; - private GPGXSettings _settings; - - public class GPGXSettings - { - [DeepEqualsIgnore] - [JsonIgnore] - private bool _DrawBGA; - - [DisplayName("Background Layer A")] - [Description("True to draw BG layer A")] - [DefaultValue(true)] - public bool DrawBGA { get { return _DrawBGA; } set { _DrawBGA = value; } } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _DrawBGB; - - [DisplayName("Background Layer B")] - [Description("True to draw BG layer B")] - [DefaultValue(true)] - public bool DrawBGB { get { return _DrawBGB; } set { _DrawBGB = value; } } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _DrawBGW; - - [DisplayName("Background Layer W")] - [Description("True to draw BG layer W")] - [DefaultValue(true)] - public bool DrawBGW { get { return _DrawBGW; } set { _DrawBGW = value; } } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _DrawObj; - - [DisplayName("Sprite Layer")] - [Description("True to draw sprite layer")] - [DefaultValue(true)] - public bool DrawObj { get { return _DrawObj; } set { _DrawObj = value; } } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _PadScreen320; - - [DisplayName("Pad screen to 320")] - [Description("When using 1:1 aspect ratio, enable to make screen width constant (320) between game modes")] - [DefaultValue(false)] - public bool PadScreen320 { get { return _PadScreen320; } set { _PadScreen320 = value; } } - - [DisplayName("Audio Filter")] - [DefaultValue(LibGPGX.InitSettings.FilterType.LowPass)] - public LibGPGX.InitSettings.FilterType Filter { get; set; } - - [DisplayName("Low Pass Range")] - [Description("Only active when filter type is lowpass")] - [DefaultValue((ushort)39321)] - public ushort LowPassRange { get; set; } - - [DisplayName("Three band low cutoff")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)880)] - public short LowFreq { get; set; } - - [DisplayName("Three band high cutoff")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)5000)] - public short HighFreq { get; set; } - - [DisplayName("Three band low gain")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)1)] - public short LowGain { get; set; } - - [DisplayName("Three band mid gain")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)1)] - public short MidGain { get; set; } - - [DisplayName("Three band high gain")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)1)] - public short HighGain { get; set; } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _Backdrop; - - [DisplayName("Use custom backdrop color")] - [Description("Filler when layers are off")] - [DefaultValue((bool)false)] - public bool Backdrop { get { return _Backdrop; } set { _Backdrop = value; } } - - [DisplayName("Custom backdrop color")] - [Description("Magic pink (0xffff00ff) by default")] - [DefaultValue((uint)0xffff00ff)] - public uint BackdropColor { get; set; } - - public GPGXSettings() - { - SettingsUtil.SetDefaultValues(this); - } - - public GPGXSettings Clone() - { - return (GPGXSettings)MemberwiseClone(); - } - - public LibGPGX.DrawMask GetDrawMask() - { - LibGPGX.DrawMask ret = 0; - if (DrawBGA) ret |= LibGPGX.DrawMask.BGA; - if (DrawBGB) ret |= LibGPGX.DrawMask.BGB; - if (DrawBGW) ret |= LibGPGX.DrawMask.BGW; - if (DrawObj) ret |= LibGPGX.DrawMask.Obj; - if (Backdrop) ret |= LibGPGX.DrawMask.Backdrop; - return ret; - } - - public static bool NeedsReboot(GPGXSettings x, GPGXSettings y) - { - return !DeepEquality.DeepEquals(x, y); - } - - public LibGPGX.InitSettings GetNativeSettings() - { - return new LibGPGX.InitSettings - { - Filter = Filter, - LowPassRange = LowPassRange, - LowFreq = LowFreq, - HighFreq = HighFreq, - LowGain = LowGain, - MidGain = MidGain, - HighGain = HighGain, - BackdropColor = BackdropColor - }; - } - } - - public class GPGXSyncSettings - { - [DisplayName("Use Six Button Controllers")] - [Description("Controls the type of any attached normal controllers; six button controllers are used if true, otherwise three button controllers. Some games don't work correctly with six button controllers. Not relevant if other controller types are connected.")] - [DefaultValue(true)] - public bool UseSixButton { get; set; } - - [DisplayName("Control Type")] - [Description("Sets the type of controls that are plugged into the console. Some games will automatically load with a different control type.")] - [DefaultValue(ControlType.Normal)] - public ControlType ControlType { get; set; } - - [DisplayName("Autodetect Region")] - [Description("Sets the region of the emulated console. Many games can run on multiple regions and will behave differently on different ones. Some games may require a particular region.")] - [DefaultValue(LibGPGX.Region.Autodetect)] - public LibGPGX.Region Region { get; set; } - - public GPGXSyncSettings() - { - SettingsUtil.SetDefaultValues(this); - } - - public GPGXSyncSettings Clone() - { - return (GPGXSyncSettings)MemberwiseClone(); - } - - public static bool NeedsReboot(GPGXSyncSettings x, GPGXSyncSettings y) - { - return !DeepEquality.DeepEquals(x, y); - } - } - } -} +using System; +using System.ComponentModel; +using System.Globalization; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using Newtonsoft.Json; + + +namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx +{ + public partial class GPGX : ISettable + { + public GPGXSettings GetSettings() + { + return _settings.Clone(); + } + + public GPGXSyncSettings GetSyncSettings() + { + return _syncSettings.Clone(); + } + + public bool PutSettings(GPGXSettings o) + { + bool ret = GPGXSettings.NeedsReboot(_settings, o); + _settings = o; + Core.gpgx_set_draw_mask(_settings.GetDrawMask()); + return ret; + } + + public bool PutSyncSettings(GPGXSyncSettings o) + { + bool ret = GPGXSyncSettings.NeedsReboot(_syncSettings, o); + _syncSettings = o; + return ret; + } + + private class UintToHexConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + else + { + return base.CanConvertFrom(context, sourceType); + } + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + { + return true; + } + else + { + return base.CanConvertTo(context, destinationType); + } + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string) && value.GetType() == typeof(uint)) + { + return string.Format("0x{0:x8}", value); + } + else + { + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value.GetType() == typeof(string)) + { + string input = (string)value; + if (input.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + { + input = input.Substring(2); + } + return uint.Parse(input, NumberStyles.HexNumber, culture); + } + else + { + return base.ConvertFrom(context, culture, value); + } + } + } + + private class UshortToHexConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + else + { + return base.CanConvertFrom(context, sourceType); + } + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + { + return true; + } + else + { + return base.CanConvertTo(context, destinationType); + } + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string) && value.GetType() == typeof(ushort)) + { + return string.Format("0x{0:x4}", value); + } + else + { + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value.GetType() == typeof(string)) + { + string input = (string)value; + if (input.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + { + input = input.Substring(2); + } + return ushort.Parse(input, NumberStyles.HexNumber, culture); + } + else + { + return base.ConvertFrom(context, culture, value); + } + } + } + + private GPGXSyncSettings _syncSettings; + private GPGXSettings _settings; + + public class GPGXSettings + { + [DeepEqualsIgnore] + [JsonIgnore] + private bool _DrawBGA; + + [DisplayName("Background Layer A")] + [Description("True to draw BG layer A")] + [DefaultValue(true)] + public bool DrawBGA { get { return _DrawBGA; } set { _DrawBGA = value; } } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _DrawBGB; + + [DisplayName("Background Layer B")] + [Description("True to draw BG layer B")] + [DefaultValue(true)] + public bool DrawBGB { get { return _DrawBGB; } set { _DrawBGB = value; } } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _DrawBGW; + + [DisplayName("Background Layer W")] + [Description("True to draw BG layer W")] + [DefaultValue(true)] + public bool DrawBGW { get { return _DrawBGW; } set { _DrawBGW = value; } } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _DrawObj; + + [DisplayName("Sprite Layer")] + [Description("True to draw sprite layer")] + [DefaultValue(true)] + public bool DrawObj { get { return _DrawObj; } set { _DrawObj = value; } } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _PadScreen320; + + [DisplayName("Pad screen to 320")] + [Description("When using 1:1 aspect ratio, enable to make screen width constant (320) between game modes")] + [DefaultValue(false)] + public bool PadScreen320 { get { return _PadScreen320; } set { _PadScreen320 = value; } } + + [DisplayName("Audio Filter")] + [DefaultValue(LibGPGX.InitSettings.FilterType.LowPass)] + public LibGPGX.InitSettings.FilterType Filter { get; set; } + + [DisplayName("Low Pass Range")] + [Description("Only active when filter type is lowpass. Range is 0 - 0xffff. Default value is 40%")] + [TypeConverter(typeof(UshortToHexConverter))] + [DefaultValue((ushort)0x6666)] + public ushort LowPassRange { get; set; } + + [DisplayName("Three band low cutoff")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)880)] + public short LowFreq { get; set; } + + [DisplayName("Three band high cutoff")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)5000)] + public short HighFreq { get; set; } + + [DisplayName("Three band low gain")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)1)] + public short LowGain { get; set; } + + [DisplayName("Three band mid gain")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)1)] + public short MidGain { get; set; } + + [DisplayName("Three band high gain")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)1)] + public short HighGain { get; set; } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _Backdrop; + + [DisplayName("Use custom backdrop color")] + [Description("Filler when layers are off")] + [DefaultValue((bool)false)] + public bool Backdrop { get { return _Backdrop; } set { _Backdrop = value; } } + + [Description("Magic pink by default. Requires core reboot")] + [TypeConverter(typeof(UintToHexConverter))] + [DefaultValue((uint)0xffff00ff)] + public uint BackdropColor { get; set; } + + public GPGXSettings() + { + SettingsUtil.SetDefaultValues(this); + } + + public GPGXSettings Clone() + { + return (GPGXSettings)MemberwiseClone(); + } + + public LibGPGX.DrawMask GetDrawMask() + { + LibGPGX.DrawMask ret = 0; + if (DrawBGA) ret |= LibGPGX.DrawMask.BGA; + if (DrawBGB) ret |= LibGPGX.DrawMask.BGB; + if (DrawBGW) ret |= LibGPGX.DrawMask.BGW; + if (DrawObj) ret |= LibGPGX.DrawMask.Obj; + if (Backdrop) ret |= LibGPGX.DrawMask.Backdrop; + return ret; + } + + public static bool NeedsReboot(GPGXSettings x, GPGXSettings y) + { + return !DeepEquality.DeepEquals(x, y); + } + + public LibGPGX.InitSettings GetNativeSettings() + { + return new LibGPGX.InitSettings + { + Filter = Filter, + LowPassRange = LowPassRange, + LowFreq = LowFreq, + HighFreq = HighFreq, + LowGain = LowGain, + MidGain = MidGain, + HighGain = HighGain, + BackdropColor = BackdropColor + }; + } + } + + public class GPGXSyncSettings + { + [DisplayName("Use Six Button Controllers")] + [Description("Controls the type of any attached normal controllers; six button controllers are used if true, otherwise three button controllers. Some games don't work correctly with six button controllers. Not relevant if other controller types are connected.")] + [DefaultValue(true)] + public bool UseSixButton { get; set; } + + [DisplayName("Control Type")] + [Description("Sets the type of controls that are plugged into the console. Some games will automatically load with a different control type.")] + [DefaultValue(ControlType.Normal)] + public ControlType ControlType { get; set; } + + [DisplayName("Autodetect Region")] + [Description("Sets the region of the emulated console. Many games can run on multiple regions and will behave differently on different ones. Some games may require a particular region.")] + [DefaultValue(LibGPGX.Region.Autodetect)] + public LibGPGX.Region Region { get; set; } + + public GPGXSyncSettings() + { + SettingsUtil.SetDefaultValues(this); + } + + public GPGXSyncSettings Clone() + { + return (GPGXSyncSettings)MemberwiseClone(); + } + + public static bool NeedsReboot(GPGXSyncSettings x, GPGXSyncSettings y) + { + return !DeepEquality.DeepEquals(x, y); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.IDebuggable.cs index ccff867f43..47cc4221e9 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.IDebuggable.cs @@ -80,7 +80,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX OctoshockDll.shock_SetRegister_CPU(psx, index, (uint)value); } - private readonly MemoryCallbackSystem _memoryCallbacks = new MemoryCallbackSystem(); + private readonly MemoryCallbackSystem _memoryCallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); // Note: there is no system bus memory domain, but there's also no hard rule that the memory callback system domains have to correspond to actual domains in MemoryDomains, that could be good, or bad, but something to be careful about public IMemoryCallbackSystem MemoryCallbacks { get { return _memoryCallbacks; } } public bool CanStep(StepType type) { return false; } diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs index e1e42df4bf..807558d6b3 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs @@ -881,13 +881,13 @@ namespace BizHawk.Emulation.Cores.Sony.PSX switch (type) { case OctoshockDll.eShockMemCb.Read: - MemoryCallbacks.CallReads(address); + MemoryCallbacks.CallReads(address, "System Bus"); break; case OctoshockDll.eShockMemCb.Write: - MemoryCallbacks.CallWrites(address); + MemoryCallbacks.CallWrites(address, "System Bus"); break; case OctoshockDll.eShockMemCb.Execute: - MemoryCallbacks.CallExecutes(address); + MemoryCallbacks.CallExecutes(address, "System Bus"); break; } } diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs index 615dcb75b7..e1defde253 100644 --- a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs +++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs @@ -104,7 +104,7 @@ namespace BizHawk.Emulation.Cores.WonderSwan private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem(); public IInputCallbackSystem InputCallbacks { get { return _inputCallbacks; } } - private readonly MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(); + private readonly MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); // This isn't an actual memory domain in this core (yet), but there's nothing that enforces that it has to be public IMemoryCallbackSystem MemoryCallbacks { get { return _memorycallbacks; } } public IDictionary GetCpuFlagsAndRegisters() @@ -140,15 +140,15 @@ namespace BizHawk.Emulation.Cores.WonderSwan void ReadCallback(uint addr) { - MemoryCallbacks.CallReads(addr); + MemoryCallbacks.CallReads(addr, "System Bus"); } void WriteCallback(uint addr) { - MemoryCallbacks.CallWrites(addr); + MemoryCallbacks.CallWrites(addr, "System Bus"); } void ExecCallback(uint addr) { - MemoryCallbacks.CallExecutes(addr); + MemoryCallbacks.CallExecutes(addr, "System Bus"); } void ButtonCallback() { diff --git a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj index 4f34ffd071..9ad6e73985 100644 --- a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj +++ b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj @@ -70,6 +70,7 @@ + diff --git a/BizHawk.Emulation.DiscSystem/CDFS/EndianBitConverter.cs b/BizHawk.Emulation.DiscSystem/CDFS/EndianBitConverter.cs index 382cd7c39a..3ecee543b6 100644 --- a/BizHawk.Emulation.DiscSystem/CDFS/EndianBitConverter.cs +++ b/BizHawk.Emulation.DiscSystem/CDFS/EndianBitConverter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; namespace BizHawk.Emulation.DiscSystem @@ -114,5 +115,49 @@ namespace BizHawk.Emulation.DiscSystem } #endregion + + // (asni 20171013) - Some methods I wrote that have been shoehorned in from another project to speed up development time + // If these are offensive in any way, tell me I suck and that I need to do more work with existing methods + #region Misc + + /// + /// Returns a byte array of any length + /// Not really anything endian going on, but I struggled to find a better place for it + /// + /// + /// + /// + /// + public byte[] ReadBytes(byte[] buffer, int offset, int length) + { + return buffer.Skip(offset).Take(length).ToArray(); + } + + /// + /// Returns an int32 value from any size byte array + /// (careful, data may/will be truncated) + /// + /// + /// + /// + /// + public int ReadIntValue(byte[] buffer, int offset, int length) + { + var bytes = buffer.Skip(offset).Take(length).ToArray(); + + if (swap) + Array.Reverse(bytes); + + if (length == 1) + return bytes.FirstOrDefault(); + + if (length == 2) + return BitConverter.ToInt16(bytes, 0); + + int result = BitConverter.ToInt32(bytes, 0); + return result; + } + + #endregion } } diff --git a/BizHawk.Emulation.DiscSystem/CDFS/ISODirectoryNode.cs b/BizHawk.Emulation.DiscSystem/CDFS/ISODirectoryNode.cs index 53cd7f09b1..2b40ebb9a0 100644 --- a/BizHawk.Emulation.DiscSystem/CDFS/ISODirectoryNode.cs +++ b/BizHawk.Emulation.DiscSystem/CDFS/ISODirectoryNode.cs @@ -48,21 +48,24 @@ namespace BizHawk.Emulation.DiscSystem s.Seek(this.Offset * ISOFile.SECTOR_SIZE, SeekOrigin.Begin); List records = new List(); - - // Read the directory entries - while (s.Position < ((this.Offset * ISOFile.SECTOR_SIZE) + this.Length)) + + // Read the directory entries + while (s.Position < ((this.Offset * ISOFile.SECTOR_SIZE) + this.Length)) { ISONode node; ISONodeRecord record; - + // Read the record record = new ISONodeRecord(); - record.Parse(s); + if (ISOFile.Format == ISOFile.ISOFormat.CDInteractive) + record.ParseCDInteractive(s); + if (ISOFile.Format == ISOFile.ISOFormat.ISO9660) + record.ParseISO9660(s); - //zero 24-jun-2013 - improved validity checks - //theres nothing here! - if (record.Length == 0) + //zero 24-jun-2013 - improved validity checks + //theres nothing here! + if (record.Length == 0) { break; } @@ -95,7 +98,8 @@ namespace BizHawk.Emulation.DiscSystem } // Add the node as a child - this.Children.Add(record.Name, node); + if (!this.Children.ContainsKey(record.Name)) + this.Children.Add(record.Name, node); } } diff --git a/BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs b/BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs index fb848fa2fe..e81d6316a4 100644 --- a/BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs +++ b/BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs @@ -2,27 +2,51 @@ using System.Collections.Generic; using System.Text; using System.IO; +using System.Linq; namespace BizHawk.Emulation.DiscSystem { - /// - /// This class is meant to parse disk images as specified by ISO9660. - /// Specifically, it should work for most disk images that are created - /// by the stanard disk imaging software. This class is by no means - /// robust to all variations of ISO9660. - /// Also, this class does not currently support the UDF file system. - /// - /// TODO: Add functions to enumerate a directory or visit a file... - /// - /// The information for building class came from three primary sources: - /// 1. The ISO9660 wikipedia article: - /// http://en.wikipedia.org/wiki/ISO_9660 - /// 2. ISO9660 Simplified for DOS/Windows - /// http://alumnus.caltech.edu/~pje/iso9660.html - /// 3. The ISO 9660 File System - /// http://users.telenet.be/it3.consultants.bvba/handouts/ISO9960.html - /// - public class ISOFile + /// + /// This class is meant to parse disk images as specified by: + /// + /// ISO9660 + /// ------- + /// It should work for most disk images that are created + /// by the stanard disk imaging software. This class is by no means + /// robust to all variations of ISO9660. + /// Also, this class does not currently support the UDF file system. + /// + /// The information for building class came from three primary sources: + /// 1. The ISO9660 wikipedia article: + /// http://en.wikipedia.org/wiki/ISO_9660 + /// 2. ISO9660 Simplified for DOS/Windows + /// http://alumnus.caltech.edu/~pje/iso9660.html + /// 3. The ISO 9660 File System + /// http://users.telenet.be/it3.consultants.bvba/handouts/ISO9960.html + /// + /// + /// CD-I + /// ---- + /// (asni - 20171013) - Class modified to be able to detect and consume Green + /// Book disc images. + /// + /// The implemtation of CD-I in this class adds some (but not all) additional + /// properties to the class structures that CD-I brings. This means that + /// the same ISO class structures can be returned for both standards. + /// These small additions are readily found in ISOVolumeDescriptor.cs + /// + /// ISOFile.cs also now contains a public 'ISOFormat' enum that is set + /// during disc parsing. + /// + /// The main reference source for this implementation: + /// 1. The CD-I Full Functional Specification (aka Green Book) + /// https://www.lscdweb.com/data/downloadables/2/8/cdi_may94_r2.pdf + /// + /// + /// TODO: Add functions to enumerate a directory or visit a file... + /// + /// + public class ISOFile { #region Constants @@ -31,21 +55,37 @@ namespace BizHawk.Emulation.DiscSystem /// public const int SECTOR_SIZE = 2048; - #endregion + #endregion - #region Public Members + #region Static Members - /// - /// This is a list of all the volume descriptors in the disk image. - /// NOTE: The first entry should be the primary volume. - /// - public List VolumeDescriptors; + /// + /// Making this a static for now. Every other way I tried was fairly ineligant (asni) + /// + public static ISOFormat Format; + + public static List CDIPathTable; + + #endregion + + #region Public Members + + /// + /// This is a list of all the volume descriptors in the disk image. + /// NOTE: The first entry should be the primary volume. + /// + public List VolumeDescriptors; /// /// The Directory that is the root of this file system /// public ISODirectoryNode Root; + /// + /// The type of CDFS format detected + /// + public ISOFormat CDFSType; + #endregion #region Construction @@ -77,9 +117,9 @@ namespace BizHawk.Emulation.DiscSystem // Seek through the first volume descriptor s.Seek(startPosition + (SECTOR_SIZE * startSector), SeekOrigin.Begin); - - // Read one of more volume descriptors - do + + // Read one of more volume descriptors + do { //zero 24-jun-2013 - improved validity checks @@ -87,6 +127,8 @@ namespace BizHawk.Emulation.DiscSystem bool isValid = desc.Parse(s); if (!isValid) return false; + this.CDFSType = Format; + if (desc.IsTerminator()) break; else if (desc.Type < 4) @@ -98,16 +140,17 @@ namespace BizHawk.Emulation.DiscSystem } while (true); - //zero 24-jun-2013 - well, my very first test iso had 2 volume descriptors. - // Check to make sure we only read one volume descriptor - // Finding more could be an error with the disk. - //if (this.VolumeDescriptors.Count != 1) { - // Console.WriteLine("Strange ISO format..."); - // return; - //} + //zero 24-jun-2013 - well, my very first test iso had 2 volume descriptors. + // Check to make sure we only read one volume descriptor + // Finding more could be an error with the disk. + //if (this.VolumeDescriptors.Count != 1) { + // Console.WriteLine("Strange ISO format..."); + // return; + //} - //zero 24-jun-2013 - if theres no volume descriptors, we're gonna call this not a cdfs - if (VolumeDescriptors.Count == 0) return false; + + //zero 24-jun-2013 - if theres no volume descriptors, we're gonna call this not a cdfs + if (VolumeDescriptors.Count == 0) return false; // Visit all the directories and get the offset of each directory/file @@ -116,12 +159,68 @@ namespace BizHawk.Emulation.DiscSystem // Create (and visit) the root node this.Root = new ISODirectoryNode(this.VolumeDescriptors[0].RootDirectoryRecord); - visitedNodes.Add(this.Root.Offset, this.Root); - this.Root.Parse(s, visitedNodes); + + visitedNodes.Add(this.Root.Offset, this.Root); + this.Root.Parse(s, visitedNodes); return true; } + + private List> fileNodes; + private List dirsParsed; + + /// + /// Returns a flat list of all recursed files + /// + /// + public List> EnumerateAllFilesRecursively() + { + fileNodes = new List>(); + dirsParsed = new List(); + + if (Root.Children == null) + return fileNodes; + + // get all folders + List> dirs = (from a in Root.Children + where a.Value.GetType() == typeof(ISODirectoryNode) + select a).ToList(); + // iterate through each folder + foreach (var d in dirs) + { + // process all files in this directory (and recursively process files in sub folders + ISODirectoryNode idn = d.Value as ISODirectoryNode; + if (dirsParsed.Where(a => a == idn).Count() > 0) + continue; + + dirsParsed.Add(idn); + ProcessDirectoryFiles(idn.Children); + } + + return fileNodes.Distinct().ToList(); + } + + private void ProcessDirectoryFiles(Dictionary idn) + { + foreach (var n in idn) + { + if (n.Value.GetType() == typeof(ISODirectoryNode)) + { + if (dirsParsed.Where(a => a == n.Value).Count() > 0) + continue; + + dirsParsed.Add(n.Value as ISODirectoryNode); + ProcessDirectoryFiles((n.Value as ISODirectoryNode).Children); + } + else + { + KeyValuePair f = new KeyValuePair(n.Key, n.Value as ISOFileNode); + fileNodes.Add(f); + } + } + } + #endregion #region Printing @@ -135,6 +234,17 @@ namespace BizHawk.Emulation.DiscSystem this.Root.Print(0); } - #endregion - } + #endregion + + #region Misc + + public enum ISOFormat + { + Unknown, + ISO9660, + CDInteractive + } + + #endregion + } } diff --git a/BizHawk.Emulation.DiscSystem/CDFS/ISONodeRecord.cs b/BizHawk.Emulation.DiscSystem/CDFS/ISONodeRecord.cs index 1913f3d897..72bb82cfff 100644 --- a/BizHawk.Emulation.DiscSystem/CDFS/ISONodeRecord.cs +++ b/BizHawk.Emulation.DiscSystem/CDFS/ISONodeRecord.cs @@ -31,10 +31,16 @@ namespace BizHawk.Emulation.DiscSystem /// public byte Length; - /// - /// The file offset of the data for this file/directory (in sectors). - /// - public long OffsetOfData; + /// + /// This is the number of blocks at the beginning of the file reserved for extended attribute information + /// The format of the extended attribute record is not defined and is reserved for application use + /// + public byte ExtendedAttribRecordLength; + + /// + /// The file offset of the data for this file/directory (in sectors). + /// + public long OffsetOfData; /// /// The length of the data for this file/directory (in bytes). /// @@ -148,14 +154,19 @@ namespace BizHawk.Emulation.DiscSystem // Put the array into a memory stream and pass to the main parsing function MemoryStream s = new MemoryStream(data); s.Seek(cursor, SeekOrigin.Begin); - this.Parse(s); + + if (ISOFile.Format == ISOFile.ISOFormat.ISO9660) + this.ParseISO9660(s); + + if (ISOFile.Format == ISOFile.ISOFormat.CDInteractive) + this.ParseCDInteractive(s); } /// - /// Parse the node record from the given stream. + /// Parse the node record from the given ISO9660 stream. /// /// The stream to parse from. - public void Parse(Stream s) + public void ParseISO9660(Stream s) { EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); long startPosition = s.Position; @@ -212,6 +223,100 @@ namespace BizHawk.Emulation.DiscSystem s.Seek(startPosition + this.Length, SeekOrigin.Begin); } - #endregion - } + /// + /// Parse the node record from the given CD-I stream. + /// + /// The stream to parse from. + public void ParseCDInteractive(Stream s) + { + /* + BP Size in bytes Description + 1 1 Record length + 2 1 Extended Attribute record length + 3 4 Reserved + 7 4 File beginning LBN + 11 4 Reserved + 15 4 File size + 19 6 Creation date + 25 1 Reserved + 26 1 File flags + 27 2 Interleave + 29 2 Reserved + 31 2 Album Set Sequence number + 33 1 File name size + 34 (n) File name + 34+n 4 Owner ID + 38+n 2 Attributes + 40+n 2 Reserved + 42+n 1 File number + 43+n 1 Reserved + 43+n Total + */ + + EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); + EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); + long startPosition = s.Position; + byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; + + // Read the entire structure + s.Read(buffer, 0, ISOFile.SECTOR_SIZE); + s.Position -= ISOFile.SECTOR_SIZE; + + // Get the record length + this.Length = buffer[0]; + + // extended attribute record length + this.ExtendedAttribRecordLength = buffer[1]; + + // Read Data Offset + this.OffsetOfData = bcBig.ReadIntValue(buffer, 6, 4); + + // Read Data Length + this.LengthOfData = bcBig.ReadIntValue(buffer, 14, 4); + + // Read the time + var ti = bc.ReadBytes(buffer, 18, 6); + this.Year = ti[0]; + this.Month = ti[1]; + this.Day = ti[2]; + this.Hour = ti[3]; + this.Minute = ti[4]; + this.Second = ti[5]; + + // read interleave - still to do + + // read album (volume) set sequence number (we are ignoring this) + + // Read the name length + this.NameLength = buffer[32]; + + // Read the file/directory name + var name = bc.ReadBytes(buffer, 33, this.NameLength); + if (this.NameLength == 1 && (name[0] == 0 || name[0] == 1)) + { + if (name[0] == 0) + this.Name = ISONodeRecord.CURRENT_DIRECTORY; + else + this.Name = ISONodeRecord.PARENT_DIRECTORY; + } + else + { + this.Name = ASCIIEncoding.ASCII.GetString(name, 0, this.NameLength); + } + + // skip ownerID for now + + // read the flags - only really interested in the directory attribute (bit 15) + // (confusingly these are called 'attributes' in CD-I. the CD-I 'File Flags' entry is something else entirely) + this.Flags = buffer[37 + this.NameLength]; + + // skip filenumber + //this.FileNumber = buffer[41 + this.NameLength]; + + // Seek to end + s.Seek(startPosition + this.Length, SeekOrigin.Begin); + } + + #endregion + } } diff --git a/BizHawk.Emulation.DiscSystem/CDFS/ISOVolumeDescriptor.cs b/BizHawk.Emulation.DiscSystem/CDFS/ISOVolumeDescriptor.cs index 4dda3f59e4..e8b271e10f 100644 --- a/BizHawk.Emulation.DiscSystem/CDFS/ISOVolumeDescriptor.cs +++ b/BizHawk.Emulation.DiscSystem/CDFS/ISOVolumeDescriptor.cs @@ -25,14 +25,21 @@ namespace BizHawk.Emulation.DiscSystem private const int LENGTH_TIME = 17; private const int LENGTH_RESERVED = 512; - #endregion + #endregion - #region Public Properties + #region Private Properties - /// - /// The type of this volume description, only 1 and 255 are supported - /// - public byte Type; + private EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); + private EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); + + #endregion + + #region Public Properties + + /// + /// The type of this volume description, only 1 and 255 are supported + /// + public byte Type; /// /// The system identifier @@ -66,21 +73,21 @@ namespace BizHawk.Emulation.DiscSystem /// public int PathTableSize; /// - /// Sector offset of the first path table + /// (ISO9660 only) Sector offset of the first path table /// public int OffsetOfFirstLittleEndianPathTable; - /// - /// Sector offset of the second path table - /// - public int OffsetOfSecondLittleEndianPathTable; - /// - /// Sector offset of the first path table - /// - public int OffsetOfFirstBigEndianPathTable; - /// - /// Sector offset of the second path table - /// - public int OffsetOfSecondBigEndianPathTable; + /// + /// (ISO9660 only) Sector offset of the second path table + /// + public int OffsetOfSecondLittleEndianPathTable; + /// + /// (ISO9660 only) Sector offset of the first path table + /// + public int OffsetOfFirstBigEndianPathTable; + /// + /// (ISO9660 only) Sector offset of the second path table + /// + public int OffsetOfSecondBigEndianPathTable; /// /// The root directory record @@ -134,19 +141,43 @@ namespace BizHawk.Emulation.DiscSystem /// public byte[] EffectiveDateTime; - /// - /// Extra reserved data - /// - public byte[] Reserved; + /// + /// (ISO9660 only) Extra reserved data + /// + public byte[] Reserved; - #endregion - #region Construction + // CD-Interactive only + + /// + /// The bits of this field are numbered from 0 to 7 starting with the least significant bit + /// BitPosition 0: A value of 0 = the coded character set identifier field specifies only an escape sequence registered according to ISO 2375 + /// A value of 1 = the coded character set identifier field specifies only an escape sequence NOT registered according to ISO 2375 + /// BitPostion 1-7: All bits are 0 (reserved for future standardization) + /// + public byte VolumeFlags; + /// + /// This field specifies one escape sequence according to the International Register of Coded Character Sets to be used with escape + /// sequence standards for recording.The ESC character, which is the first character of all sequences, shall be omitted when recording this field + /// + public byte[] CodedCharSetIdent; + /// + /// The block address of the first block of the system Path Table is kept in this field + /// + public int AddressOfPathTable; + /// + /// This number is used to indicate the revision number of the file structure standard to which the + /// directory search files conform. It is set to one + /// - /// - /// Constructor. - /// - public ISOVolumeDescriptor() + #endregion + + #region Construction + + /// + /// Constructor. + /// + public ISOVolumeDescriptor() { // Set everything to the default value this.Type = 0; @@ -183,6 +214,11 @@ namespace BizHawk.Emulation.DiscSystem this.EffectiveDateTime = new byte[LENGTH_TIME]; this.Reserved = new byte[LENGTH_RESERVED]; + + // CD-I specific + this.VolumeFlags = 0; + this.CodedCharSetIdent = new byte[LENGTH_SHORT_IDENTIFIER]; + this.AddressOfPathTable = 0; } #endregion @@ -190,137 +226,391 @@ namespace BizHawk.Emulation.DiscSystem #region Parsing /// - /// Parse the volume descriptor header. + /// Start parsing the volume descriptor header. /// /// The stream to parse from. public bool Parse(Stream s) { - EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); - EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); long startPosition = s.Position; byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; // Read the entire structure s.Read(buffer, 0, ISOFile.SECTOR_SIZE); - // Get the type - this.Type = buffer[0]; + // Parse based on format + byte[] header = bc.ReadBytes(buffer, 0, ISOFile.SECTOR_SIZE); + if (GetISO9660(header)) + { + ParseISO9660(s); + return true; + } + if (GetCDI(header)) + { + ParseCDInteractive(s); + return true; + } - //zero 24-jun-2013 - validate - // "CD001" + 0x01 - if (buffer[1] == 'C' && buffer[2] == 'D' && buffer[3] == '0' && buffer[4] == '0' && buffer[5] == '1' && buffer[6] == 0x01) - { - //it seems to be a valid volume descriptor - } - else - { - return false; - } - - // Handle the primary volume information - if (this.Type == 1) - { - int cursor = 8; - // Get the system identifier - Array.Copy(buffer, cursor, - this.SystemIdentifier, 0, LENGTH_SHORT_IDENTIFIER); - cursor += LENGTH_SHORT_IDENTIFIER; - - // Get the volume identifier - Array.Copy(buffer, cursor, - this.VolumeIdentifier, 0, LENGTH_SHORT_IDENTIFIER); - cursor += LENGTH_SHORT_IDENTIFIER; - - cursor += 8; - - // Get the total number of sectors - this.NumberOfSectors = bc.ToInt32(buffer, cursor); - cursor += 8; - - cursor += 32; - - this.VolumeSetSize = bc.ToInt16(buffer, cursor); - cursor += 4; - this.VolumeSequenceNumber = bc.ToInt16(buffer, cursor); - cursor += 4; - this.SectorSize = bc.ToInt16(buffer, cursor); - cursor += 4; - - this.PathTableSize = bc.ToInt32(buffer, cursor); - cursor += 8; - this.OffsetOfFirstLittleEndianPathTable = bc.ToInt32(buffer, cursor); - cursor += 4; - this.OffsetOfSecondLittleEndianPathTable = bc.ToInt32(buffer, cursor); - cursor += 4; - this.OffsetOfFirstLittleEndianPathTable = bcBig.ToInt32(buffer, cursor); - cursor += 4; - this.OffsetOfSecondLittleEndianPathTable = bcBig.ToInt32(buffer, cursor); - cursor += 4; - - this.RootDirectoryRecord.Parse(buffer, cursor); - cursor += LENGTH_ROOT_DIRECTORY_RECORD; - - Array.Copy(buffer, cursor, - this.VolumeSetIdentifier, 0, LENGTH_LONG_IDENTIFIER); - cursor += LENGTH_LONG_IDENTIFIER; - Array.Copy(buffer, cursor, - this.PublisherIdentifier, 0, LENGTH_LONG_IDENTIFIER); - cursor += LENGTH_LONG_IDENTIFIER; - Array.Copy(buffer, cursor, - this.DataPreparerIdentifier, 0, LENGTH_LONG_IDENTIFIER); - cursor += LENGTH_LONG_IDENTIFIER; - Array.Copy(buffer, cursor, - this.ApplicationIdentifier, 0, LENGTH_LONG_IDENTIFIER); - cursor += LENGTH_LONG_IDENTIFIER; - - Array.Copy(buffer, cursor, - this.CopyrightFileIdentifier, 0, LENGTH_IDENTIFIER); - cursor += LENGTH_IDENTIFIER; - Array.Copy(buffer, cursor, - this.AbstractFileIdentifier, 0, LENGTH_IDENTIFIER); - cursor += LENGTH_IDENTIFIER; - Array.Copy(buffer, cursor, - this.BibliographicalFileIdentifier, 0, LENGTH_IDENTIFIER); - cursor += LENGTH_IDENTIFIER; - - Array.Copy(buffer, cursor, - this.VolumeCreationDateTime, 0, LENGTH_TIME); - cursor += LENGTH_TIME; - Array.Copy(buffer, cursor, - this.LastModifiedDateTime, 0, LENGTH_TIME); - cursor += LENGTH_TIME; - Array.Copy(buffer, cursor, - this.ExpirationDateTime, 0, LENGTH_TIME); - cursor += LENGTH_TIME; - Array.Copy(buffer, cursor, - this.EffectiveDateTime, 0, LENGTH_TIME); - cursor += LENGTH_TIME; - - cursor += 1; - - cursor += 1; - - Array.Copy(buffer, cursor, - this.Reserved, 0, LENGTH_RESERVED); - cursor += LENGTH_RESERVED; - } - - return true; + return false; } - #endregion + public void ParseISO9660(Stream s) + { + long startPosition = s.Position; + byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; + s.Position = startPosition - ISOFile.SECTOR_SIZE; - #region Type Information + // Read the entire structure + s.Read(buffer, 0, ISOFile.SECTOR_SIZE); - /// - /// Returns true if this is the terminator volume descriptor. - /// - /// True if the terminator. - public bool IsTerminator() + // Get the type + this.Type = buffer[0]; + + // Handle the primary volume information + if (this.Type == 1) + { + int cursor = 8; + // Get the system identifier + Array.Copy(buffer, cursor, + this.SystemIdentifier, 0, LENGTH_SHORT_IDENTIFIER); + cursor += LENGTH_SHORT_IDENTIFIER; + + // Get the volume identifier + Array.Copy(buffer, cursor, + this.VolumeIdentifier, 0, LENGTH_SHORT_IDENTIFIER); + cursor += LENGTH_SHORT_IDENTIFIER; + + cursor += 8; + + // Get the total number of sectors + this.NumberOfSectors = bc.ToInt32(buffer, cursor); + cursor += 8; + + cursor += 32; + + this.VolumeSetSize = bc.ToInt16(buffer, cursor); + cursor += 4; + this.VolumeSequenceNumber = bc.ToInt16(buffer, cursor); + cursor += 4; + this.SectorSize = bc.ToInt16(buffer, cursor); + cursor += 4; + + this.PathTableSize = bc.ToInt32(buffer, cursor); + cursor += 8; + this.OffsetOfFirstLittleEndianPathTable = bc.ToInt32(buffer, cursor); + cursor += 4; + this.OffsetOfSecondLittleEndianPathTable = bc.ToInt32(buffer, cursor); + cursor += 4; + this.OffsetOfFirstLittleEndianPathTable = bcBig.ToInt32(buffer, cursor); + cursor += 4; + this.OffsetOfSecondLittleEndianPathTable = bcBig.ToInt32(buffer, cursor); + cursor += 4; + + this.RootDirectoryRecord.Parse(buffer, cursor); + cursor += LENGTH_ROOT_DIRECTORY_RECORD; + + Array.Copy(buffer, cursor, + this.VolumeSetIdentifier, 0, LENGTH_LONG_IDENTIFIER); + cursor += LENGTH_LONG_IDENTIFIER; + Array.Copy(buffer, cursor, + this.PublisherIdentifier, 0, LENGTH_LONG_IDENTIFIER); + cursor += LENGTH_LONG_IDENTIFIER; + Array.Copy(buffer, cursor, + this.DataPreparerIdentifier, 0, LENGTH_LONG_IDENTIFIER); + cursor += LENGTH_LONG_IDENTIFIER; + Array.Copy(buffer, cursor, + this.ApplicationIdentifier, 0, LENGTH_LONG_IDENTIFIER); + cursor += LENGTH_LONG_IDENTIFIER; + + Array.Copy(buffer, cursor, + this.CopyrightFileIdentifier, 0, LENGTH_IDENTIFIER); + cursor += LENGTH_IDENTIFIER; + Array.Copy(buffer, cursor, + this.AbstractFileIdentifier, 0, LENGTH_IDENTIFIER); + cursor += LENGTH_IDENTIFIER; + Array.Copy(buffer, cursor, + this.BibliographicalFileIdentifier, 0, LENGTH_IDENTIFIER); + cursor += LENGTH_IDENTIFIER; + + Array.Copy(buffer, cursor, + this.VolumeCreationDateTime, 0, LENGTH_TIME); + cursor += LENGTH_TIME; + Array.Copy(buffer, cursor, + this.LastModifiedDateTime, 0, LENGTH_TIME); + cursor += LENGTH_TIME; + Array.Copy(buffer, cursor, + this.ExpirationDateTime, 0, LENGTH_TIME); + cursor += LENGTH_TIME; + Array.Copy(buffer, cursor, + this.EffectiveDateTime, 0, LENGTH_TIME); + cursor += LENGTH_TIME; + + cursor += 1; + + cursor += 1; + + Array.Copy(buffer, cursor, + this.Reserved, 0, LENGTH_RESERVED); + cursor += LENGTH_RESERVED; + } + } + + public void ParseCDInteractive(Stream s) + { + /* From the Green Book Spec + * BP (byte position) obviously is n+1 + + BP Size in Bytes Description + 1 1 Disc Label Record Type + 2 5 Volume Structure Standard ID + 7 1 Volume Structure Version number + 8 1 Volume flags + 9 32 System identifier + 41 32 Volume identifier + 73 12 Reserved + 85 4 Volume space size + 89 32 Coded Character Set identifier + 121 2 Reserved + 123 2 Number of Volumes in Album + 125 2 Reserved + 127 2 Album Set Sequence number + 129 2 Reserved + 131 2 Logical Block size + 133 4 Reserved + 137 4 Path Table size + 141 8 Reserved + 149 4 Address of Path Table + 153 38 Reserved + 191 128 Album identifier + 319 128 Publisher identifier + 447 128 Data Preparer identifier + 575 128 Application identifier + 703 32 Copyright file name + 735 5 Reserved + 740 32 Abstract file name + 772 5 Reserved + 777 32 Bibliographic file name + 809 5 Reserved + 814 16 Creation date and time + 830 1 Reserved + 831 16 Modification date and time + 847 1 Reserved + 848 16 Expiration date and time + 864 1 Reserved + 865 16 Effective date and time + 881 1 Reserved + 882 1 File Structure Standard Version number + 883 1 Reserved + 884 512 Application use + 1396 653 Reserved */ + + long startPosition = s.Position; + byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; + s.Position = startPosition - ISOFile.SECTOR_SIZE; + + // Read the entire structure + s.Read(buffer, 0, ISOFile.SECTOR_SIZE); + + // Get the type + this.Type = buffer[0]; + + // Handle the primary volume information + if (this.Type == 1) + { + this.VolumeFlags = buffer[7]; + this.SystemIdentifier = bc.ReadBytes(buffer, 8, LENGTH_SHORT_IDENTIFIER); + this.VolumeIdentifier = bc.ReadBytes(buffer, 40, LENGTH_SHORT_IDENTIFIER); + this.NumberOfSectors = bcBig.ReadIntValue(buffer, 84, 4); + this.CodedCharSetIdent = bc.ReadBytes(buffer, 88, LENGTH_SHORT_IDENTIFIER); + this.VolumeSetSize = bcBig.ReadIntValue(buffer, 122, 2); + this.VolumeSequenceNumber = bcBig.ReadIntValue(buffer, 126, 2); + this.SectorSize = bcBig.ReadIntValue(buffer, 130, 2); + this.PathTableSize = bcBig.ReadIntValue(buffer, 136, 4); + this.AddressOfPathTable = bcBig.ReadIntValue(buffer, 148, 4); + + this.VolumeSetIdentifier = bc.ReadBytes(buffer, 190, LENGTH_LONG_IDENTIFIER); + this.PublisherIdentifier = bc.ReadBytes(buffer, 318, LENGTH_LONG_IDENTIFIER); + this.DataPreparerIdentifier = bc.ReadBytes(buffer, 446, LENGTH_LONG_IDENTIFIER); + this.ApplicationIdentifier = bc.ReadBytes(buffer, 574, LENGTH_LONG_IDENTIFIER); + + this.CopyrightFileIdentifier = bc.ReadBytes(buffer, 702, LENGTH_SHORT_IDENTIFIER); + this.AbstractFileIdentifier = bc.ReadBytes(buffer, 739, LENGTH_SHORT_IDENTIFIER); + this.BibliographicalFileIdentifier = bc.ReadBytes(buffer, 776, LENGTH_SHORT_IDENTIFIER); + + this.VolumeCreationDateTime = bc.ReadBytes(buffer, 813, 16); + this.LastModifiedDateTime = bc.ReadBytes(buffer, 830, 16); + this.ExpirationDateTime = bc.ReadBytes(buffer, 847, 16); + this.EffectiveDateTime = bc.ReadBytes(buffer, 864, 16); + + // save current position + long pos = s.Position; + + // get path table records + s.Position = ISOFile.SECTOR_SIZE * this.AddressOfPathTable; + ISOFile.CDIPathTable = CDIPathNode.ParsePathTable(s, this.PathTableSize); + + // read the root dir record + s.Position = ISOFile.SECTOR_SIZE * ISOFile.CDIPathTable[0].DirectoryBlockAddress; + s.Read(buffer, 0, ISOFile.SECTOR_SIZE); + this.RootDirectoryRecord.Parse(buffer, 0); + + // go back to where we were + s.Position = pos; + } + } + + /// + /// Detect ISO9660 + /// + /// + /// + public bool GetISO9660(byte[] buffer) + { + //zero 24-jun-2013 - validate ISO9660 + // "CD001" + 0x01 + if (buffer[1] == 'C' && buffer[2] == 'D' && buffer[3] == '0' && buffer[4] == '0' && buffer[5] == '1' && buffer[6] == 0x01) + { + ISOFile.Format = ISOFile.ISOFormat.ISO9660; + return true; + } + + return false; + } + + /// + /// Detect CD-I + /// + /// + /// + public bool GetCDI(byte[] buffer) + { + // CD-Interactive + if (Encoding.ASCII.GetString(bc.ReadBytes(buffer, 1, 5)).Contains("CD-I")) + { + ISOFile.Format = ISOFile.ISOFormat.CDInteractive; + return true; + } + + return false; + } + + #endregion + + #region Type Information + + /// + /// Returns true if this is the terminator volume descriptor. + /// + /// True if the terminator. + public bool IsTerminator() { return (this.Type == 255); } #endregion } + + /// + /// Represents a Directory Path Table entry on a CD-I disc + /// + public class CDIPathNode + { + #region Public Properties + + /// + /// The length of the directory name. + /// + public byte NameLength; + + /// + /// This is the length of the Extended Attribute record + /// + public byte ExtendedAttribRecordLength; + + /// + /// This field contains the beginning logical block number (LBN) of the directory file on disc + /// + public int DirectoryBlockAddress; + + /// + /// This is the number (relative to the beginning of the Path Table) of this directory's parent + /// + public int ParentDirectoryNumber; + + /// + /// The directory name. + /// This variable length field is used to store the actual text representing the name of the directory. + /// If the length of the file name is odd, a null padding byte is added to make the size of the Path Table record even. + /// The padding byte is not included in the name size field. + /// + public string Name; + + #endregion + + #region Construction + + /// + /// Empty Constructor + /// + public CDIPathNode() + { + + } + + #endregion + + #region Parsing + + /* + BP Size in bytes Description + 1 1 Name size + 2 1 Extended Attribute record length + 3 4 Directory block address + 7 2 Parent Directory number + 9 n Directory file name + */ + + public static List ParsePathTable(Stream s, int PathTableSize) + { + EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); + EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); + + byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; + + // Read the entire structure + s.Read(buffer, 0, ISOFile.SECTOR_SIZE); + + int startCursor = 0; + + List pathNodes = new List(); + + int pad = 0; + + do + { + CDIPathNode node = new CDIPathNode(); + byte[] data = bc.ReadBytes(buffer, startCursor, ISOFile.SECTOR_SIZE - startCursor); + node.NameLength = data[0]; + + node.ExtendedAttribRecordLength = data[1]; + node.DirectoryBlockAddress = bcBig.ReadIntValue(data, 2, 4); + node.ParentDirectoryNumber = bcBig.ReadIntValue(data, 6, 2); + node.Name = Encoding.ASCII.GetString(bc.ReadBytes(data, 8, data[0])); + + // if nameLength is odd a padding byte must be added + + if (node.NameLength % 2 != 0) + pad = 1; + + pathNodes.Add(node); + + startCursor += node.NameLength + 8; + + } while (startCursor < PathTableSize + pad); + + + return pathNodes; + } + + #endregion + } } diff --git a/BizHawk.Emulation.DiscSystem/Disc.cs b/BizHawk.Emulation.DiscSystem/Disc.cs index ea971e56e9..88b38540ae 100644 --- a/BizHawk.Emulation.DiscSystem/Disc.cs +++ b/BizHawk.Emulation.DiscSystem/Disc.cs @@ -74,12 +74,36 @@ namespace BizHawk.Emulation.DiscSystem } } + /// + /// Easily extracts a mode1 sector range (suitable for extracting ISO FS data files) + /// + public byte[] Easy_Extract_Mode1(int lba_start, int lba_count, int byteLength = -1) + { + int totsize = lba_count * 2048; + byte[] ret = new byte[totsize]; + var dsr = new DiscSectorReader(this); + dsr.Policy.DeterministicClearBuffer = false; + for (int i = 0; i < lba_count; i++) + { + dsr.ReadLBA_2048(lba_start + i, ret, i*2048); + } + if (byteLength != -1 && byteLength != totsize) + { + byte[] newret = new byte[byteLength]; + Array.Copy(ret, newret, byteLength); + return newret; + } + return ret; + } + /// /// The DiscMountPolicy used to mount the disc. Consider this read-only. /// NOT SURE WE NEED THIS /// //public DiscMountPolicy DiscMountPolicy; + + //---------------------------------------------------------------------------- /// diff --git a/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs b/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs new file mode 100644 index 0000000000..27699da2d1 --- /dev/null +++ b/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs @@ -0,0 +1,915 @@ +using System; +using System.Text; +using System.IO; +using System.Globalization; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.DiscSystem +{ + /// + /// Parsing Alcohol 120% files + /// Info taken from: + /// * http://forum.redump.org/post/41803/#p41803 + /// * Libmirage image-mds parser - https://sourceforge.net/projects/cdemu/files/libmirage/ + /// * DiscImageChef - https://github.com/claunia/DiscImageChef/blob/master/DiscImageChef.DiscImages/Alcohol120.cs + /// + public class MDS_Format + { + /// + /// A loose representation of an Alcohol 120 .mds file (with a few extras) + /// + public class AFile + { + /// + /// Full path to the MDS file + /// + public string MDSPath; + + /// + /// MDS Header + /// + public AHeader Header = new AHeader(); + + /// + /// List of MDS session blocks + /// + public List Sessions = new List(); + + /// + /// List of track blocks + /// + public List Tracks = new List(); + + /// + /// Current parsed session objects + /// + public List ParsedSession = new List(); + + /// + /// Calculated MDS TOC entries (still to be parsed into BizHawk) + /// + public List TOCEntries = new List(); + + } + + public class AHeader + { + /// + /// Standard alcohol 120% signature - usually "MEDIA DESCRIPTOR" + /// + public string Signature; // 16 bytes + + /// + /// Alcohol version? + /// + public byte[] Version; // 2 bytes + + /// + /// The medium type + /// * 0x00 - CD + /// * 0x01 - CD-R + /// * 0x02 - CD-RW + /// * 0x10 - DVD + /// * 0x12 - DVD-R + /// + public int Medium; + + /// + /// Number of sessions + /// + public int SessionCount; + + /// + /// Burst Cutting Area length + /// + public int BCALength; + + /// + /// Burst Cutting Area data offset + /// + public Int64 BCAOffset; + + /// + /// Offset to disc (DVD?) structures + /// + public Int64 StructureOffset; + + /// + /// Offset to the first session block + /// + public Int64 SessionOffset; + + /// + /// Data Position Measurement offset + /// + public Int64 DPMOffset; + + /// + /// Parse mds stream for the header + /// + /// + /// + public AHeader Parse(Stream stream) + { + EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); + EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); + + byte[] header = new byte[88]; + stream.Read(header, 0, 88); + + this.Signature = Encoding.ASCII.GetString(header.Take(16).ToArray()); + this.Version = header.Skip(16).Take(2).ToArray(); + this.Medium = bc.ToInt16(header.Skip(18).Take(2).ToArray()); + this.SessionCount = bc.ToInt16(header.Skip(20).Take(2).ToArray()); + this.BCALength = bc.ToInt16(header.Skip(26).Take(2).ToArray()); + this.BCAOffset = bc.ToInt32(header.Skip(36).Take(4).ToArray()); + this.StructureOffset = bc.ToInt32(header.Skip(64).Take(4).ToArray()); + this.SessionOffset = bc.ToInt32(header.Skip(80).Take(4).ToArray()); + this.DPMOffset = bc.ToInt32(header.Skip(84).Take(4).ToArray()); + + return this; + } + } + + /// + /// MDS session block representation + /// + public class ASession + { + public int SessionStart; /* Session's start address */ + public int SessionEnd; /* Session's end address */ + public int SessionNumber; /* Session number */ + public byte AllBlocks; /* Number of all data blocks. */ + public byte NonTrackBlocks; /* Number of lead-in data blocks */ + public int FirstTrack; /* First track in session */ + public int LastTrack; /* Last track in session */ + public Int64 TrackOffset; /* Offset of lead-in+regular track data blocks. */ + } + + /// + /// Representation of an MDS track block + /// For convenience (and extra confusion) this also holds the track extrablock, filename(footer) block infos + /// as well as the calculated image filepath as specified in the MDS file + /// + public class ATrack + { + /// + /// The specified data mode + /// 0x00 - None (no data) + /// 0x02 - DVD + /// 0xA9 - Audio + /// 0xAA - Mode1 + /// 0xAB - Mode2 + /// 0xAC - Mode2 Form1 + /// 0xAD - Mode2 Form2 + /// + public byte Mode; /* Track mode */ + + /// + /// Subchannel mode for the track (0x00 = None, 0x08 = Interleaved) + /// + public byte SubMode; /* Subchannel mode */ + + /* These are the fields from Sub-channel Q information, which are + also returned in full TOC by READ TOC/PMA/ATIP command */ + public int ADR_Control; /* Adr/Ctl */ + public int TrackNo; /* Track number field */ + public int Point; /* Point field (= track number for track entries) */ + public int AMin; /* Min */ + public int ASec; /* Sec */ + public int AFrame; /* Frame */ + public int Zero; /* Zero */ + public int PMin; /* PMin */ + public int PSec; /* PSec */ + public int PFrame; /* PFrame */ + + public Int64 ExtraOffset; /* Start offset of this track's extra block. */ + public int SectorSize; /* Sector size. */ + public Int64 PLBA; /* Track start sector (PLBA). */ + public ulong StartOffset; /* Track start offset (from beginning of MDS file) */ + public Int64 Files; /* Number of filenames for this track */ + public Int64 FooterOffset; /* Start offset of footer (from beginning of MDS file) */ + + /// + /// Track extra block + /// + public ATrackExtra ExtraBlock = new ATrackExtra(); + + /// + /// List of footer(filename) blocks for this track + /// + public List FooterBlocks = new List(); + + /// + /// List of the calculated full paths to this track's image file + /// The MDS file itself may contain a filename, or just an *.extension + /// + public List ImageFileNamePaths = new List(); + + public int BlobIndex; + } + + /// + /// Extra track block + /// + public class ATrackExtra + { + public Int64 Pregap; /* Number of sectors in pregap. */ + public Int64 Sectors; /* Number of sectors in track. */ + } + + /// + /// Footer (filename) block - potentially one for every track + /// + public class AFooter + { + public Int64 FilenameOffset; /* Start offset of image filename string (from beginning of mds file) */ + public Int64 WideChar; /* Seems to be set to 1 if widechar filename is used */ + } + + /// + /// Represents a parsed MDS TOC entry + /// + public class ATOCEntry + { + public ATOCEntry(int entryNum) + { + EntryNum = entryNum; + } + + /// + /// these should be 0-indexed + /// + public int EntryNum; + + + /// + /// 1-indexed - the session that this entry belongs to + /// + public int Session; + + /// + /// this seems just to be the LBA corresponding to AMIN:ASEC:AFRAME (give or take 150). It's not stored on the disc, and it's redundant. + /// + //public int ALBA; + + /// + /// this seems just to be the LBA corresponding to PMIN:PSEC:PFRAME (give or take 150). + /// + public int PLBA; + + //these correspond pretty directly to values in the Q subchannel fields + //NOTE: they're specified as absolute MSF. That means, they're 2 seconds off from what they should be when viewed as final TOC values + public int ADR_Control; + public int TrackNo; + public int Point; + public int AMin; + public int ASec; + public int AFrame; + public int Zero; + public int PMin; + public int PSec; + public int PFrame; + + + public int SectorSize; + public long TrackOffset; + + /// + /// List of the calculated full paths to this track's image file + /// The MDS file itself may contain a filename, or just an *.extension + /// + public List ImageFileNamePaths = new List(); + + /// + /// Track extra block + /// + public ATrackExtra ExtraBlock = new ATrackExtra(); + + public int BlobIndex; + } + + public AFile Parse(Stream stream) + { + EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); + EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); + bool isDvd = false; + + AFile aFile = new AFile(); + + aFile.MDSPath = (stream as FileStream).Name; + + stream.Seek(0, SeekOrigin.Begin); + + // check whether the header in the mds file is long enough + if (stream.Length < 88) throw new MDSParseException("Malformed MDS format: The descriptor file does not appear to be long enough."); + + // parse header + aFile.Header = aFile.Header.Parse(stream); + + // check version to make sure this is only v1.x + // currently NO support for version 2.x + + if (aFile.Header.Version[0] > 1) + { + throw new MDSParseException("MDS Parse Error: Only MDS version 1.x is supported!\nDetected version: " + aFile.Header.Version[0] + "." + aFile.Header.Version[1]); + } + + // parse sessions + Dictionary aSessions = new Dictionary(); + + stream.Seek(aFile.Header.SessionOffset, SeekOrigin.Begin); + for (int se = 0; se < aFile.Header.SessionCount; se++) + { + byte[] sessionHeader = new byte[24]; + stream.Read(sessionHeader, 0, 24); + //sessionHeader.Reverse().ToArray(); + + ASession session = new ASession(); + + session.SessionStart = bc.ToInt32(sessionHeader.Take(4).ToArray()); + session.SessionEnd = bc.ToInt32(sessionHeader.Skip(4).Take(4).ToArray()); + session.SessionNumber = bc.ToInt16(sessionHeader.Skip(8).Take(2).ToArray()); + session.AllBlocks = sessionHeader[10]; + session.NonTrackBlocks = sessionHeader[11]; + session.FirstTrack = bc.ToInt16(sessionHeader.Skip(12).Take(2).ToArray()); + session.LastTrack = bc.ToInt16(sessionHeader.Skip(14).Take(2).ToArray()); + session.TrackOffset = bc.ToInt32(sessionHeader.Skip(20).Take(4).ToArray()); + + + //mdsf.Sessions.Add(session); + aSessions.Add(session.SessionNumber, session); + } + + long footerOffset = 0; + + // parse track blocks + Dictionary aTracks = new Dictionary(); + + // iterate through each session block + foreach (ASession session in aSessions.Values) + { + stream.Seek(session.TrackOffset, SeekOrigin.Begin); + //Dictionary sessionToc = new Dictionary(); + + // iterate through every block specified in each session + for (int bl = 0; bl < session.AllBlocks; bl++) + { + byte[] trackHeader; + ATrack track = new ATrack(); + + trackHeader = new byte[80]; + + stream.Read(trackHeader, 0, 80); + + track.Mode = trackHeader[0]; + track.SubMode = trackHeader[1]; + track.ADR_Control = trackHeader[2]; + track.TrackNo = trackHeader[3]; + track.Point = trackHeader[4]; + track.AMin = trackHeader[5]; + track.ASec = trackHeader[6]; + track.AFrame = trackHeader[7]; + track.Zero = trackHeader[8]; + track.PMin = trackHeader[9]; + track.PSec = trackHeader[10]; + track.PFrame = trackHeader[11]; + track.ExtraOffset = bc.ToInt32(trackHeader.Skip(12).Take(4).ToArray()); + track.SectorSize = bc.ToInt16(trackHeader.Skip(16).Take(2).ToArray()); + track.PLBA = bc.ToInt32(trackHeader.Skip(36).Take(4).ToArray()); + track.StartOffset = BitConverter.ToUInt64(trackHeader.Skip(40).Take(8).ToArray(), 0); + track.Files = bc.ToInt32(trackHeader.Skip(48).Take(4).ToArray()); + track.FooterOffset = bc.ToInt32(trackHeader.Skip(52).Take(4).ToArray()); + + if (track.Mode == 0x02) + { + isDvd = true; + throw new MDSParseException("DVD Detected. Not currently supported!"); + } + + + // check for track extra block - this can probably be handled in a separate loop, + // but I'll just store the current stream position then seek forward to the extra block for this track + Int64 currPos = stream.Position; + + // Only CDs have extra blocks - for DVDs ExtraOffset = track length + if (track.ExtraOffset > 0 && !isDvd) + { + byte[] extHeader = new byte[8]; + stream.Seek(track.ExtraOffset, SeekOrigin.Begin); + stream.Read(extHeader, 0, 8); + track.ExtraBlock.Pregap = bc.ToInt32(extHeader.Take(4).ToArray()); + track.ExtraBlock.Sectors = bc.ToInt32(extHeader.Skip(4).Take(4).ToArray()); + stream.Seek(currPos, SeekOrigin.Begin); + } + else if (isDvd == true) + { + track.ExtraBlock.Sectors = track.ExtraOffset; + } + + // read the footer/filename block for this track + currPos = stream.Position; + long numOfFilenames = track.Files; + for (long fi = 1; fi <= numOfFilenames; fi++) + { + // skip leadin/out info tracks + if (track.FooterOffset == 0) + continue; + + byte[] foot = new byte[16]; + stream.Seek(track.FooterOffset, SeekOrigin.Begin); + stream.Read(foot, 0, 16); + + AFooter f = new AFooter(); + f.FilenameOffset = bc.ToInt32(foot.Take(4).ToArray()); + f.WideChar = bc.ToInt32(foot.Skip(4).Take(4).ToArray()); + track.FooterBlocks.Add(f); + track.FooterBlocks = track.FooterBlocks.Distinct().ToList(); + + // parse the filename string + string fileName = "*.mdf"; + if (f.FilenameOffset > 0) + { + // filename offset is present + stream.Seek(f.FilenameOffset, SeekOrigin.Begin); + byte[] fname; + + if (numOfFilenames == 1) + { + if (aFile.Header.DPMOffset == 0) + { + // filename is in the remaining space to EOF + fname = new byte[stream.Length - stream.Position]; + } + else + { + // filename is in the remaining space to EOF + dpm offset + fname = new byte[aFile.Header.DPMOffset - stream.Position]; + } + } + + else + { + // looks like each filename string is 6 bytes with a trailing \0 + fname = new byte[6]; + } + + + // read the filename + stream.Read(fname, 0, fname.Length); + + // if widechar is 1 filename is stored using 16-bit, otherwise 8-bit is used + if (f.WideChar == 1) + fileName = Encoding.Unicode.GetString(fname).TrimEnd('\0'); + else + fileName = Encoding.Default.GetString(fname).TrimEnd('\0'); + } + + else + { + // assume an MDF file with the same name as the MDS + } + + string dir = Path.GetDirectoryName(aFile.MDSPath); + + if (f.FilenameOffset == 0 || + string.Compare(fileName, "*.mdf", StringComparison.InvariantCultureIgnoreCase) == 0) + { + fileName = dir + @"\" + Path.GetFileNameWithoutExtension(aFile.MDSPath) + ".mdf"; + } + else + { + fileName = dir + @"\" + fileName; + } + + track.ImageFileNamePaths.Add(fileName); + track.ImageFileNamePaths = track.ImageFileNamePaths.Distinct().ToList(); + } + + stream.Position = currPos; + + + aTracks.Add(track.Point, track); + aFile.Tracks.Add(track); + + if (footerOffset == 0) + footerOffset = track.FooterOffset; + } + } + + + // build custom session object + aFile.ParsedSession = new List(); + foreach (var s in aSessions.Values) + { + Session session = new Session(); + ATrack startTrack; + ATrack endTrack; + + if (!aTracks.TryGetValue(s.FirstTrack, out startTrack)) + { + break; + } + + if (!aTracks.TryGetValue(s.LastTrack, out endTrack)) + { + break; + } + + session.StartSector = startTrack.PLBA; + session.StartTrack = s.FirstTrack; + session.SessionSequence = s.SessionNumber; + session.EndSector = endTrack.PLBA + endTrack.ExtraBlock.Sectors - 1; + session.EndTrack = s.LastTrack; + + aFile.ParsedSession.Add(session); + } + + // now build the TOC object + foreach (var se in aFile.ParsedSession) + { + // get the first and last tracks + int sTrack = se.StartTrack; + int eTrack = se.EndTrack; + + // get list of all tracks from aTracks for this session + var tracks = (from a in aTracks.Values + where a.TrackNo >= sTrack || a.TrackNo <= eTrack + orderby a.TrackNo + select a).ToList(); + + // create the TOC entries + foreach (var t in tracks) + { + ATOCEntry toc = new ATOCEntry(t.Point); + toc.ADR_Control = t.ADR_Control; + toc.AFrame = t.AFrame; + toc.AMin = t.AMin; + toc.ASec = t.ASec; + toc.EntryNum = t.TrackNo; + toc.PFrame = t.PFrame; + toc.PLBA = Convert.ToInt32(t.PLBA); + toc.PMin = t.PMin; + toc.Point = t.Point; + toc.PSec = t.PSec; + toc.SectorSize = t.SectorSize; + toc.Zero = t.Zero; + toc.TrackOffset = Convert.ToInt64(t.StartOffset); + toc.Session = se.SessionSequence; + toc.ImageFileNamePaths = t.ImageFileNamePaths; + toc.ExtraBlock = t.ExtraBlock; + toc.BlobIndex = t.BlobIndex; + aFile.TOCEntries.Add(toc); + } + + } + + return aFile; + } + + /// + /// Custom session object + /// + public class Session + { + public long StartSector; + public int StartTrack; + public int SessionSequence; + public long EndSector; + public int EndTrack; + } + + + public class MDSParseException : Exception + { + public MDSParseException(string message) : base(message) { } + } + + + public class LoadResults + { + public List RawTOCEntries; + public AFile ParsedMDSFile; + public bool Valid; + public Exception FailureException; + public string MdsPath; + } + + public static LoadResults LoadMDSPath(string path) + { + LoadResults ret = new LoadResults(); + ret.MdsPath = path; + //ret.MdfPath = Path.ChangeExtension(path, ".mdf"); + try + { + if (!File.Exists(path)) throw new MDSParseException("Malformed MDS format: nonexistent MDS file!"); + + AFile mdsf; + using (var infMDS = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) + mdsf = new MDS_Format().Parse(infMDS); + + ret.ParsedMDSFile = mdsf; + + ret.Valid = true; + } + catch (MDSParseException ex) + { + ret.FailureException = ex; + } + + return ret; + } + + Dictionary MountBlobs(AFile mdsf, Disc disc) + { + Dictionary BlobIndex = new Dictionary(); + + int count = 0; + foreach (var track in mdsf.Tracks) + { + foreach (var file in track.ImageFileNamePaths.Distinct()) + { + if (!File.Exists(file)) + throw new MDSParseException("Malformed MDS format: nonexistent image file: " + file); + + IBlob mdfBlob = null; + long mdfLen = -1; + + //mount the file + if (mdfBlob == null) + { + var mdfFile = new Disc.Blob_RawFile() { PhysicalPath = file }; + mdfLen = mdfFile.Length; + mdfBlob = mdfFile; + } + + bool dupe = false; + foreach (var re in disc.DisposableResources) + { + if (re.ToString() == mdfBlob.ToString()) + dupe = true; + } + + if (!dupe) + { + // wrap in zeropadadapter + disc.DisposableResources.Add(mdfBlob); + BlobIndex[count] = mdfBlob; + } + } + } + + return BlobIndex; + } + + RawTOCEntry EmitRawTOCEntry(ATOCEntry entry) + { + BCD2 tno, ino; + + //this should actually be zero. im not sure if this is stored as BCD2 or not + tno = BCD2.FromDecimal(entry.TrackNo); + + //these are special values.. I think, taken from this: + //http://www.staff.uni-mainz.de/tacke/scsi/SCSI2-14.html + //the CCD will contain Points as decimal values except for these specially converted decimal values which should stay as BCD. + //Why couldn't they all be BCD? I don't know. I guess because BCD is inconvenient, but only A0 and friends have special meaning. It's confusing. + ino = BCD2.FromDecimal(entry.Point); + if (entry.Point == 0xA0) ino.BCDValue = 0xA0; + else if (entry.Point == 0xA1) ino.BCDValue = 0xA1; + else if (entry.Point == 0xA2) ino.BCDValue = 0xA2; + + // get ADR & Control from ADR_Control byte + byte adrc = Convert.ToByte(entry.ADR_Control); + var Control = adrc & 0x0F; + var ADR = adrc >> 4; + + var q = new SubchannelQ + { + q_status = SubchannelQ.ComputeStatus(ADR, (EControlQ)(Control & 0xF)), + q_tno = tno, + q_index = ino, + min = BCD2.FromDecimal(entry.AMin), + sec = BCD2.FromDecimal(entry.ASec), + frame = BCD2.FromDecimal(entry.AFrame), + zero = (byte)entry.Zero, + ap_min = BCD2.FromDecimal(entry.PMin), + ap_sec = BCD2.FromDecimal(entry.PSec), + ap_frame = BCD2.FromDecimal(entry.PFrame), + q_crc = 0, //meaningless + }; + + return new RawTOCEntry { QData = q }; + } + + + /// + /// Loads a MDS at the specified path to a Disc object + /// + public Disc LoadMDSToDisc(string mdsPath, DiscMountPolicy IN_DiscMountPolicy) + { + var loadResults = LoadMDSPath(mdsPath); + if (!loadResults.Valid) + throw loadResults.FailureException; + + Disc disc = new Disc(); + + // load all blobs + Dictionary BlobIndex = MountBlobs(loadResults.ParsedMDSFile, disc); + + var mdsf = loadResults.ParsedMDSFile; + + //generate DiscTOCRaw items from the ones specified in the MDS file + disc.RawTOCEntries = new List(); + foreach (var entry in mdsf.TOCEntries) + { + disc.RawTOCEntries.Add(EmitRawTOCEntry(entry)); + } + + //analyze the RAWTocEntries to figure out what type of track track 1 is + var tocSynth = new Synthesize_DiscTOC_From_RawTOCEntries_Job() { Entries = disc.RawTOCEntries }; + tocSynth.Run(); + + // now build the sectors + int currBlobIndex = 0; + foreach (var session in mdsf.ParsedSession) + { + for (int i = session.StartTrack; i <= session.EndTrack; i++) + { + int relMSF = -1; + + var track = mdsf.TOCEntries.Where(t => t.Point == i).FirstOrDefault(); + if (track == null) + break; + + // ignore the info entries + if (track.Point == 0xA0 || + track.Point == 0xA1 || + track.Point == 0xA2) + { + continue; + } + + // get the blob(s) for this track + // its probably a safe assumption that there will be only one blob per track, + // but i'm still not 100% sure on this + var tr = (from a in mdsf.TOCEntries + where a.Point == i + select a).FirstOrDefault(); + + if (tr == null) + throw new MDSParseException("BLOB Error!"); + + List blobstrings = new List(); + foreach (var t in tr.ImageFileNamePaths) + { + if (!blobstrings.Contains(t)) + blobstrings.Add(t); + } + + var tBlobs = (from a in tr.ImageFileNamePaths + select a).ToList(); + + if (tBlobs.Count < 1) + throw new MDSParseException("BLOB Error!"); + + // is the currBlob valid for this track, or do we need to increment? + string bString = tBlobs.First(); + + IBlob mdfBlob = null; + + // check for track pregap and create if neccessary + // this is specified in the track extras block + if (track.ExtraBlock.Pregap > 0) + { + CUE.CueTrackType pregapTrackType = CUE.CueTrackType.Audio; + if (tocSynth.Result.TOCItems[1].IsData) + { + if (tocSynth.Result.Session1Format == SessionFormat.Type20_CDXA) + pregapTrackType = CUE.CueTrackType.Mode2_2352; + else if (tocSynth.Result.Session1Format == SessionFormat.Type10_CDI) + pregapTrackType = CUE.CueTrackType.CDI_2352; + else if (tocSynth.Result.Session1Format == SessionFormat.Type00_CDROM_CDDA) + pregapTrackType = CUE.CueTrackType.Mode1_2352; + } + for (int pre = 0; pre < track.ExtraBlock.Pregap; pre++) + { + relMSF++; + + var ss_gap = new CUE.SS_Gap() + { + Policy = IN_DiscMountPolicy, + TrackType = pregapTrackType + }; + disc._Sectors.Add(ss_gap); + + int qRelMSF = pre - Convert.ToInt32(track.ExtraBlock.Pregap); + + //tweak relMSF due to ambiguity/contradiction in yellowbook docs + if (!IN_DiscMountPolicy.CUE_PregapContradictionModeA) + qRelMSF++; + + //setup subQ + byte ADR = 1; //absent some kind of policy for how to set it, this is a safe assumption: + ss_gap.sq.SetStatus(ADR, tocSynth.Result.TOCItems[1].Control); + ss_gap.sq.q_tno = BCD2.FromDecimal(1); + ss_gap.sq.q_index = BCD2.FromDecimal(0); + ss_gap.sq.AP_Timestamp = pre; + ss_gap.sq.Timestamp = qRelMSF; + + //setup subP + ss_gap.Pause = true; + } + // pregap processing completed + } + + + + // create track sectors + long currBlobOffset = track.TrackOffset; + for (long sector = session.StartSector; sector <= session.EndSector; sector++) + { + CUE.SS_Base sBase = null; + + // get the current blob from the BlobIndex + Disc.Blob_RawFile currBlob = BlobIndex[currBlobIndex] as Disc.Blob_RawFile; + long currBlobLength = currBlob.Length; + long currBlobPosition = sector; + if (currBlobPosition == currBlobLength) + currBlobIndex++; + mdfBlob = disc.DisposableResources[currBlobIndex] as Disc.Blob_RawFile; + + int userSector = 2048; + switch (track.SectorSize) + { + case 2448: + sBase = new CUE.SS_2352() + { + Policy = IN_DiscMountPolicy + }; + userSector = 2352; + break; + case 2048: + default: + sBase = new CUE.SS_Mode1_2048() + { + Policy = IN_DiscMountPolicy + }; + userSector = 2048; + break; + + //throw new Exception("Not supported: Sector Size " + track.SectorSize); + } + + // configure blob + sBase.Blob = mdfBlob; + sBase.BlobOffset = currBlobOffset; + + currBlobOffset += track.SectorSize; // userSector; + + // add subchannel data + relMSF++; + BCD2 tno, ino; + + //this should actually be zero. im not sure if this is stored as BCD2 or not + tno = BCD2.FromDecimal(track.TrackNo); + + //these are special values.. I think, taken from this: + //http://www.staff.uni-mainz.de/tacke/scsi/SCSI2-14.html + //the CCD will contain Points as decimal values except for these specially converted decimal values which should stay as BCD. + //Why couldn't they all be BCD? I don't know. I guess because BCD is inconvenient, but only A0 and friends have special meaning. It's confusing. + ino = BCD2.FromDecimal(track.Point); + if (track.Point == 0xA0) ino.BCDValue = 0xA0; + else if (track.Point == 0xA1) ino.BCDValue = 0xA1; + else if (track.Point == 0xA2) ino.BCDValue = 0xA2; + + // get ADR & Control from ADR_Control byte + byte adrc = Convert.ToByte(track.ADR_Control); + var Control = adrc & 0x0F; + var ADR = adrc >> 4; + + var q = new SubchannelQ + { + q_status = SubchannelQ.ComputeStatus(ADR, (EControlQ)(Control & 0xF)), + q_tno = BCD2.FromDecimal(track.Point), + q_index = ino, + AP_Timestamp = disc._Sectors.Count, + Timestamp = relMSF - Convert.ToInt32(track.ExtraBlock.Pregap) + }; + + sBase.sq = q; + + disc._Sectors.Add(sBase); + + } + } + } + + return disc; + } + + } //class MDS_Format +} + + diff --git a/BizHawk.Emulation.DiscSystem/DiscIdentifier.cs b/BizHawk.Emulation.DiscSystem/DiscIdentifier.cs index a9add9cf4e..e4fe3c2f74 100644 --- a/BizHawk.Emulation.DiscSystem/DiscIdentifier.cs +++ b/BizHawk.Emulation.DiscSystem/DiscIdentifier.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; //disc type identification logic @@ -8,7 +9,7 @@ namespace BizHawk.Emulation.DiscSystem public enum DiscType { /// - /// Disc contains audio in track 1. Nothing more can readily be determined + /// Disc contains audio in track 1. This may be a PCFX or PCECD game, but if not it is assumed AudioDisc /// AudioDisc, @@ -38,7 +39,7 @@ namespace BizHawk.Emulation.DiscSystem SegaSaturn, /// - /// Its not clear whether we can ever have enough info to ID a turboCD disc (we're using hashes) + /// PC Engine CD /// TurboCD, @@ -50,7 +51,47 @@ namespace BizHawk.Emulation.DiscSystem /// /// By NEC. /// - PCFX + PCFX, + + /// + /// By Panasonic + /// + Panasonic3DO, + + /// + /// Philips + /// + CDi, + + /// + /// Nintendo Gamecube + /// + GameCube, + + /// + /// Nintendo Wii + /// + Wii, + + /// + /// SNK NeoGeo + /// + NeoGeoCD, + + /// + /// Bandai Playdia + /// + Playdia, + + /// + /// Either CDTV or CD32 (I havent found a reliable way of distinguishing between them yet -asni) + /// + Amiga, + + /// + /// Sega Dreamcast + /// + Dreamcast } public class DiscIdentifier @@ -76,24 +117,26 @@ namespace BizHawk.Emulation.DiscSystem /// public DiscType DetectDiscType() { - // not fully tested yet + // PCFX & TurboCD sometimes (if not alltimes) have audio on track 1 - run these before the AudioDisc detection (asni) if (DetectPCFX()) return DiscType.PCFX; - //check track 1's data type. if it's an audio track, further data-track testing is useless - //furthermore, it's probably senseless (no binary data there to read) - //NOTE: PCE-CD detection goes through here (no good way to detect PCE cd) - if (!_disc.TOC.TOCItems[1].IsData) + if (DetectTurboCD()) + return DiscType.TurboCD; + + //check track 1's data type. if it's an audio track, further data-track testing is useless + //furthermore, it's probably senseless (no binary data there to read) + if (!_disc.TOC.TOCItems[1].IsData) return DiscType.AudioDisc; // if (_dsr.ReadLBA_Mode(_disc.TOC.TOCItems[1].LBA) == 0) // return DiscType.AudioDisc; // sega doesnt put anything identifying in the cdfs volume info. but its consistent about putting its own header here in sector 0 + //asni - this isn't strictly true - SystemIdentifier in volume descriptor has been observed on occasion (see below) if (DetectSegaSaturn()) return DiscType.SegaSaturn; - // not fully tested yet if (DetectMegaCD()) return DiscType.MegaCD; @@ -102,31 +145,79 @@ namespace BizHawk.Emulation.DiscSystem if (DetectPSX()) return DiscType.SonyPSX; - //we dont know how to detect TurboCD. - //an emulator frontend will likely just guess TurboCD if the disc is UnknownFormat - //(we can also have a gameDB!) + if (Detect3DO()) + return DiscType.Panasonic3DO; - var discView = EDiscStreamView.DiscStreamView_Mode1_2048; + if (DetectCDi()) + return DiscType.CDi; + + if (DetectGameCube()) + return DiscType.GameCube; + + if (DetectWii()) + return DiscType.Wii; + + var discView = EDiscStreamView.DiscStreamView_Mode1_2048; if (_disc.TOC.Session1Format == SessionFormat.Type20_CDXA) discView = EDiscStreamView.DiscStreamView_Mode2_Form1_2048; var iso = new ISOFile(); bool isIso = iso.Parse(new DiscStream(_disc, discView, 0)); + if (!isIso) + { + // its much quicker to detect dreamcast from ISO data. Only do this if ISO is not detected + if (DetectDreamcast()) + return DiscType.Dreamcast; + } + + //*** asni - 20171011 - Suggestion: move this to the beginning of the DetectDiscType() method before any longer running lookups? + //its a cheap win for a lot of systems, but ONLY if the iso.Parse() method is quick running (might have to time it) if (isIso) { var appId = System.Text.Encoding.ASCII.GetString(iso.VolumeDescriptors[0].ApplicationIdentifier).TrimEnd('\0', ' '); + var sysId = System.Text.Encoding.ASCII.GetString(iso.VolumeDescriptors[0].SystemIdentifier).TrimEnd('\0', ' '); - //for example: PSX magical drop F (JP SLPS_02337) doesn't have the correct iso PVD fields - //but, some PSX games (junky rips) don't have the 'licensed by string' so we'll hope they get caught here - if (appId == "PLAYSTATION") + //for example: PSX magical drop F (JP SLPS_02337) doesn't have the correct iso PVD fields + //but, some PSX games (junky rips) don't have the 'licensed by string' so we'll hope they get caught here + if (appId == "PLAYSTATION") return DiscType.SonyPSX; if (appId == "PSP GAME") return DiscType.SonyPSP; + // in case the appId is not set correctly... + if (iso.Root.Children.Where(a => a.Key == "PSP_GAME").FirstOrDefault().Value as ISODirectoryNode != null) + return DiscType.SonyPSP; - return DiscType.UnknownCDFS; - } + if (sysId == "SEGA SEGASATURN") + return DiscType.SegaSaturn; + + if (sysId.Contains("SEGAKATANA")) + return DiscType.Dreamcast; + + if (sysId == "MEGA_CD") + return DiscType.MegaCD; + + if (sysId == "ASAHI-CDV") + return DiscType.Playdia; + + if (sysId == "CDTV" || sysId == "AMIGA") + return DiscType.Amiga; + foreach (var f in iso.Root.Children) + if (f.Key.ToLower().Contains("cd32")) + return DiscType.Amiga; + + // NeoGeoCD Check + var absTxt = iso.Root.Children.Where(a => a.Key.Contains("ABS.TXT")).ToList(); + if (absTxt.Count > 0) + { + if (SectorContains("abstracted by snk", Convert.ToInt32(absTxt.First().Value.Offset))) + return DiscType.NeoGeoCD; + } + + + return DiscType.UnknownCDFS; + } return DiscType.UnknownFormat; } @@ -165,13 +256,87 @@ namespace BizHawk.Emulation.DiscSystem t++) { var track = _disc.TOC.TOCItems[t]; - if (track.IsData && StringAt("PC-FX:Hu_CD-ROM", 0, track.LBA)) + //asni - this search is less specific - turns out there are discs where 'Hu:' is not present + if (track.IsData && SectorContains("pc-fx", track.LBA)) return true; } return false; } - private byte[] ReadSectorCached(int lba) + //asni 20171011 - this ONLY works if a valid cuefile/ccd is passed into DiscIdentifier. + //if an .iso is presented, the internally manufactured cue data does not work - possibly something to do with + //track 01 being Audio. Not tested, but presumably PCFX has the same issue + bool DetectTurboCD() + { + var toc = _disc.TOC; + for (int t = toc.FirstRecordedTrackNumber; + t <= toc.LastRecordedTrackNumber; + t++) + { + var track = _disc.TOC.TOCItems[t]; + //asni - pcfx games also contain the 'PC Engine' string + if ((track.IsData && SectorContains("pc engine", track.LBA + 1) && !SectorContains("pc-fx", track.LBA + 1))) + return true; + } + return false; + } + + bool Detect3DO() + { + var toc = _disc.TOC; + for (int t = toc.FirstRecordedTrackNumber; + t <= toc.LastRecordedTrackNumber; + t++) + { + var track = _disc.TOC.TOCItems[t]; + if (track.IsData && SectorContains("iamaduckiamaduck", track.LBA)) + return true; + } + return false; + } + + //asni - slightly longer running than the others due to its brute-force nature. Should run later in the method + bool DetectDreamcast() + { + for (int i = 0; i < 1000; i++) + { + if (SectorContains("segakatana", i)) + return true; + } + + return false; + } + + bool DetectCDi() + { + return StringAt("CD-RTOS", 8, 16); + } + + bool DetectGameCube() + { + var data = ReadSectorCached(0); + if (data == null) return false; + byte[] magic = data.Skip(28).Take(4).ToArray(); + string hexString = ""; + foreach (var b in magic) + hexString += b.ToString("X2"); + + return hexString == "C2339F3D"; + } + + bool DetectWii() + { + var data = ReadSectorCached(0); + if (data == null) return false; + byte[] magic = data.Skip(24).Take(4).ToArray(); + string hexString = ""; + foreach (var b in magic) + hexString += b.ToString("X2"); + + return hexString == "5D1C9EA3"; + } + + private byte[] ReadSectorCached(int lba) { //read it if we dont have it cached //we wont be caching very much here, it's no big deal @@ -197,5 +362,12 @@ namespace BizHawk.Emulation.DiscSystem Buffer.BlockCopy(data, n, cmp2, 0, cmp.Length); return System.Linq.Enumerable.SequenceEqual(cmp, cmp2); } + + private bool SectorContains(string s, int lba = 0) + { + var data = ReadSectorCached(lba); + if (data == null) return false; + return System.Text.Encoding.ASCII.GetString(data).ToLower().Contains(s.ToLower()); + } } } \ No newline at end of file diff --git a/BizHawk.Emulation.DiscSystem/DiscMountJob.cs b/BizHawk.Emulation.DiscSystem/DiscMountJob.cs index dab08a7dbf..7282d00f74 100644 --- a/BizHawk.Emulation.DiscSystem/DiscMountJob.cs +++ b/BizHawk.Emulation.DiscSystem/DiscMountJob.cs @@ -187,6 +187,11 @@ namespace BizHawk.Emulation.DiscSystem CCD_Format ccdLoader = new CCD_Format(); OUT_Disc = ccdLoader.LoadCCDToDisc(IN_FromPath, IN_DiscMountPolicy); } + else if (ext == ".mds") + { + MDS_Format mdsLoader = new MDS_Format(); + OUT_Disc = mdsLoader.LoadMDSToDisc(IN_FromPath, IN_DiscMountPolicy); + } DONE: diff --git a/BizHawk.sln.DotSettings b/BizHawk.sln.DotSettings index ad7cb00825..e447905302 100644 --- a/BizHawk.sln.DotSettings +++ b/BizHawk.sln.DotSettings @@ -3,6 +3,8 @@ True ExplicitlyExcluded DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW DO_NOT_SHOW DO_NOT_SHOW DO_NOT_SHOW diff --git a/libmupen64plus/mupen64plus-core/src/r4300/pure_interp.c b/libmupen64plus/mupen64plus-core/src/r4300/pure_interp.c index c9b7e8ef81..e93b90600e 100644 --- a/libmupen64plus/mupen64plus-core/src/r4300/pure_interp.c +++ b/libmupen64plus/mupen64plus-core/src/r4300/pure_interp.c @@ -60,6 +60,7 @@ static void prefetch(void); interp_PC.addr += 4; \ delay_slot=1; \ prefetch(); \ + TRACECB(); \ PC->ops(); \ update_count(); \ delay_slot=0; \ diff --git a/libmupen64plus/mupen64plus-core/src/r4300/r4300.c b/libmupen64plus/mupen64plus-core/src/r4300/r4300.c index f881ce0e0d..832829ec87 100644 --- a/libmupen64plus/mupen64plus-core/src/r4300/r4300.c +++ b/libmupen64plus/mupen64plus-core/src/r4300/r4300.c @@ -94,6 +94,7 @@ int rounding_mode = 0x33F, trunc_mode = 0xF3F, round_mode = 0x33F, PC++; \ delay_slot=1; \ UPDATE_DEBUGGER(); \ + TRACECB(); \ PC->ops(); \ update_count(); \ delay_slot=0; \ @@ -126,6 +127,7 @@ int rounding_mode = 0x33F, trunc_mode = 0xF3F, round_mode = 0x33F, PC++; \ delay_slot=1; \ UPDATE_DEBUGGER(); \ + TRACECB(); \ PC->ops(); \ update_count(); \ delay_slot=0; \ diff --git a/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.sln b/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.sln index 7ef3faea38..ba5b475069 100644 --- a/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.sln +++ b/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.sln @@ -6,13 +6,19 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|Win32.ActiveCfg = Debug|Win32 - {A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|Win32.Build.0 = Debug|Win32 + {A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|Win32.ActiveCfg = Debug|x64 + {A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|Win32.Build.0 = Debug|x64 + {A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|x64.ActiveCfg = Debug|x64 + {A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|x64.Build.0 = Debug|x64 {A4D13408-A794-4199-8FC7-4A9A32505005}.Release|Win32.ActiveCfg = Release|Win32 {A4D13408-A794-4199-8FC7-4A9A32505005}.Release|Win32.Build.0 = Release|Win32 + {A4D13408-A794-4199-8FC7-4A9A32505005}.Release|x64.ActiveCfg = Release|x64 + {A4D13408-A794-4199-8FC7-4A9A32505005}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.vcxproj b/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.vcxproj index 35d3025ae6..26e5fdb29a 100644 --- a/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.vcxproj +++ b/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {A4D13408-A794-4199-8FC7-4A9A32505005} @@ -23,34 +31,64 @@ true v100 + + DynamicLibrary + false + MultiByte + true + v100 + DynamicLibrary false MultiByte v100 + + DynamicLibrary + false + MultiByte + v100 + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 $(SolutionDir)..\..\..\..\output\dll\ + $(SolutionDir)..\..\..\..\output\dll\ $(Configuration)\ + $(Configuration)\ true + true $(SolutionDir)..\..\..\..\output\dll\ + $(SolutionDir)..\..\..\..\output\dll\ $(Configuration)\ + $(Configuration)\ false + false true + true F:\Code\Third Party\boost;$(IncludePath) + F:\Code\Third Party\boost;$(IncludePath) F:\Code\Third Party\boost\stage\lib;$(LibraryPath) + F:\Code\Third Party\boost\stage\lib;$(LibraryPath) @@ -98,6 +136,50 @@ .\Debug/n64Glide.bsc + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\Debug/n64Glide.tlb + + + + + Disabled + ..\..\..\mupen64plus-win32-deps\boost-1.57.0\;..\..\..\mupen64plus-core\src\api;..\..\src\Glide64;..\..\src\Glide64\inc;..\..\src\GlideHQ;..\..\src\GlideHQ\tc-1.1+;..\..\src\Glitch64;..\..\src\Glitch64\inc;..\..\..\mupen64plus-win32-deps\SDL-1.2.15\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.8\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.18\include;%(AdditionalIncludeDirectories) + _DEBUG;NO_ASM;_GLIBCXX_HAVE_BROKEN_VSWPRINTF;NO_FILTER_THREAD;_VARIADIC_MAX=10;_CRT_SECURE_NO_WARNINGS;__MSC__;WIN32;%(PreprocessorDefinitions) + Async + EnableFastChecks + MultiThreadedDebugDLL + .\Debug/n64Glide.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level3 + true + ProgramDatabase + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + SDL.lib;zlib.lib;libpng16.lib;opengl32.lib;winmm.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ..\..\..\deps\libs;..\..\..\mupen64plus-win32-deps\libpng-1.6.18\lib\x64;..\..\..\mupen64plus-win32-deps\zlib-1.2.8\lib\x64;..\..\..\mupen64plus-win32-deps\SDL-1.2.15\lib\x64;%(AdditionalLibraryDirectories) + false + true + $(TargetDir)$(TargetName).pdb + .\Debug/Glide64.lib + + + true + .\Debug/n64Glide.bsc + + NDEBUG;%(PreprocessorDefinitions) @@ -157,122 +239,220 @@ copy ..\..\data\* "$(OutDir)" + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\Release/n64Glide.tlb + + + + + MaxSpeed + OnlyExplicitInline + true + Speed + false + ..\..\..\mupen64plus-win32-deps\boost-1.57.0\;..\..\..\mupen64plus-core\src\api;..\..\src\Glide64;..\..\src\Glide64\inc;..\..\src\GlideHQ;..\..\src\GlideHQ\tc-1.1+;..\..\src\Glitch64;..\..\src\Glitch64\inc;..\..\..\mupen64plus-win32-deps\SDL-1.2.15\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.8\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.18\include;%(AdditionalIncludeDirectories) + NO_ASM;_GLIBCXX_HAVE_BROKEN_VSWPRINTF;NO_FILTER_THREAD;_VARIADIC_MAX=10;_CRT_SECURE_NO_WARNINGS;__MSC__;WIN32;__VISUALC__;%(PreprocessorDefinitions) + true + Async + MultiThreadedDLL + true + NotSet + .\Release/n64Glide.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + SDL.lib;zlib.lib;libpng16.lib;opengl32.lib;winmm.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ..\..\..\deps\libs;..\..\..\mupen64plus-win32-deps\libpng-1.6.18\lib\x64;..\..\..\mupen64plus-win32-deps\zlib-1.2.8\lib\x64;..\..\..\mupen64plus-win32-deps\SDL-1.2.15\lib\x64;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).pdb + + + Windows + true + /pdbaltpath:%_PDB% %(AdditionalOptions) + + + true + .\Release/n64Glide.bsc + + + true + + + Copying shared data and libraries to build directory... + copy ..\..\data\* "$(OutDir)" + + false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false .\Release/%(Filename)1.obj + .\Release/%(Filename)1.obj $(IntDir)%(Filename)1.xdc + $(IntDir)%(Filename)1.xdc false + false false + false diff --git a/output/dll/libdarm.dll b/output/dll/libdarm.dll new file mode 100644 index 0000000000..6a16a2bc5f Binary files /dev/null and b/output/dll/libdarm.dll differ diff --git a/output/dll/libsnes.wbx.gz b/output/dll/libsnes.wbx.gz index 4877d7e2ed..67a8e75a6a 100644 Binary files a/output/dll/libsnes.wbx.gz and b/output/dll/libsnes.wbx.gz differ diff --git a/output/dll/mupen64plus-video-glide64mk2.dll b/output/dll/mupen64plus-video-glide64mk2.dll index da44f01514..36989cb4d3 100644 Binary files a/output/dll/mupen64plus-video-glide64mk2.dll and b/output/dll/mupen64plus-video-glide64mk2.dll differ diff --git a/output/dll/mupen64plus.dll b/output/dll/mupen64plus.dll index d4f49ceb97..a7c7facbda 100644 Binary files a/output/dll/mupen64plus.dll and b/output/dll/mupen64plus.dll differ diff --git a/output/dll/octoshock.dll b/output/dll/octoshock.dll index 292d2536eb..3e80c9454e 100644 Binary files a/output/dll/octoshock.dll and b/output/dll/octoshock.dll differ diff --git a/output/dll/sameboy.wbx.gz b/output/dll/sameboy.wbx.gz index 451322c759..9233cc62d7 100644 Binary files a/output/dll/sameboy.wbx.gz and b/output/dll/sameboy.wbx.gz differ diff --git a/psx/octoshock/psx/input/memcard.cpp b/psx/octoshock/psx/input/memcard.cpp index 814e68d117..b98fa9de58 100644 --- a/psx/octoshock/psx/input/memcard.cpp +++ b/psx/octoshock/psx/input/memcard.cpp @@ -193,7 +193,9 @@ void InputDevice_Memcard::SyncState(bool isReader, EW::NewState *ns) //HOWEVER - we clear the dirty flag. that way, a user wont accidentally `clobber` his savestates when loading a state. //instead, the state will only be dirtied when the game actually modifies the contents NSS(card_data); - dirty_count = 0; + + if(isReader) + dirty_count = 0; } // //int InputDevice_Memcard::StateAction(StateMem* sm, int load, int data_only, const char* section_name) diff --git a/waterbox/libsnes/bsnes/snes/smp/smp.hpp b/waterbox/libsnes/bsnes/snes/smp/smp.hpp index cbaa81affc..2923092c38 100644 --- a/waterbox/libsnes/bsnes/snes/smp/smp.hpp +++ b/waterbox/libsnes/bsnes/snes/smp/smp.hpp @@ -18,6 +18,12 @@ struct SMP : public Processor, public SMPcore { ~SMP(); void initialize(); + struct Debugger { + hook op_exec; + hook op_read; + hook op_write; + } debugger; + privileged: #include "memory/memory.hpp" #include "timing/timing.hpp" @@ -50,12 +56,6 @@ privileged: static void Enter(); friend class SMPcore; - - struct Debugger { - hook op_exec; - hook op_read; - hook op_write; - } debugger; }; extern SMP smp; diff --git a/waterbox/libsnes/bsnes/target-libsnes/libsnes_pwrap.cpp b/waterbox/libsnes/bsnes/target-libsnes/libsnes_pwrap.cpp index ed230e6cb8..55d01886f0 100644 --- a/waterbox/libsnes/bsnes/target-libsnes/libsnes_pwrap.cpp +++ b/waterbox/libsnes/bsnes/target-libsnes/libsnes_pwrap.cpp @@ -47,6 +47,9 @@ enum eMessage : int32 eMessage_QUERY_state_hook_write, eMessage_QUERY_state_hook_nmi, eMessage_QUERY_state_hook_irq, + eMessage_QUERY_state_hook_exec_smp, + eMessage_QUERY_state_hook_read_smp, + eMessage_QUERY_state_hook_write_smp, eMessage_QUERY_enable_trace, eMessage_QUERY_enable_scanline, eMessage_QUERY_enable_audio, @@ -86,6 +89,9 @@ enum eMessage : int32 eMessage_BRK_hook_write, eMessage_BRK_hook_nmi, eMessage_BRK_hook_irq, + eMessage_BRK_hook_exec_smp, + eMessage_BRK_hook_read_smp, + eMessage_BRK_hook_write_smp, eMessage_BRK_scanlineStart, }; @@ -348,6 +354,25 @@ static void debug_op_irq() BREAK(eMessage_BRK_hook_irq); } +static void debug_op_exec_smp(uint24 addr) +{ + comm.addr = addr; + BREAK(eMessage_BRK_hook_exec_smp); +} + +static void debug_op_read_smp(uint24 addr) +{ + comm.addr = addr; + BREAK(eMessage_BRK_hook_read_smp); +} + +static void debug_op_write_smp(uint24 addr, uint8 value) +{ + comm.addr = addr; + comm.value = value; + BREAK(eMessage_BRK_hook_write_smp); +} + void pwrap_init() { //bsnes's interface initialization calls into this after initializing itself, so we can get a chance to mod it for pwrap functionalities @@ -455,6 +480,15 @@ void QUERY_state_hook_nmi() { void QUERY_state_hook_irq() { SNES::cpu.debugger.op_irq = comm.value ? debug_op_irq : hook(); } +void QUERY_state_hook_exec_smp() { + SNES::smp.debugger.op_exec = comm.value ? debug_op_exec_smp : hook(); +} +void QUERY_state_hook_read_smp() { + SNES::smp.debugger.op_read = comm.value ? debug_op_read_smp : hook(); +} +void QUERY_state_hook_write_smp() { + SNES::smp.debugger.op_write = comm.value ? debug_op_write_smp : hook(); +} void QUERY_state_enable_trace() { snes_set_trace_callback(comm.value, snes_trace); } @@ -535,6 +569,9 @@ const Action kHandlers_QUERY[] = { QUERY_state_hook_exec, //eMessage_QUERY_state_hook_exec QUERY_state_hook_read, //eMessage_QUERY_state_hook_read QUERY_state_hook_write, //eMessage_QUERY_state_hook_write + QUERY_state_hook_exec_smp, //eMessage_QUERY_state_hook_exec_smp + QUERY_state_hook_read_smp, //eMessage_QUERY_state_hook_read_smp + QUERY_state_hook_write_smp, //eMessage_QUERY_state_hook_write_smp QUERY_state_hook_nmi, //eMessage_QUERY_state_hook_nmi QUERY_state_hook_irq, //eMessage_QUERY_state_hook_irq QUERY_state_enable_trace, //eMessage_QUERY_enable_trace TODO - consolidate enable flags diff --git a/waterbox/sameboy/sgb.c b/waterbox/sameboy/sgb.c index f4fb6af834..d08ff4ae8d 100644 --- a/waterbox/sameboy/sgb.c +++ b/waterbox/sameboy/sgb.c @@ -3,6 +3,7 @@ #include #include #include "snes_spc/spc.h" +#include "../emulibc/emulibc.h" #define utils_log printf @@ -76,13 +77,13 @@ typedef struct uint16_t tilemap[32 * 32]; // frame data - uint8_t frame[160 * 144]; // the most recent obtained full frame + uint8_t frame[160 * 144]; // the most recent obtained full frame uint32_t frozenframe[256 * 224]; // the most recent saved full frame (MASK_EN) - uint8_t attr[20 * 18]; // current attr map for the GB screen - uint8_t auxattr[45][20 * 18]; // 45 attr files + uint8_t attr[20 * 18]; // current attr map for the GB screen + uint8_t auxattr[45][20 * 18]; // 45 attr files // MASK_EN - uint8_t active_mask; // true if mask is currently being used + uint8_t active_mask; // true if mask is currently being used // audio SNES_SPC *spc; @@ -622,12 +623,15 @@ int sgb_init(const uint8_t *spc, int length) utils_log("SGB: Failed to load SPC\n"); return 0; } - + + // make a scratch buffer in a predictable (not stack) place because spc stores multiple pointers to it + // which is kind of nasty... + int16_t *sound_buffer = alloc_invisible(4096 * sizeof(int16_t)); + // the combination of the sameboy bootrom plus the built in SPC file we use means // that the SPC doesn't finish its init fast enough for donkey kong, which starts poking // data too early. it's just a combination of various HLE concerns not meshing... - int16_t sound_buffer[4096]; - spc_set_output(sgb.spc, sound_buffer, sizeof(sound_buffer) / sizeof(sound_buffer[0])); + spc_set_output(sgb.spc, sound_buffer, 4096); for (int i = 0; i < 240; i++) { spc_end_frame(sgb.spc, 35104); @@ -741,10 +745,10 @@ void sgb_set_controller_data(const uint8_t *buttons) memcpy(sgb.joypad_data, buttons, sizeof(sgb.joypad_data)); } -static void trn_sound(const uint8_t* data) +static void trn_sound(const uint8_t *data) { - const uint8_t* const dataend = data + 0x10000; - uint8_t* const dst = spc_get_ram(sgb.spc); + const uint8_t *const dataend = data + 0x10000; + uint8_t *const dst = spc_get_ram(sgb.spc); while (1) { @@ -771,7 +775,7 @@ static void trn_sound(const uint8_t* data) utils_log("TRN_SOUND dst overflow\n"); return; } - utils_log("TRN_SOUND addr %04x len %04x\n", addr, len); + utils_log("TRN_SOUND addr %04x len %04x\n", addr, len); memcpy(dst + addr, data, len); data += len; } @@ -1014,14 +1018,14 @@ void sgb_render_audio(uint64_t time, void (*callback)(int16_t l, int16_t r, uint else { utils_log("SPC: %02x %02x %02x %02x => %02x %02x %02x %02x\n", - spc_read_port(sgb.spc, 0, 0), - spc_read_port(sgb.spc, 0, 1), - spc_read_port(sgb.spc, 0, 2), - spc_read_port(sgb.spc, 0, 3), - sgb.sound_control[0], - sgb.sound_control[1], - sgb.sound_control[2], - sgb.sound_control[3]); + spc_read_port(sgb.spc, 0, 0), + spc_read_port(sgb.spc, 0, 1), + spc_read_port(sgb.spc, 0, 2), + spc_read_port(sgb.spc, 0, 3), + sgb.sound_control[0], + sgb.sound_control[1], + sgb.sound_control[2], + sgb.sound_control[3]); } for (int p = 0; p < 4; p++) {