split arm7 polling/touch screen polling to a new "alt lag" variable and add a setting for whether to consider these sources (fixes #3278)

add in new disasm system (taken from https://github.com/MAP233224/dthumb), works much better than darm
This commit is contained in:
CasualPokePlayer 2022-06-24 01:30:30 -07:00
parent d3d90eb70d
commit 347fa24820
10 changed files with 1473 additions and 85 deletions

Binary file not shown.

View File

@ -38,6 +38,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
public byte TouchY;
public byte MicVolume;
public byte GBALightSensor;
public bool ConsiderAltLag;
}
[Flags]
@ -112,21 +113,24 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
[BizImport(CC)]
public abstract void SetMemoryCallback(int which, MemoryCallback callback);
// bit 0 -> ARM9 or ARM7
// bit 1 -> ARM or THUMB mode
public enum CpuTypes : uint
[Flags]
public enum TraceMask : uint
{
ARM9,
ARM7,
ARM9_THUMB,
ARM7_THUMB,
NONE = 0,
ARM7_THUMB = 1,
ARM7_ARM = 2,
ARM9_THUMB = 4,
ARM9_ARM = 8,
}
[UnmanagedFunctionPointer(CC)]
public delegate void TraceCallback(CpuTypes _cpu, IntPtr _regs, uint _opcode);
public delegate void TraceCallback(TraceMask type, IntPtr regs, IntPtr disasm, uint cyclesOff);
[BizImport(CC)]
public abstract void SetTraceCallback(TraceCallback callback);
public abstract void SetTraceCallback(TraceCallback callback, TraceMask mask);
[BizImport(CC)]
public abstract void GetDisassembly(TraceMask type, uint opcode, byte[] ret);
[BizImport(CC)]
public abstract IntPtr GetFrameThreadProc();

View File

@ -71,6 +71,45 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
[DefaultValue(AudioBitrateType.Auto)]
public AudioBitrateType AudioBitrate { get; set; }
[DisplayName("Alt Lag")]
[Description("If true, touch screen polling and ARM7 key polling will be considered for lag frames. Otherwise, only ARM9 key polling will be considered.")]
[DefaultValue(false)]
public bool ConsiderAltLag { get; set; }
[DisplayName("Trace ARM7 Thumb")]
[Description("")]
[DefaultValue(false)]
public bool TraceArm7Thumb { get; set; }
[DisplayName("Trace ARM7 ARM")]
[Description("")]
[DefaultValue(false)]
public bool TraceArm7Arm { get; set; }
[DisplayName("Trace ARM9 Thumb")]
[Description("")]
[DefaultValue(false)]
public bool TraceArm9Thumb { get; set; }
[DisplayName("Trace ARM9 ARM")]
[Description("")]
[DefaultValue(true)]
public bool TraceArm9Arm { get; set; }
public LibMelonDS.TraceMask GetTraceMask()
{
var ret = LibMelonDS.TraceMask.NONE;
if (TraceArm7Thumb)
ret |= LibMelonDS.TraceMask.ARM7_THUMB;
if (TraceArm7Arm)
ret |= LibMelonDS.TraceMask.ARM7_ARM;
if (TraceArm9Thumb)
ret |= LibMelonDS.TraceMask.ARM9_THUMB;
if (TraceArm9Arm)
ret |= LibMelonDS.TraceMask.ARM9_ARM;
return ret;
}
public NDSSettings Clone() => MemberwiseClone() as NDSSettings;
public static bool NeedsScreenResize(NDSSettings x, NDSSettings y)

View File

@ -10,44 +10,43 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
private ITraceable Tracer { get; }
private readonly LibMelonDS.TraceCallback _tracecb;
private void MakeTrace(LibMelonDS.CpuTypes _cpu, IntPtr _regs, uint _opcode)
private unsafe void MakeTrace(LibMelonDS.TraceMask type, IntPtr r, IntPtr disasm, uint cyclesOff)
{
string cpu = _cpu switch
{
LibMelonDS.CpuTypes.ARM9 => "ARM9",
LibMelonDS.CpuTypes.ARM7 => "ARM7",
LibMelonDS.CpuTypes.ARM9_THUMB => "ARM9 (Thumb)",
LibMelonDS.CpuTypes.ARM7_THUMB => "ARM7 (Thumb)",
string cpu = type switch
{
LibMelonDS.TraceMask.ARM7_THUMB => "ARM7 (Thumb)",
LibMelonDS.TraceMask.ARM7_ARM => "ARM7",
LibMelonDS.TraceMask.ARM9_THUMB => "ARM9 (Thumb)",
LibMelonDS.TraceMask.ARM9_ARM => "ARM9",
_ => throw new InvalidOperationException("Invalid CPU Mode???"),
};
int[] regs = new int[16];
Marshal.Copy(_regs, regs, 0, 16);
uint* regs = (uint*)r;
bool isthumb = ((uint)_cpu & 2u) == 2u;
uint pc = (uint)regs[15] - (isthumb ? 2u : 4u); // handle prefetch
bool isthumb = type is LibMelonDS.TraceMask.ARM7_THUMB or LibMelonDS.TraceMask.ARM9_THUMB;
uint pc = regs[15] - (isthumb ? 2u : 4u); // handle prefetch
Tracer.Put(new(
disassembly: string.Format("{0:x8}", pc).PadRight(12) + _disassembler.Trace(pc, _opcode, isthumb).PadRight(32),
disassembly: string.Format("{0:x8}", pc).PadRight(12) + Marshal.PtrToStringAnsi(disasm).PadRight(64),
registerInfo: string.Format(
"r0:{0:x8} r1:{1:x8} r2:{2:x8} r3:{3:x8} r4:{4:x8} r5:{5:x8} r6:{6:x8} r7:{7:x8} r8:{8:x8} r9:{9:x8} r10:{10:x8} r11:{11:x8} r12:{12:x8} r13:{13:x8} r14:{14:x8} r15:{15:x8} Cy:{16} {17}",
(uint)regs[0],
(uint)regs[1],
(uint)regs[2],
(uint)regs[3],
(uint)regs[4],
(uint)regs[5],
(uint)regs[6],
(uint)regs[7],
(uint)regs[8],
(uint)regs[9],
(uint)regs[10],
(uint)regs[11],
(uint)regs[12],
(uint)regs[13],
(uint)regs[14],
(uint)regs[15],
TotalExecutedCycles,
regs[0],
regs[1],
regs[2],
regs[3],
regs[4],
regs[5],
regs[6],
regs[7],
regs[8],
regs[9],
regs[10],
regs[11],
regs[12],
regs[13],
regs[14],
regs[15],
CycleCount + cyclesOff,
cpu)));
}
}

View File

@ -213,7 +213,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
_resampler = new SpeexResampler(SpeexResampler.Quality.QUALITY_DEFAULT, 32768, 44100, 32768, 44100, null, this);
_serviceProvider.Register<ISoundProvider>(_resampler);
_disassembler = new NDSDisassembler();
_disassembler = new(_core);
_serviceProvider.Register<IDisassemblable>(_disassembler);
const string TRACE_HEADER = "ARM9+ARM7: PC, opcode, registers (r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, Cy, CpuMode)";
@ -327,7 +327,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
{
_core.SetTraceCallback(Tracer.IsEnabled() ? _tracecb : null);
_core.SetTraceCallback(Tracer.IsEnabled() ? _tracecb : null, _settings.GetTraceMask());
return new LibMelonDS.FrameInfo
{
Time = GetRtcTime(!DeterministicEmulation),
@ -336,6 +336,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
TouchY = (byte)controller.AxisValue("Touch Y"),
MicVolume = (byte)controller.AxisValue("Mic Volume"),
GBALightSensor = (byte)controller.AxisValue("GBA Light Sensor"),
ConsiderAltLag = _settings.ConsiderAltLag,
};
}

View File

@ -1,18 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
using BizHawk.BizInvoke;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Components.ARM;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
{
public class NDSDisassembler : VerifiedDisassembler
{
private static readonly Darm _libdarm = BizInvoker.GetInvoker<Darm>(
new DynamicLibraryImportResolver(OSTailoredCode.IsUnixHost ? "libdarm.so" : "libdarm.dll", hasLimitedLifetime: false),
CallingConventionAdapters.Native
);
private readonly LibMelonDS _core;
public NDSDisassembler(LibMelonDS core)
=> _core = core;
public override IEnumerable<string> AvailableCpus => new[]
{
@ -29,52 +28,37 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
if (m is NDS.NDSSystemBus NdsSysBus)
{
NdsSysBus.UseArm9 = int.Parse(Cpu.Substring(5, 1)) == 5;
m = NdsSysBus;
}
var ret = new byte[64];
var type = Cpu switch
{
"ARM v5" => LibMelonDS.TraceMask.ARM9_ARM,
"ARM v5 (Thumb)" => LibMelonDS.TraceMask.ARM9_THUMB,
"ARM v4" => LibMelonDS.TraceMask.ARM7_ARM,
"ARM v4 (Thumb)" => LibMelonDS.TraceMask.ARM7_THUMB,
_ => throw new Exception("Invalid CPU mode?"),
};
if (Cpu.Length == 14)
{
addr &= ~1u;
int op = m.PeekByte(addr) | m.PeekByte(addr + 1) << 8;
string ret = _libdarm.DisassembleStuff(addr | 1, (uint)op);
uint op = m.PeekByte(addr) | (uint)m.PeekByte(addr + 1) << 8;
_core.GetDisassembly(type, op, ret);
length = 2;
return ret;
}
else
{
addr &= ~3u;
int op = m.PeekByte(addr)
| m.PeekByte(addr + 1) << 8
| m.PeekByte(addr + 2) << 16
| m.PeekByte(addr + 3) << 24;
string ret = _libdarm.DisassembleStuff(addr, (uint)op);
uint op = m.PeekByte(addr)
| (uint)m.PeekByte(addr + 1) << 8
| (uint)m.PeekByte(addr + 2) << 16
| (uint)m.PeekByte(addr + 3) << 24;
_core.GetDisassembly(type, op, ret);
length = 4;
return ret;
}
}
public string Trace(uint pc, uint op, bool isthumb)
{
if (isthumb)
{
pc &= ~1u;
string ret = _libdarm.DisassembleStuff(pc | 1, op);
if (ret == null)
{
ret = "Can't disassemble???";
}
return ret;
}
else
{
pc &= ~3u;
string ret = _libdarm.DisassembleStuff(pc, op);
if (ret == null)
{
ret = "Can't disassemble???";
}
return ret;
}
return Encoding.ASCII.GetString(ret);
}
}
}

View File

@ -339,6 +339,7 @@ struct MyFrameInfo : public FrameInfo
u8 TouchY;
s8 MicVolume;
s8 GBALightSensor;
bool ConsiderAltLag;
};
static s16 biz_mic_input[735];
@ -424,6 +425,11 @@ EXPORT void FrameAdvance(MyFrameInfo* f)
}
f->Cycles = NDS::GetSysClockCycles(2);
f->Lagged = NDS::LagFrameFlag;
// if we want to consider other lag sources, use that lag flag if we haven't unlagged already
if (f->ConsiderAltLag && NDS::LagFrameFlag)
{
f->Lagged = NDS::AltLagFrameFlag;
}
RunningFrame = false;
}
@ -464,13 +470,52 @@ EXPORT void SetMemoryCallback(u32 which, void (*callback)(u32 addr))
}
}
void (*TraceCallback)(u32, u32*, u32) = nullptr;
TraceMask_t TraceMask = TRACE_NONE;
static void (*TraceCallback)(TraceMask_t, u32*, u8*, u32) = nullptr;
#define TRACE_STRING_LENGTH 64
typedef enum {
ARMv4T, //ARM v4, THUMB v1
ARMv5TE, //ARM v5, THUMB v2
ARMv6, //ARM v6, THUMB v3
} ARMARCH; //only 32-bit legacy architectures with THUMB support
extern "C" unsigned int Disassemble_thumb(unsigned int code, unsigned char str[TRACE_STRING_LENGTH], unsigned int it, const unsigned char* cond, ARMARCH tv);
extern "C" void Disassemble_arm(unsigned int code, unsigned char str[TRACE_STRING_LENGTH], ARMARCH av);
EXPORT void SetTraceCallback(void (*callback)(u32 cpu, u32* regs, u32 opcode))
void TraceTrampoline(TraceMask_t type, u32* regs, u32 opcode)
{
static unsigned char disasm[TRACE_STRING_LENGTH];
memset(disasm, 0, sizeof disasm);
switch (type) {
case TRACE_ARM7_THUMB: Disassemble_thumb(opcode, disasm, 0, nullptr, ARMv4T); break;
case TRACE_ARM7_ARM: Disassemble_arm(opcode, disasm, ARMv4T); break;
case TRACE_ARM9_THUMB: Disassemble_thumb(opcode, disasm, 0, nullptr, ARMv5TE); break;
case TRACE_ARM9_ARM: Disassemble_arm(opcode, disasm, ARMv5TE); break;
default: __builtin_unreachable();
}
TraceCallback(type, regs, disasm, NDS::GetSysClockCycles(2));
}
EXPORT void SetTraceCallback(void (*callback)(TraceMask_t mask, u32* regs, u8* disasm, u32 cyclesOff), TraceMask_t mask)
{
TraceCallback = callback;
TraceMask = callback ? mask : TRACE_NONE;
}
EXPORT void GetDisassembly(TraceMask_t type, u32 opcode, char* ret)
{
static unsigned char disasm[TRACE_STRING_LENGTH];
memset(disasm, 0, sizeof disasm);
switch (type) {
case TRACE_ARM7_THUMB: Disassemble_thumb(opcode, disasm, 0, nullptr, ARMv4T); break;
case TRACE_ARM7_ARM: Disassemble_arm(opcode, disasm, ARMv4T); break;
case TRACE_ARM9_THUMB: Disassemble_thumb(opcode, disasm, 0, nullptr, ARMv5TE); break;
case TRACE_ARM9_ARM: Disassemble_arm(opcode, disasm, ARMv5TE); break;
default: __builtin_unreachable();
}
memcpy(ret, disasm, TRACE_STRING_LENGTH);
}
namespace Platform
{
extern uintptr_t FrameThreadProc;

View File

@ -1,4 +1,4 @@
CCFLAGS := -Wno-discarded-qualifiers
CCFLAGS := -Wno-discarded-qualifiers -Wno-pointer-sign
CXXFLAGS := -DMELONDS_VERSION="" \
-I./melonDS/src -I./melonDS/src/teakra/include \
@ -76,6 +76,7 @@ SRCS = \
$(addprefix melonDS/src/,$(MISC_SRCS)) \
BizConfig.cpp \
BizInterface.cpp \
BizPlatform.cpp
BizPlatform.cpp \
dthumb.c
include ../common.mak

1315
waterbox/melon/dthumb.c Normal file

File diff suppressed because it is too large Load Diff

@ -1 +1 @@
Subproject commit d0aff66cf671d9853974d374d39e11fd89d13819
Subproject commit c9e835f87408ba9b00708941fc07e541eedcb3ec