diff --git a/.gitmodules b/.gitmodules index 39e4c1fa9a..082b322f45 100644 --- a/.gitmodules +++ b/.gitmodules @@ -40,6 +40,9 @@ [submodule "submodules/libfwunpack"] path = submodules/libfwunpack url = https://github.com/TASEmulators/fwunpack.git +[submodule "submodules/libemu83"] + path = submodules/libemu83 + url = https://github.com/CasualPokePlayer/Emu83.git [submodule "submodules/sameboy/libsameboy"] path = submodules/sameboy/libsameboy url = https://github.com/LIJI32/SameBoy.git diff --git a/Assets/dll/libemu83.dll b/Assets/dll/libemu83.dll new file mode 100644 index 0000000000..08876c9f21 Binary files /dev/null and b/Assets/dll/libemu83.dll differ diff --git a/Assets/dll/libemu83.so b/Assets/dll/libemu83.so new file mode 100644 index 0000000000..17999891f2 Binary files /dev/null and b/Assets/dll/libemu83.so differ diff --git a/src/BizHawk.Client.Common/RomLoader.cs b/src/BizHawk.Client.Common/RomLoader.cs index 032ddfa92d..176ee60719 100644 --- a/src/BizHawk.Client.Common/RomLoader.cs +++ b/src/BizHawk.Client.Common/RomLoader.cs @@ -805,7 +805,7 @@ namespace BizHawk.Client.Common public static readonly IReadOnlyCollection SNES = new[] { "smc", "sfc", "xml" }; - public static readonly IReadOnlyCollection TI83 = new[] { "rom" }; + public static readonly IReadOnlyCollection TI83 = new[] { "83g", "83l", "83p" }; public static readonly IReadOnlyCollection UZE = new[] { "uze" }; diff --git a/src/BizHawk.Client.Common/config/Config.cs b/src/BizHawk.Client.Common/config/Config.cs index 840fddfae3..a57874ede2 100644 --- a/src/BizHawk.Client.Common/config/Config.cs +++ b/src/BizHawk.Client.Common/config/Config.cs @@ -33,7 +33,9 @@ namespace BizHawk.Client.Common (new[] { VSystemID.Raw.GBL }, new[] { CoreNames.GambatteLink, CoreNames.GBHawkLink, CoreNames.GBHawkLink3x, CoreNames.GBHawkLink4x }), (new[] { VSystemID.Raw.PCE, VSystemID.Raw.PCECD, VSystemID.Raw.SGX }, - new[] { CoreNames.TurboNyma, CoreNames.HyperNyma, CoreNames.PceHawk }) + new[] { CoreNames.TurboNyma, CoreNames.HyperNyma, CoreNames.PceHawk }), + (new[] { VSystemID.Raw.TI83 }, + new[] { CoreNames.TI83Hawk, CoreNames.Emu83 }), }; public Config() @@ -322,6 +324,7 @@ namespace BizHawk.Client.Common [VSystemID.Raw.PCE] = CoreNames.TurboNyma, [VSystemID.Raw.PCECD] = CoreNames.TurboNyma, [VSystemID.Raw.SGX] = CoreNames.TurboNyma, + [VSystemID.Raw.TI83] = CoreNames.Emu83, }; public bool DontTryOtherCores { get; set; } diff --git a/src/BizHawk.Client.Common/movie/bk2/Bk2MnemonicLookup.cs b/src/BizHawk.Client.Common/movie/bk2/Bk2MnemonicLookup.cs index 5b564d3fcb..9ca435af63 100644 --- a/src/BizHawk.Client.Common/movie/bk2/Bk2MnemonicLookup.cs +++ b/src/BizHawk.Client.Common/movie/bk2/Bk2MnemonicLookup.cs @@ -282,7 +282,8 @@ namespace BizHawk.Client.Common ["MODE"] = 'O', ["DEL"] = 'D', ["COMMA"] = ',', - ["SIN"] = 'S' + ["SIN"] = 'S', + ["SEND"] = 'N', }, [VSystemID.Raw.C64] = new() { diff --git a/src/BizHawk.Client.EmuHawk/MainForm.Events.cs b/src/BizHawk.Client.EmuHawk/MainForm.Events.cs index 92ad4f38f6..84e24ed671 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -14,7 +14,7 @@ using BizHawk.Client.EmuHawk.ToolExtensions; using BizHawk.Common; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Atari.A7800Hawk; -using BizHawk.Emulation.Cores.Calculators; +using BizHawk.Emulation.Cores.Calculators.TI83; using BizHawk.Emulation.Cores.ColecoVision; using BizHawk.Emulation.Cores.Computers.AmstradCPC; using BizHawk.Emulation.Cores.Computers.AppleII; @@ -1512,7 +1512,7 @@ namespace BizHawk.Client.EmuHawk private void Ti83PaletteMenuItem_Click(object sender, EventArgs e) { - if (Emulator is TI83 ti83) + if (Emulator is TI83Common ti83) { using var form = new TI83PaletteConfig(this, ti83.GetSettings().Clone()); if (form.ShowDialog().IsOk()) AddOnScreenMessage("Palette settings saved"); @@ -2477,7 +2477,7 @@ namespace BizHawk.Client.EmuHawk private void MainForm_Shown(object sender, EventArgs e) { - if (Emulator is TI83 && Config.Ti83AutoloadKeyPad) + if (Emulator is TI83Common && Config.Ti83AutoloadKeyPad) { Tools.Load(); } diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs index 46b4be032d..68aca97cda 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.cs @@ -24,6 +24,7 @@ using BizHawk.Bizware.BizwareGL; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.Base_Implementations; using BizHawk.Emulation.Cores; +using BizHawk.Emulation.Cores.Calculators.TI83; using BizHawk.Emulation.Cores.Consoles.NEC.PCE; using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES; using BizHawk.Emulation.Cores.Consoles.SNK; @@ -1987,6 +1988,7 @@ namespace BizHawk.Client.EmuHawk break; case VSystemID.Raw.TI83: TI83SubMenu.Visible = true; + LoadTIFileMenuItem.Visible = Emulator is TI83; break; case VSystemID.Raw.ZXSpectrum: zXSpectrumToolStripMenuItem.Visible = true; diff --git a/src/BizHawk.Client.EmuHawk/config/TI83/TI83PaletteConfig.cs b/src/BizHawk.Client.EmuHawk/config/TI83/TI83PaletteConfig.cs index 57e57703a1..ffa7858257 100644 --- a/src/BizHawk.Client.EmuHawk/config/TI83/TI83PaletteConfig.cs +++ b/src/BizHawk.Client.EmuHawk/config/TI83/TI83PaletteConfig.cs @@ -1,18 +1,18 @@ using System; using System.Drawing; using System.Windows.Forms; -using BizHawk.Emulation.Cores.Calculators; +using BizHawk.Emulation.Cores.Calculators.TI83; namespace BizHawk.Client.EmuHawk { public partial class TI83PaletteConfig : Form { private readonly IMainFormForConfig _mainForm; - private readonly TI83.TI83Settings _settings; + private readonly TI83Common.TI83CommonSettings _settings; public TI83PaletteConfig( IMainFormForConfig mainForm, - TI83.TI83Settings settings) + TI83Common.TI83CommonSettings settings) { _mainForm = mainForm; _settings = settings; @@ -88,7 +88,7 @@ namespace BizHawk.Client.EmuHawk private void DefaultsBtn_Click(object sender, EventArgs e) { - var s = new TI83.TI83Settings(); + var s = new TI83Common.TI83CommonSettings(); BackgroundPanel.BackColor = Color.FromArgb((int)s.BGColor); ForeGroundPanel.BackColor = Color.FromArgb((int)s.ForeColor); } diff --git a/src/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskBundler.Designer.cs b/src/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskBundler.Designer.cs index 1d07c2dea1..d3e0a9c3de 100644 --- a/src/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskBundler.Designer.cs +++ b/src/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskBundler.Designer.cs @@ -148,7 +148,8 @@ "SAT", "ZXSpectrum", "AmstradCPC", - "GGL"}); + "GGL", + "TI83"}); this.SystemDropDown.Location = new System.Drawing.Point(405, 75); this.SystemDropDown.Name = "SystemDropDown"; this.SystemDropDown.Size = new System.Drawing.Size(89, 21); diff --git a/src/BizHawk.Client.EmuHawk/tools/TI83/TI83KeyPad.cs b/src/BizHawk.Client.EmuHawk/tools/TI83/TI83KeyPad.cs index 58f6c01d28..d6b1a885e5 100644 --- a/src/BizHawk.Client.EmuHawk/tools/TI83/TI83KeyPad.cs +++ b/src/BizHawk.Client.EmuHawk/tools/TI83/TI83KeyPad.cs @@ -1,7 +1,7 @@ using System; using BizHawk.Client.Common; using BizHawk.Client.EmuHawk.Properties; -using BizHawk.Emulation.Cores.Calculators; +using BizHawk.Emulation.Cores.Calculators.TI83; using BizHawk.Emulation.Common; namespace BizHawk.Client.EmuHawk @@ -10,7 +10,7 @@ namespace BizHawk.Client.EmuHawk { [RequiredService] // ReSharper disable once UnusedAutoPropertyAccessor.Local - public TI83 Emu { get; private set; } + public TI83Common Emu { get; private set; } protected override string WindowTitleStatic => "TI-83 Virtual KeyPad"; diff --git a/src/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/src/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 7d2e3ed670..bcd273f1b1 100644 --- a/src/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/src/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -19,7 +19,8 @@ - + + diff --git a/src/BizHawk.Emulation.Cores/CPUs/Z80A/NewDisassembler.cs b/src/BizHawk.Emulation.Cores/CPUs/Z80A/NewDisassembler.cs index 4e8ef9b4de..0c39a2be33 100644 --- a/src/BizHawk.Emulation.Cores/CPUs/Z80A/NewDisassembler.cs +++ b/src/BizHawk.Emulation.Cores/CPUs/Z80A/NewDisassembler.cs @@ -380,7 +380,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0x100 }; - public string Disassemble(ushort addr, Func read, out int size) + public static string Disassemble(ushort addr, Func read, out int size) { ushort start_addr = addr; ushort extra_inc = 0; diff --git a/src/BizHawk.Emulation.Cores/Calculator/TI83.ISettable.cs b/src/BizHawk.Emulation.Cores/Calculator/TI83.ISettable.cs deleted file mode 100644 index 31389c24dc..0000000000 --- a/src/BizHawk.Emulation.Cores/Calculator/TI83.ISettable.cs +++ /dev/null @@ -1,41 +0,0 @@ -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Calculators -{ - public partial class TI83 : ISettable - { - private TI83Settings _settings; - - public TI83Settings GetSettings() - { - return _settings.Clone(); - } - - public PutSettingsDirtyBits PutSettings(TI83Settings o) - { - _settings = o; - return PutSettingsDirtyBits.None; - } - - public object GetSyncSettings() - { - return null; - } - - public PutSettingsDirtyBits PutSyncSettings(object o) - { - return PutSettingsDirtyBits.None; - } - - public class TI83Settings - { - public uint BGColor { get; set; } = 0x889778; - public uint ForeColor { get; set; } = 0x36412D; - - public TI83Settings Clone() - { - return (TI83Settings)MemberwiseClone(); - } - } - } -} diff --git a/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IDebuggable.cs new file mode 100644 index 0000000000..a62c5fc1f8 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IDebuggable.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Calculators.Emu83 +{ + public partial class Emu83 : IDebuggable + { + public IDictionary GetCpuFlagsAndRegisters() + { + int[] regs = new int[12]; + LibEmu83.TI83_GetRegs(Context, regs); + return new Dictionary + { + ["AF"] = (ushort)regs[0], + ["BC"] = (ushort)regs[1], + ["DE"] = (ushort)regs[2], + ["HL"] = (ushort)regs[3], + ["AF'"] = (ushort)regs[4], + ["BC'"] = (ushort)regs[5], + ["DE'"] = (ushort)regs[6], + ["HL'"] = (ushort)regs[7], + ["IX"] = (ushort)regs[8], + ["IY"] = (ushort)regs[9], + ["PC"] = (ushort)regs[10], + ["SP"] = (ushort)regs[11], + }; + } + + [FeatureNotImplemented] + public void SetCpuRegister(string register, int value) => throw new NotImplementedException(); + + public bool CanStep(StepType type) => false; + + [FeatureNotImplemented] + public void Step(StepType type) => throw new NotImplementedException(); + + private long _callbackCycleCount = 0; + public long TotalExecutedCycles => Math.Max(LibEmu83.TI83_GetCycleCount(Context), _callbackCycleCount); + + public IMemoryCallbackSystem MemoryCallbacks => _memoryCallbacks; + + private readonly MemoryCallbackSystem _memoryCallbacks = new(new[] { "System Bus" }); + + private LibEmu83.MemoryCallback _readCallback; + private LibEmu83.MemoryCallback _writeCallback; + private LibEmu83.MemoryCallback _execCallback; + + private void InitMemoryCallbacks() + { + LibEmu83.MemoryCallback CreateCallback(MemoryCallbackFlags flags, Func getHasCBOfType) + { + var rawFlags = (uint)flags; + return (address, cycleCount) => + { + _callbackCycleCount = cycleCount; + if (getHasCBOfType()) + { + MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, "System Bus"); + } + }; + } + + _readCallback = CreateCallback(MemoryCallbackFlags.AccessRead, () => MemoryCallbacks.HasReads); + _writeCallback = CreateCallback(MemoryCallbackFlags.AccessWrite, () => MemoryCallbacks.HasWrites); + _execCallback = CreateCallback(MemoryCallbackFlags.AccessExecute, () => MemoryCallbacks.HasExecutes); + + _memoryCallbacks.ActiveChanged += SetMemoryCallbacks; + } + + private void SetMemoryCallbacks() + { + LibEmu83.TI83_SetMemoryCallback(Context, LibEmu83.MemoryCallbackId_t.MEM_CB_READ, MemoryCallbacks.HasReads ? _readCallback : null); + LibEmu83.TI83_SetMemoryCallback(Context, LibEmu83.MemoryCallbackId_t.MEM_CB_WRITE, MemoryCallbacks.HasWrites ? _writeCallback : null); + LibEmu83.TI83_SetMemoryCallback(Context, LibEmu83.MemoryCallbackId_t.MEM_CB_EXECUTE, MemoryCallbacks.HasExecutes ? _execCallback : null); + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IDriveLight.cs b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IDriveLight.cs new file mode 100644 index 0000000000..5789c458ce --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IDriveLight.cs @@ -0,0 +1,10 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Calculators.Emu83 +{ + public partial class Emu83 : IDriveLight + { + public bool DriveLightEnabled => true; + public bool DriveLightOn => LibEmu83.TI83_GetLinkActive(Context); + } +} diff --git a/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IEmulator.cs b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IEmulator.cs new file mode 100644 index 0000000000..6b4c26f0bd --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IEmulator.cs @@ -0,0 +1,53 @@ +using System; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Calculators.Emu83 +{ + public partial class Emu83 : IEmulator + { + public IEmulatorServiceProvider ServiceProvider => _serviceProvider; + + public ControllerDefinition ControllerDefinition => TI83Controller; + + public bool FrameAdvance(IController controller, bool render, bool renderSound) + { + _controller = controller; + + LibEmu83.TI83_SetTraceCallback(Context, Tracer.IsEnabled() ? _traceCallback : null); + + IsLagFrame = LibEmu83.TI83_Advance(Context, _controller.IsPressed("ON"), _controller.IsPressed("SEND"), render ? _videoBuffer : null, _settings.BGColor, _settings.ForeColor); + + Frame++; + + if (IsLagFrame) + { + LagCount++; + } + + return true; + } + + public int Frame { get; set; } + + public string SystemId => VSystemID.Raw.TI83; + + public bool DeterministicEmulation => true; + + public void ResetCounters() + { + Frame = 0; + LagCount = 0; + IsLagFrame = false; + } + + public void Dispose() + { + if (Context != IntPtr.Zero) + { + LibEmu83.TI83_DestroyContext(Context); + Context = IntPtr.Zero; + } + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IInputPollable.cs b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IInputPollable.cs new file mode 100644 index 0000000000..af8cc1241e --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IInputPollable.cs @@ -0,0 +1,12 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Calculators.Emu83 +{ + public partial class Emu83 : IInputPollable + { + private readonly LibEmu83.InputCallback _inputCallback; + public int LagCount { get; set; } + public bool IsLagFrame { get; set; } + public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem(); + } +} diff --git a/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IMemoryDomains.cs b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IMemoryDomains.cs new file mode 100644 index 0000000000..c4b4aeb217 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IMemoryDomains.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Calculators.Emu83 +{ + public partial class Emu83 + { + private readonly List _memoryDomains = new(); + private IMemoryDomains MemoryDomains { get; set; } + + private void CreateMemoryDomain(LibEmu83.MemoryArea_t which, string name) + { + IntPtr data = IntPtr.Zero; + int length = 0; + + if (!LibEmu83.TI83_GetMemoryArea(Context, which, ref data, ref length)) + { + throw new Exception($"{nameof(LibEmu83.TI83_GetMemoryArea)}() failed!"); + } + + _memoryDomains.Add(new MemoryDomainIntPtr(name, MemoryDomain.Endian.Little, data, length, true, 1)); + } + + private void InitMemoryDomains() + { + CreateMemoryDomain(LibEmu83.MemoryArea_t.MEM_ROM, "ROM"); + CreateMemoryDomain(LibEmu83.MemoryArea_t.MEM_RAM, "RAM"); + CreateMemoryDomain(LibEmu83.MemoryArea_t.MEM_VRAM, "VRAM"); + + _memoryDomains.Add(new MemoryDomainDelegate("System Bus", 0x10000, MemoryDomain.Endian.Little, + delegate(long addr) + { + if (addr < 0 || addr >= 0x10000) + { + throw new ArgumentOutOfRangeException(); + } + + return LibEmu83.TI83_ReadMemory(Context, (ushort)addr); + }, + delegate(long addr, byte val) + { + if (addr < 0 || addr >= 0x10000) + { + throw new ArgumentOutOfRangeException(); + } + + LibEmu83.TI83_WriteMemory(Context, (ushort)addr, val); + }, 1)); + + MemoryDomains = new MemoryDomainList(_memoryDomains); + _serviceProvider.Register(MemoryDomains); + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IStatable.cs b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IStatable.cs new file mode 100644 index 0000000000..e81aae3d87 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IStatable.cs @@ -0,0 +1,49 @@ +using System; +using System.IO; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Calculators.Emu83 +{ + public partial class Emu83 : IStatable + { + private readonly byte[] _stateBuf = new byte[LibEmu83.TI83_GetStateSize()]; + + public void SaveStateBinary(BinaryWriter writer) + { + if (!LibEmu83.TI83_SaveState(Context, _stateBuf)) + { + throw new Exception($"{nameof(LibEmu83.TI83_SaveState)}() returned false"); + } + + writer.Write(_stateBuf.Length); + writer.Write(_stateBuf); + + // other variables + writer.Write(IsLagFrame); + writer.Write(LagCount); + writer.Write(Frame); + } + + public void LoadStateBinary(BinaryReader reader) + { + int length = reader.ReadInt32(); + if (length != _stateBuf.Length) + { + throw new InvalidOperationException("Savestate buffer size mismatch!"); + } + + reader.Read(_stateBuf, 0, _stateBuf.Length); + + if (!LibEmu83.TI83_LoadState(Context, _stateBuf)) + { + throw new Exception($"{nameof(LibEmu83.TI83_LoadState)}() returned false"); + } + + // other variables + IsLagFrame = reader.ReadBoolean(); + LagCount = reader.ReadInt32(); + Frame = reader.ReadInt32(); + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.ITraceable.cs b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.ITraceable.cs new file mode 100644 index 0000000000..fc17a6deb6 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.ITraceable.cs @@ -0,0 +1,39 @@ +using System; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Components.Z80A; + +namespace BizHawk.Emulation.Cores.Calculators.Emu83 +{ + public partial class Emu83 + { + private ITraceable Tracer { get; } + private readonly LibEmu83.TraceCallback _traceCallback; + + private void MakeTrace(long _cycleCount) + { + int[] regs = new int[12]; + LibEmu83.TI83_GetRegs(Context, regs); + ushort PC = (ushort)regs[10]; + + string disasm = Z80A.Disassemble(PC, addr => LibEmu83.TI83_ReadMemory(Context, addr), out int bytes_read); + string byte_code = null; + + for (ushort i = 0; i < bytes_read; i++) + { + byte_code += $"{LibEmu83.TI83_ReadMemory(Context, (ushort)(PC + i)):X2}"; + if (i < (bytes_read - 1)) + { + byte_code += " "; + } + } + + Tracer.Put(new( + disassembly: + $"{PC:X4}: {byte_code,-12} {disasm,-26}", + registerInfo: + $"AF:{regs[0]:X4} BC:{regs[1]:X4} DE:{regs[2]:X4} HL:{regs[3]:X4} IX:{regs[8]:X4} IY:{regs[9]:X4} SP:{regs[11]:X4} Cy:{_cycleCount}" + )); + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IVideoProvider.cs b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IVideoProvider.cs new file mode 100644 index 0000000000..66e786332a --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IVideoProvider.cs @@ -0,0 +1,18 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Calculators.Emu83 +{ + public partial class Emu83 : IVideoProvider + { + public int VirtualWidth => 96; + public int VirtualHeight => 64; + public int BufferWidth => 96; + public int BufferHeight => 64; + public int BackgroundColor => 0; + public int VsyncNumerator => NullVideo.DefaultVsyncNum; + public int VsyncDenominator => NullVideo.DefaultVsyncDen; + + private readonly int[] _videoBuffer = new int[96 * 64]; + public int[] GetVideoBuffer() => _videoBuffer; + } +} diff --git a/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.cs b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.cs new file mode 100644 index 0000000000..b754cc453a --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.cs @@ -0,0 +1,164 @@ +using System; +using System.Linq; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Calculators.TI83; + +namespace BizHawk.Emulation.Cores.Calculators.Emu83 +{ + [PortedCore(CoreNames.Emu83, "CasualPokePlayer", "1b8cd90f5b451df3fb07fe3d32d3686a6b93eab4", "https://github.com/CasualPokePlayer/Emu83")] + [ServiceNotApplicable(new[] { typeof(IBoardInfo), typeof(IRegionable), typeof(ISaveRam), typeof(ISoundProvider) })] + public partial class Emu83 : TI83Common + { + private IntPtr Context = IntPtr.Zero; + + private readonly BasicServiceProvider _serviceProvider; + + private readonly TI83Disassembler _disassembler = new(); + + [CoreConstructor(VSystemID.Raw.TI83)] + public Emu83(CoreLoadParameters lp) + { + try + { + _serviceProvider = new BasicServiceProvider(this); + PutSettings(lp.Settings ?? new TI83CommonSettings()); + var rom = lp.Comm.CoreFileProvider.GetFirmwareOrThrow(new("TI83", "Rom")); + Context = LibEmu83.TI83_CreateContext(rom, rom.Length); + if (Context == IntPtr.Zero) + { + throw new Exception("Core returned null! Bad ROM?"); + } + var linkFiles = lp.Roms.Select(r => r.RomData).ToList(); + foreach (var linkFile in linkFiles) + { + if (!LibEmu83.TI83_LoadLinkFile(Context, linkFile, linkFile.Length)) + { + throw new Exception("Core rejected the link files!"); + } + } + LibEmu83.TI83_SetLinkFilesAreLoaded(Context); + _inputCallback = ReadKeyboard; + LibEmu83.TI83_SetInputCallback(Context, _inputCallback); + _serviceProvider.Register(_disassembler); + _traceCallback = MakeTrace; + LibEmu83.TI83_SetTraceCallback(Context, null); + const string TRACE_HEADER = "Z80A: PC, machine code, mnemonic, operands, registers (AF, BC, DE, HL, IX, IY, SP, Cy)"; + Tracer = new TraceBuffer(TRACE_HEADER); + _serviceProvider.Register(Tracer); + InitMemoryDomains(); + InitMemoryCallbacks(); + } + catch + { + Dispose(); + throw; + } + } + + private static readonly ControllerDefinition TI83Controller = new ControllerDefinition("TI83 Controller") + { + BoolButtons = + { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "DOT", + "ON", "ENTER", + "DOWN", "LEFT", "UP", "RIGHT", + "PLUS", "MINUS", "MULTIPLY", "DIVIDE", + "CLEAR", "EXP", "DASH", "PARACLOSE", "TAN", "VARS", "PARAOPEN", + "COS", "PRGM", "STAT", "COMMA", "SIN", "MATRIX", "X", + "STO", "LN", "LOG", "SQUARED", "NEG1", "MATH", "ALPHA", + "GRAPH", "TRACE", "ZOOM", "WINDOW", "Y", "2ND", "MODE", "DEL", + "SEND", + }, + }.MakeImmutable(); + + private IController _controller = NullController.Instance; + + private byte ReadKeyboard(byte _keyboardMask) + { + InputCallbacks.Call(); + + // ref TI-9X + int ret = 0xFF; + ////Console.WriteLine("keyboardMask: {0:X2}",keyboardMask); + if ((_keyboardMask & 1) == 0) + { + if (_controller.IsPressed("DOWN")) ret ^= 1; + if (_controller.IsPressed("LEFT")) ret ^= 2; + if (_controller.IsPressed("RIGHT")) ret ^= 4; + if (_controller.IsPressed("UP")) ret ^= 8; + } + + if ((_keyboardMask & 2) == 0) + { + if (_controller.IsPressed("ENTER")) ret ^= 1; + if (_controller.IsPressed("PLUS")) ret ^= 2; + if (_controller.IsPressed("MINUS")) ret ^= 4; + if (_controller.IsPressed("MULTIPLY")) ret ^= 8; + if (_controller.IsPressed("DIVIDE")) ret ^= 16; + if (_controller.IsPressed("EXP")) ret ^= 32; + if (_controller.IsPressed("CLEAR")) ret ^= 64; + } + + if ((_keyboardMask & 4) == 0) + { + if (_controller.IsPressed("DASH")) ret ^= 1; + if (_controller.IsPressed("3")) ret ^= 2; + if (_controller.IsPressed("6")) ret ^= 4; + if (_controller.IsPressed("9")) ret ^= 8; + if (_controller.IsPressed("PARACLOSE")) ret ^= 16; + if (_controller.IsPressed("TAN")) ret ^= 32; + if (_controller.IsPressed("VARS")) ret ^= 64; + } + + if ((_keyboardMask & 8) == 0) + { + if (_controller.IsPressed("DOT")) ret ^= 1; + if (_controller.IsPressed("2")) ret ^= 2; + if (_controller.IsPressed("5")) ret ^= 4; + if (_controller.IsPressed("8")) ret ^= 8; + if (_controller.IsPressed("PARAOPEN")) ret ^= 16; + if (_controller.IsPressed("COS")) ret ^= 32; + if (_controller.IsPressed("PRGM")) ret ^= 64; + if (_controller.IsPressed("STAT")) ret ^= 128; + } + + if ((_keyboardMask & 16) == 0) + { + if (_controller.IsPressed("0")) ret ^= 1; + if (_controller.IsPressed("1")) ret ^= 2; + if (_controller.IsPressed("4")) ret ^= 4; + if (_controller.IsPressed("7")) ret ^= 8; + if (_controller.IsPressed("COMMA")) ret ^= 16; + if (_controller.IsPressed("SIN")) ret ^= 32; + if (_controller.IsPressed("MATRIX")) ret ^= 64; + if (_controller.IsPressed("X")) ret ^= 128; + } + + if ((_keyboardMask & 32) == 0) + { + if (_controller.IsPressed("STO")) ret ^= 2; + if (_controller.IsPressed("LN")) ret ^= 4; + if (_controller.IsPressed("LOG")) ret ^= 8; + if (_controller.IsPressed("SQUARED")) ret ^= 16; + if (_controller.IsPressed("NEG1")) ret ^= 32; + if (_controller.IsPressed("MATH")) ret ^= 64; + if (_controller.IsPressed("ALPHA")) ret ^= 128; + } + + if ((_keyboardMask & 64) == 0) + { + if (_controller.IsPressed("GRAPH")) ret ^= 1; + if (_controller.IsPressed("TRACE")) ret ^= 2; + if (_controller.IsPressed("ZOOM")) ret ^= 4; + if (_controller.IsPressed("WINDOW")) ret ^= 8; + if (_controller.IsPressed("Y")) ret ^= 16; + if (_controller.IsPressed("2ND")) ret ^= 32; + if (_controller.IsPressed("MODE")) ret ^= 64; + if (_controller.IsPressed("DEL")) ret ^= 128; + } + + return (byte)ret; + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Calculators/Emu83/LibEmu83.cs b/src/BizHawk.Emulation.Cores/Calculators/Emu83/LibEmu83.cs new file mode 100644 index 0000000000..dc2a66279a --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Calculators/Emu83/LibEmu83.cs @@ -0,0 +1,85 @@ +using System; +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.Cores.Calculators.Emu83 +{ + public static class LibEmu83 + { + private const string lib = "libemu83"; + private const CallingConvention cc = CallingConvention.Cdecl; + + [DllImport(lib, CallingConvention = cc)] + public static extern IntPtr TI83_CreateContext(byte[] rom, int len); + + [DllImport(lib, CallingConvention = cc)] + public static extern void TI83_DestroyContext(IntPtr context); + + [DllImport(lib, CallingConvention = cc)] + public static extern bool TI83_LoadLinkFile(IntPtr context, byte[] linkfile, int len); + + [DllImport(lib, CallingConvention = cc)] + public static extern void TI83_SetLinkFilesAreLoaded(IntPtr context); + + [DllImport(lib, CallingConvention = cc)] + public static extern bool TI83_GetLinkActive(IntPtr context); + + [DllImport(lib, CallingConvention = cc)] + public static extern bool TI83_Advance(IntPtr context, bool onpress, bool sendnextlinkfile, int[] videobuf, uint bgcol, uint forecol); + + [DllImport(lib, CallingConvention = cc)] + public static extern long TI83_GetStateSize(); + + [DllImport(lib, CallingConvention = cc)] + public static extern bool TI83_SaveState(IntPtr context, byte[] buf); + + [DllImport(lib, CallingConvention = cc)] + public static extern bool TI83_LoadState(IntPtr context, byte[] buf); + + [DllImport(lib, CallingConvention = cc)] + public static extern void TI83_GetRegs(IntPtr context, int[] buf); + + public enum MemoryArea_t : int + { + MEM_ROM, + MEM_RAM, + MEM_VRAM, + } + + [DllImport(lib, CallingConvention = cc)] + public static extern bool TI83_GetMemoryArea(IntPtr context, MemoryArea_t which, ref IntPtr ptr, ref int len); + + [DllImport(lib, CallingConvention = cc)] + public static extern byte TI83_ReadMemory(IntPtr context, ushort addr); + + [DllImport(lib, CallingConvention = cc)] + public static extern void TI83_WriteMemory(IntPtr context, ushort addr, byte val); + + [DllImport(lib, CallingConvention = cc)] + public static extern long TI83_GetCycleCount(IntPtr context); + + public enum MemoryCallbackId_t : int + { + MEM_CB_READ, + MEM_CB_WRITE, + MEM_CB_EXECUTE, + } + + [UnmanagedFunctionPointer(cc)] + public delegate void MemoryCallback(ushort addr, long _cycleCount); + + [DllImport(lib, CallingConvention = cc)] + public static extern void TI83_SetMemoryCallback(IntPtr context, MemoryCallbackId_t id, MemoryCallback callback); + + [UnmanagedFunctionPointer(cc)] + public delegate void TraceCallback(long _cycleCount); + + [DllImport(lib, CallingConvention = cc)] + public static extern void TI83_SetTraceCallback(IntPtr context, TraceCallback callback); + + [UnmanagedFunctionPointer(cc)] + public delegate byte InputCallback(byte _keyboardMask); + + [DllImport(lib, CallingConvention = cc)] + public static extern void TI83_SetInputCallback(IntPtr context, InputCallback callback); + } +} diff --git a/src/BizHawk.Emulation.Cores/Calculators/Emu83/TI83Disassembler.cs b/src/BizHawk.Emulation.Cores/Calculators/Emu83/TI83Disassembler.cs new file mode 100644 index 0000000000..80ea48a2f8 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Calculators/Emu83/TI83Disassembler.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Components.Z80A; + +namespace BizHawk.Emulation.Cores.Calculators.Emu83 +{ + public class TI83Disassembler : VerifiedDisassembler + { + public override IEnumerable AvailableCpus { get; } = new[] { "Z80" }; + + public override string PCRegisterName => "PC"; + + public override string Disassemble(MemoryDomain m, uint addr, out int length) + { + var ret = Z80A.Disassemble((ushort) addr, a => m.PeekByte(a), out var tmp); + length = tmp; + return ret; + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Calculator/TI83.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IDebuggable.cs similarity index 90% rename from src/BizHawk.Emulation.Cores/Calculator/TI83.IDebuggable.cs rename to src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IDebuggable.cs index 0580777493..b55e40fac3 100644 --- a/src/BizHawk.Emulation.Cores/Calculator/TI83.IDebuggable.cs +++ b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IDebuggable.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using BizHawk.Emulation.Common; -namespace BizHawk.Emulation.Cores.Calculators +namespace BizHawk.Emulation.Cores.Calculators.TI83 { public partial class TI83 : IDebuggable { diff --git a/src/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IEmulator.cs similarity index 91% rename from src/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs rename to src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IEmulator.cs index 95b16665b4..c24ce6fd02 100644 --- a/src/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs +++ b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IEmulator.cs @@ -1,6 +1,6 @@ using BizHawk.Emulation.Common; -namespace BizHawk.Emulation.Cores.Calculators +namespace BizHawk.Emulation.Cores.Calculators.TI83 { public partial class TI83 : IEmulator { diff --git a/src/BizHawk.Emulation.Cores/Calculator/TI83.IInputPollable.cs b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IInputPollable.cs similarity index 84% rename from src/BizHawk.Emulation.Cores/Calculator/TI83.IInputPollable.cs rename to src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IInputPollable.cs index a31df55395..2694b9a4cd 100644 --- a/src/BizHawk.Emulation.Cores/Calculator/TI83.IInputPollable.cs +++ b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IInputPollable.cs @@ -1,6 +1,6 @@ using BizHawk.Emulation.Common; -namespace BizHawk.Emulation.Cores.Calculators +namespace BizHawk.Emulation.Cores.Calculators.TI83 { public partial class TI83 : IInputPollable { diff --git a/src/BizHawk.Emulation.Cores/Calculator/TI83.IMemoryDomains.cs b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IMemoryDomains.cs similarity index 92% rename from src/BizHawk.Emulation.Cores/Calculator/TI83.IMemoryDomains.cs rename to src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IMemoryDomains.cs index a41f923225..d9412b485d 100644 --- a/src/BizHawk.Emulation.Cores/Calculator/TI83.IMemoryDomains.cs +++ b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IMemoryDomains.cs @@ -4,7 +4,7 @@ using System.Linq; using BizHawk.Emulation.Common; -namespace BizHawk.Emulation.Cores.Calculators +namespace BizHawk.Emulation.Cores.Calculators.TI83 { public partial class TI83 { diff --git a/src/BizHawk.Emulation.Cores/Calculator/TI83.IStatable.cs b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IStatable.cs similarity index 93% rename from src/BizHawk.Emulation.Cores/Calculator/TI83.IStatable.cs rename to src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IStatable.cs index 8f8608a46f..99f5c354e8 100644 --- a/src/BizHawk.Emulation.Cores/Calculator/TI83.IStatable.cs +++ b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IStatable.cs @@ -2,7 +2,7 @@ using BizHawk.Common; -namespace BizHawk.Emulation.Cores.Calculators +namespace BizHawk.Emulation.Cores.Calculators.TI83 { public partial class TI83 { diff --git a/src/BizHawk.Emulation.Cores/Calculator/TI83.IVideoProvider.cs b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IVideoProvider.cs similarity index 90% rename from src/BizHawk.Emulation.Cores/Calculator/TI83.IVideoProvider.cs rename to src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IVideoProvider.cs index 1ea0a88ed6..af1fe83bd6 100644 --- a/src/BizHawk.Emulation.Cores/Calculator/TI83.IVideoProvider.cs +++ b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IVideoProvider.cs @@ -1,6 +1,6 @@ using BizHawk.Emulation.Common; -namespace BizHawk.Emulation.Cores.Calculators +namespace BizHawk.Emulation.Cores.Calculators.TI83 { public partial class TI83 : IVideoProvider { diff --git a/src/BizHawk.Emulation.Cores/Calculator/TI83.cs b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.cs similarity index 93% rename from src/BizHawk.Emulation.Cores/Calculator/TI83.cs rename to src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.cs index 536d35ced0..f06bdfd0c9 100644 --- a/src/BizHawk.Emulation.Cores/Calculator/TI83.cs +++ b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.cs @@ -4,18 +4,18 @@ using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Components.Z80A; // http://www.ticalc.org/pub/text/calcinfo/ -namespace BizHawk.Emulation.Cores.Calculators +namespace BizHawk.Emulation.Cores.Calculators.TI83 { [Core(CoreNames.TI83Hawk, "zeromus")] [ServiceNotApplicable(new[] { typeof(IBoardInfo), typeof(IDriveLight), typeof(IRegionable), typeof(ISaveRam), typeof(ISoundProvider) })] - public partial class TI83 : IEmulator, IVideoProvider, IDebuggable, IInputPollable, ISettable + public partial class TI83 : TI83Common, IEmulator, IVideoProvider, IDebuggable, IInputPollable { [CoreConstructor(VSystemID.Raw.TI83)] - public TI83(CoreLoadParameters lp) + public TI83(CoreLoadParameters lp) { var ser = new BasicServiceProvider(this); ServiceProvider = ser; - PutSettings(lp.Settings ?? new TI83Settings()); + PutSettings(lp.Settings ?? new TI83CommonSettings()); _cpu.FetchMemory = ReadMemory; _cpu.ReadMemory = ReadMemory; diff --git a/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83Common.cs b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83Common.cs new file mode 100644 index 0000000000..886bd1206c --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83Common.cs @@ -0,0 +1,31 @@ +using System; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Calculators.TI83 +{ + public class TI83Common : ISettable + { + protected TI83CommonSettings _settings; + + public TI83CommonSettings GetSettings() => _settings.Clone(); + + public PutSettingsDirtyBits PutSettings(TI83CommonSettings o) + { + _settings = o; + return PutSettingsDirtyBits.None; + } + + public object GetSyncSettings() => null; + + public PutSettingsDirtyBits PutSyncSettings(object o) => PutSettingsDirtyBits.None; + + public class TI83CommonSettings + { + public uint BGColor { get; set; } = 0x889778; + public uint ForeColor { get; set; } = 0x36412D; + + public TI83CommonSettings Clone() => (TI83CommonSettings)MemberwiseClone(); + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Calculator/TI83LinkPort.cs b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83LinkPort.cs similarity index 94% rename from src/BizHawk.Emulation.Cores/Calculator/TI83LinkPort.cs rename to src/BizHawk.Emulation.Cores/Calculators/TI83/TI83LinkPort.cs index d9c1890fa2..e2cabbfeb0 100644 --- a/src/BizHawk.Emulation.Cores/Calculator/TI83LinkPort.cs +++ b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83LinkPort.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; -namespace BizHawk.Emulation.Cores.Calculators +namespace BizHawk.Emulation.Cores.Calculators.TI83 { public class TI83LinkPort { diff --git a/src/BizHawk.Emulation.Cores/CoreNames.cs b/src/BizHawk.Emulation.Cores/CoreNames.cs index 49cbfa8fbf..c34aeca5de 100644 --- a/src/BizHawk.Emulation.Cores/CoreNames.cs +++ b/src/BizHawk.Emulation.Cores/CoreNames.cs @@ -19,6 +19,7 @@ namespace BizHawk.Emulation.Cores public const string CPCHawk = "CPCHawk"; public const string Cygne = "Cygne/Mednafen"; public const string DobieStation = "DobieStation"; + public const string Emu83 = "Emu83"; public const string Faust = "Faust"; public const string Gambatte = "Gambatte"; public const string GambatteLink = "GambatteLink"; diff --git a/submodules/libemu83 b/submodules/libemu83 new file mode 160000 index 0000000000..1b8cd90f5b --- /dev/null +++ b/submodules/libemu83 @@ -0,0 +1 @@ +Subproject commit 1b8cd90f5b451df3fb07fe3d32d3686a6b93eab4