Add tracer + disassembler + get registers + system bus to Ares64, mark Ares64 as released

Squashed commit of the following:

commit 2e29aee13276412b2832e8f0efa10d9c57ed9d78
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Thu Apr 14 22:44:33 2022 -0700

    .

commit be73cf5e2204405a84b42948fd104d18c75be45a
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Thu Apr 14 22:37:34 2022 -0700

    hook up debug stuff + disassembler + tracer, mark Ares64 as released

commit fdd440703ecef48c94bb2bb1ad9c2d3dc5c96e42
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Thu Apr 14 20:36:08 2022 -0700

    maybe fix disassembly

commit d0808551c60fe3c03506b1ad89766a0d397e06dd
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Thu Apr 14 20:06:36 2022 -0700

    system bus

commit 60d1df8f33043fb656f90c1cf4ace8788489c3e1
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Thu Apr 14 16:40:11 2022 -0700

    regs

commit c64be2df293ea44694868355747061a952bd54aa
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Thu Apr 14 15:31:08 2022 -0700

    tracing and disasembly for ares, needs to be hooked up to frontend
This commit is contained in:
CasualPokePlayer 2022-04-14 22:45:10 -07:00
parent 7d268e244b
commit 20ecfb81ea
8 changed files with 255 additions and 5 deletions

Binary file not shown.

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
{
public partial class Ares64 : IDebuggable
{
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
{
var ret = new Dictionary<string, RegisterValue>();
var data = new ulong[32 + 3]; // GPRs, lo, hi, pc (todo: other regs)
_core.GetRegisters(data);
for (int i = 0; i < 32; i++)
{
ret.Add(_GPRnames[i], data[i]);
}
ret.Add("LO", data[32]);
ret.Add("HI", data[33]);
ret.Add("PC", (uint)data[34]);
return ret;
}
private readonly string[] _GPRnames = new string[32]
{
"R0",
"AT",
"V0", "V1",
"A0", "A1", "A2", "A3",
"T0", "T1", "T2", "T3", "T4", "T5", "T6", "T7",
"S0", "S1", "S2", "S3", "S4", "S5", "S6", "S7",
"T8", "T9",
"K0", "K1",
"GP",
"SP",
"S8",
"RA",
};
[FeatureNotImplemented]
public void SetCpuRegister(string register, int value) => throw new NotImplementedException();
[FeatureNotImplemented]
public IMemoryCallbackSystem MemoryCallbacks => throw new NotImplementedException();
public bool CanStep(StepType type) => false;
[FeatureNotImplemented]
public long TotalExecutedCycles => throw new NotImplementedException();
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
}
}

View File

@ -0,0 +1,38 @@
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
{
public class Ares64Disassembler : VerifiedDisassembler
{
private readonly LibAres64 _core;
private readonly byte[] _disasmbuf = new byte[100]; // todo: is this big enough?
public Ares64Disassembler(LibAres64 core)
{
_core = core;
}
public override IEnumerable<string> AvailableCpus => new[] { "R4300", };
public override string PCRegisterName => "PC";
public override string Disassemble(MemoryDomain m, uint addr, out int length)
{
_core.GetDisassembly(addr, m.PeekUint(addr, true), _disasmbuf);
length = 4;
var ret = Encoding.UTF8.GetString(_disasmbuf);
var z = ret.IndexOf('\0');
if (z > -1)
{
ret = ret.Substring(0, z); // remove garbage past null terminator
}
ret = Regex.Replace(ret, @"\u001b?\[[0-9]{1,2}m", ""); // remove ANSI escape sequences
ret = Regex.Replace(ret, @"\{.*\}", ""); // remove any {*} patterns
return ret;
}
}
}

View File

@ -4,7 +4,6 @@ using System.ComponentModel;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
{
public partial class Ares64 : ISettable<Ares64.Ares64Settings, Ares64.Ares64SyncSettings>

View File

@ -0,0 +1,38 @@
using System;
using System.Text.RegularExpressions;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
{
public partial class Ares64
{
private ITraceable Tracer { get; }
private readonly LibAres64.TraceCallback _tracecb;
private void MakeTrace(IntPtr disasm)
{
var regs = GetCpuFlagsAndRegisters();
var regsStr = "";
foreach (var r in regs)
{
if (r.Key is not "PC")
{
regsStr += r.Key + $":{r.Value.Value:X16} ";
}
}
regsStr = regsStr.Remove(regsStr.Length - 1, 1);
var disasmStr = Mershul.PtrToStringUtf8(disasm);
disasmStr = disasmStr.Remove(0, 5); // remove "CPU "
disasmStr = disasmStr.Replace("\n", ""); // remove newlines
disasmStr = Regex.Replace(disasmStr, @"\{.*\}", ""); // remove any {*} patterns
Tracer.Put(new(
disassembly: disasmStr,
registerInfo: regsStr));
}
}
}

View File

@ -8,11 +8,12 @@ using BizHawk.Emulation.Cores.Waterbox;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
{
[PortedCore(CoreNames.Ares64, "ares team, Near", "v127", "https://ares-emulator.github.io/", isReleased: false)]
[PortedCore(CoreNames.Ares64, "ares team, Near", "v127", "https://ares-emulator.github.io/")]
[ServiceNotApplicable(new[] { typeof(IDriveLight), })]
public partial class Ares64 : WaterboxCore, IRegionable
{
private readonly LibAres64 _core;
private readonly Ares64Disassembler _disassembler;
[CoreConstructor(VSystemID.Raw.N64)]
public Ares64(CoreLoadParameters<Ares64Settings, Ares64SyncSettings> lp)
@ -40,6 +41,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
};
N64Controller = CreateControllerDefinition(ControllerSettings);
_tracecb = MakeTrace;
_core = PreInit<LibAres64>(new WaterboxOptions
{
@ -51,7 +53,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
MmapHeapSizeKB = 512 * 1024,
SkipCoreConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
});
}, new[] { _tracecb, });
var rom = lp.Roms[0].RomData;
@ -114,6 +116,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
PostInit();
Tracer = new TraceBuffer("r3400: PC, mnemonic, operands, registers (GPRs, Load/Link Bit, MultHI, MultLO, Implementation/Revision, Control/Status, FGRs)");
_serviceProvider.Register(Tracer);
_disassembler = new(_core);
_serviceProvider.Register<IDisassemblable>(_disassembler);
DeterministicEmulation = lp.DeterministicEmulationRequested || (!_syncSettings.UseRealTime);
InitializeRtc(_syncSettings.InitialTime);
}
@ -203,6 +211,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
{
_core.SetTraceCallback(Tracer.IsEnabled() ? _tracecb : null);
for (int i = 0; i < 4; i++)
{
if (ControllerSettings[i] == LibAres64.ControllerType.Rumblepak)

View File

@ -99,5 +99,17 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
[BizImport(CC)]
public abstract bool GetRumbleStatus(int num);
[BizImport(CC)]
public abstract void GetDisassembly(uint address, uint instruction, byte[] buf);
[UnmanagedFunctionPointer(CC)]
public delegate void TraceCallback(IntPtr disasm);
[BizImport(CC)]
public abstract void SetTraceCallback(TraceCallback callback);
[BizImport(CC)]
public abstract void GetRegisters(ulong[] buf);
}
}

View File

@ -46,6 +46,7 @@ struct BizPlatform : ares::Platform
{
auto attach(ares::Node::Object) -> void override;
auto pak(ares::Node::Object) -> ares::VFS::Pak override;
auto log(string_view) -> void override;
auto video(ares::Node::Video::Screen, const u32*, u32, u32, u32) -> void override;
auto audio(ares::Node::Audio::Stream) -> void override;
auto input(ares::Node::Input::Input) -> void override;
@ -60,6 +61,7 @@ struct BizPlatform : ares::Platform
bool hack = false;
void (*inputcb)() = nullptr;
bool lagged = true;
void (*tracecb)(const char*) = nullptr;
};
auto BizPlatform::attach(ares::Node::Object node) -> void
@ -75,6 +77,11 @@ auto BizPlatform::pak(ares::Node::Object) -> ares::VFS::Pak
return bizpak;
}
auto BizPlatform::log(string_view message) -> void
{
if (tracecb) tracecb(message.data());
}
auto BizPlatform::video(ares::Node::Video::Screen screen, const u32* data, u32 pitch, u32 width, u32 height) -> void
{
videobuf = (u32*)data;
@ -566,17 +573,76 @@ EXPORT bool GetRumbleStatus(u32 num)
m[i].Data = c->transferPak.rom.data; \
m[i].Name = "GB ROM " #NUM; \
m[i].Size = c->transferPak.rom.size; \
m[i].Flags = MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_SWAPPED | MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE; \
m[i].Flags = MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_SWAPPED | MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE; \
i++; \
\
m[i].Data = c->transferPak.ram.data; \
m[i].Name = "GB SRAM " #NUM; \
m[i].Size = c->transferPak.ram.size; \
m[i].Flags = MEMORYAREA_FLAGS_ONEFILLED | MEMORYAREA_FLAGS_SAVERAMMABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_SWAPPED | MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE; \
m[i].Flags = MEMORYAREA_FLAGS_ONEFILLED | MEMORYAREA_FLAGS_SAVERAMMABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_SWAPPED | MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE; \
i++; \
} \
} while (0)
static inline u8 GetByteFromWord(u32 word, u32 addr)
{
switch (addr & 3)
{
case 0: return (word >> 24) & 0xFF;
case 1: return (word >> 16) & 0xFF;
case 2: return (word >> 8) & 0xFF;
case 3: return (word >> 0) & 0xFF;
default: __builtin_unreachable();
}
}
static u8 PeekFunc(u64 address)
{
address &= 0x1fff'ffff;
const u32 addr = address;
if (addr > 0x0403'ffff && addr <= 0x0407'ffff) // RSP
{
address = (address & 0x3ffff) >> 2;
if (address == 7) // SP_SEMAPHORE
{
return GetByteFromWord(ares::Nintendo64::rsp.status.semaphore & 1, addr);
}
}
else if (addr > 0x0407'ffff && addr <= 0x040f'ffff) // RSP Status
{
address = (address & 0x7ffff) >> 2;
if (address == 0) // SP_PC_REG
{
return GetByteFromWord(ares::Nintendo64::rsp.ipu.pc & 0xFFF, addr);
}
}
else if (addr > 0x046f'ffff && addr <= 0x047f'ffff) // RI
{
address = (address & 0xfffff) >> 2;
if (address == 3) // RI_SELECT
{
return GetByteFromWord(ares::Nintendo64::ri.io.select, addr);
}
}
return ares::Nintendo64::bus.read<ares::Nintendo64::Byte>(addr);
}
static void SysBusAccess(u8* buffer, u64 address, u64 count, bool write)
{
if (write)
{
while (count--)
ares::Nintendo64::bus.write<ares::Nintendo64::Byte>(address++, *buffer++);
}
else
{
while (count--)
*buffer++ = PeekFunc(address++);
}
}
EXPORT void GetMemoryAreas(MemoryArea *m)
{
int i = 0;
@ -597,6 +663,11 @@ EXPORT void GetMemoryAreas(MemoryArea *m)
ADD_GB_DOMAINS(2);
ADD_GB_DOMAINS(3);
ADD_GB_DOMAINS(4);
m[i].Data = (void*)SysBusAccess;
m[i].Name = "System Bus";
m[i].Size = 1ull << 32;
m[i].Flags = MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_SWAPPED | MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_FUNCTIONHOOK;
}
struct MyFrameInfo : public FrameInfo
@ -698,3 +769,27 @@ EXPORT void SetInputCallback(void (*callback)())
{
platform->inputcb = callback;
}
EXPORT void GetDisassembly(u32 address, u32 instruction, char* buf)
{
auto s = ares::Nintendo64::cpu.disassembler.disassemble(address, instruction).strip();
strcpy(buf, s.data());
}
EXPORT void SetTraceCallback(void (*callback)(const char*))
{
ares::Nintendo64::cpu.debugger.tracer.instruction->setEnabled(!!callback);
platform->tracecb = callback;
}
EXPORT void GetRegisters(u64* buf)
{
for (int i = 0; i < 32; i++)
{
buf[i] = ares::Nintendo64::cpu.ipu.r[i].u64;
}
buf[32] = ares::Nintendo64::cpu.ipu.lo.u64;
buf[33] = ares::Nintendo64::cpu.ipu.hi.u64;
buf[34] = ares::Nintendo64::cpu.ipu.pc;
}