MSXHawk: Tracer Support
This commit is contained in:
parent
1e195243be
commit
ce7d6cdcf5
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using BizHawk.Emulation.Common;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.MSX
|
||||
{
|
||||
|
@ -39,5 +40,68 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
|
|||
/// <returns>0 on success, negative value on failure.</returns>
|
||||
[DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool MSX_frame_advance(IntPtr core, byte ctrl1, byte ctrl2, bool render, bool sound);
|
||||
|
||||
/// <summary>
|
||||
/// Get Video data
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="ctrl1">controller data for player 1</param>
|
||||
/// <param name="ctrl2">controller data for player 2</param>
|
||||
/// <param name="render">length of romdata in bytes</param>
|
||||
/// <param name="sound">Mapper number to load core with</param>
|
||||
/// <returns>0 on success, negative value on failure.</returns>
|
||||
[DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void MSX_get_video(IntPtr core, int[] videobuf);
|
||||
|
||||
/// <summary>
|
||||
/// type of the cpu trace callback
|
||||
/// </summary>
|
||||
/// <param name="t">type of event</param>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void TraceCallback(int t);
|
||||
|
||||
/// <summary>
|
||||
/// set a callback for trace logging
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="callback">null to clear</param>
|
||||
[DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void MSX_settracecallback(IntPtr core, TraceCallback callback);
|
||||
|
||||
/// <summary>
|
||||
/// get the trace logger header
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="h">pointer to const char *</param>
|
||||
/// <param name="callback">null to clear</param>
|
||||
[DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void MSX_getheader(IntPtr core, StringBuilder h);
|
||||
|
||||
/// <summary>
|
||||
/// get the trace logger header length
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="h">pointer to const char *</param>
|
||||
/// <param name="callback">null to clear</param>
|
||||
[DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int MSX_getheaderlength(IntPtr core);
|
||||
|
||||
/// <summary>
|
||||
/// get the register state from the cpu
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="r">pointer to const char *</param>
|
||||
/// <param name="t">call type</param>
|
||||
[DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void MSX_getregisterstate(IntPtr core, StringBuilder h, int t);
|
||||
|
||||
/// <summary>
|
||||
/// get the register state from the cpu
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="d">pointer to const char *</param>
|
||||
/// <param name="t">call type</param>
|
||||
[DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void MSX_getdisassembly(IntPtr core, StringBuilder h, int t);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,21 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
|
|||
_controller = controller;
|
||||
|
||||
_frame++;
|
||||
|
||||
if (Tracer.Enabled)
|
||||
{
|
||||
tracecb = MakeTrace;
|
||||
}
|
||||
else
|
||||
{
|
||||
tracecb = null;
|
||||
}
|
||||
|
||||
return LibMSX.MSX_frame_advance(MSX_Pntr, 0, 0, true, true);
|
||||
LibMSX.MSX_settracecallback(MSX_Pntr, tracecb);
|
||||
|
||||
LibMSX.MSX_frame_advance(MSX_Pntr, 0, 0, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int Frame => _frame;
|
||||
|
@ -119,13 +132,12 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
|
|||
#region Video
|
||||
public int _frameHz = 60;
|
||||
|
||||
public int[] _vidbuffer;
|
||||
|
||||
public int[] frame_buffer = new int[160 * 144];
|
||||
public int[] _vidbuffer = new int[160 * 144];
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return frame_buffer;
|
||||
LibMSX.MSX_get_video(MSX_Pntr, _vidbuffer);
|
||||
return _vidbuffer;
|
||||
}
|
||||
|
||||
public int VirtualWidth => 160;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using System;
|
||||
|
||||
using System.Text;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.MSX
|
||||
|
@ -39,8 +39,14 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
|
|||
|
||||
InputCallbacks = new InputCallbackSystem();
|
||||
|
||||
//var serviceProvider = ServiceProvider as BasicServiceProvider;
|
||||
//serviceProvider.Register<ITraceable>(Tracer);
|
||||
int new_header_size = LibMSX.MSX_getheaderlength(MSX_Pntr);
|
||||
StringBuilder new_header = new StringBuilder(new_header_size);
|
||||
LibMSX.MSX_getheader(MSX_Pntr, new_header);
|
||||
|
||||
Tracer = new TraceBuffer { Header = new_header.ToString() };
|
||||
|
||||
var serviceProvider = ServiceProvider as BasicServiceProvider;
|
||||
serviceProvider.Register<ITraceable>(Tracer);
|
||||
}
|
||||
|
||||
public void HardReset()
|
||||
|
@ -63,7 +69,29 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
|
|||
|
||||
public DisplayType Region => DisplayType.NTSC;
|
||||
|
||||
private readonly ITraceable Tracer;
|
||||
#region Trace Logger
|
||||
private ITraceable Tracer;
|
||||
|
||||
private LibMSX.TraceCallback tracecb;
|
||||
|
||||
private void MakeTrace(int t)
|
||||
{
|
||||
|
||||
|
||||
StringBuilder new_d = new StringBuilder(500);
|
||||
StringBuilder new_r = new StringBuilder(500);
|
||||
|
||||
LibMSX.MSX_getdisassembly(MSX_Pntr, new_d, t);
|
||||
LibMSX.MSX_getregisterstate(MSX_Pntr, new_r, t);
|
||||
|
||||
Tracer.Put(new TraceInfo
|
||||
{
|
||||
Disassembly = new_d.ToString().PadRight(36),
|
||||
RegisterInfo = new_r.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(new[] { "System Bus" });
|
||||
public IMemoryCallbackSystem MemoryCallbacks => _memorycallbacks;
|
||||
|
|
|
@ -21,6 +21,11 @@ namespace MSXHawk
|
|||
cpu.mem_ctrl = &MemMap;
|
||||
};
|
||||
|
||||
VDP vdp;
|
||||
Z80A cpu;
|
||||
SN76489sms psg;
|
||||
MemoryManager MemMap;
|
||||
|
||||
void Load_ROM(uint8_t* ext_rom, uint32_t ext_rom_size, uint32_t ext_rom_mapper)
|
||||
{
|
||||
MemMap.Load_ROM(ext_rom, ext_rom_size, ext_rom_mapper);
|
||||
|
@ -78,10 +83,60 @@ namespace MSXHawk
|
|||
return MemMap.lagged;
|
||||
}
|
||||
|
||||
VDP vdp;
|
||||
Z80A cpu;
|
||||
SN76489sms psg;
|
||||
MemoryManager MemMap;
|
||||
void GetVideo(uint32_t* dest) {
|
||||
uint32_t* src = vdp.GameGearFrameBuffer;
|
||||
uint32_t* dst = dest;
|
||||
|
||||
for (int i = 0; i < 144; i++)
|
||||
{
|
||||
std::memcpy(dst, src, sizeof uint32_t * 160);
|
||||
src += 160;
|
||||
dst += 160;
|
||||
}
|
||||
}
|
||||
|
||||
void SetTraceCallback(void (*callback)(int))
|
||||
{
|
||||
cpu.TraceCallback = callback;
|
||||
}
|
||||
|
||||
void GetHeader(char* h)
|
||||
{
|
||||
memcpy(h, cpu.TraceHeader, *(&cpu.TraceHeader + 1) - cpu.TraceHeader);
|
||||
}
|
||||
|
||||
int GetHeaderLength()
|
||||
{
|
||||
return *(&cpu.TraceHeader + 1) - cpu.TraceHeader;
|
||||
}
|
||||
|
||||
void GetRegisterState(char* r, int t)
|
||||
{
|
||||
if (t == 0)
|
||||
{
|
||||
memcpy(r, cpu.CPURegisterState().c_str(), cpu.CPURegisterState().length() + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(r, cpu.No_Reg, *(&cpu.No_Reg + 1) - cpu.No_Reg);
|
||||
}
|
||||
}
|
||||
|
||||
void GetDisassembly(char* d, int t)
|
||||
{
|
||||
if (t == 0)
|
||||
{
|
||||
memcpy(d, cpu.CPUDisassembly().c_str(), cpu.CPUDisassembly().length() + 1);
|
||||
}
|
||||
else if (t == 1)
|
||||
{
|
||||
memcpy(d, cpu.NMI_event, *(&cpu.NMI_event + 1) - cpu.NMI_event);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(d, cpu.IRQ_event, *(&cpu.IRQ_event + 1) - cpu.IRQ_event);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -35,3 +35,34 @@ MSXHAWK_EXPORT void MSX_frame_advance(MSXCore* p, uint8_t ctrl1, uint8_t ctrl2,
|
|||
p->FrameAdvance(ctrl1, ctrl2, render, sound);
|
||||
}
|
||||
|
||||
// send video data to external video provider
|
||||
MSXHAWK_EXPORT void MSX_get_video(MSXCore* p, uint32_t* dest)
|
||||
{
|
||||
p->GetVideo(dest);
|
||||
}
|
||||
|
||||
// set tracer callback
|
||||
MSXHAWK_EXPORT void MSX_settracecallback(MSXCore* p, void (*callback)(int)) {
|
||||
p->SetTraceCallback(callback);
|
||||
}
|
||||
|
||||
// return the cpu trace header
|
||||
MSXHAWK_EXPORT void MSX_getheader(MSXCore* p, char* h) {
|
||||
p->GetHeader(h);
|
||||
}
|
||||
|
||||
// return the cpu trace header length
|
||||
MSXHAWK_EXPORT int MSX_getheaderlength(MSXCore* p) {
|
||||
return p->GetHeaderLength();
|
||||
}
|
||||
|
||||
// return the cpu register state
|
||||
MSXHAWK_EXPORT void MSX_getregisterstate(MSXCore* p, char* r, int t) {
|
||||
p->GetRegisterState(r, t);
|
||||
}
|
||||
|
||||
// return the cpu disassembly
|
||||
MSXHAWK_EXPORT void MSX_getdisassembly(MSXCore* p, char* d, int t) {
|
||||
p->GetDisassembly(d, t);
|
||||
}
|
||||
|
||||
|
|
|
@ -59,8 +59,8 @@ namespace MSXHawk
|
|||
|
||||
int32_t IPeriod = 228;
|
||||
int32_t FrameHeight = 192;
|
||||
int32_t FrameBuffer[256 * 244];
|
||||
int32_t GameGearFrameBuffer[160 * 144];
|
||||
uint32_t FrameBuffer[256 * 244];
|
||||
uint32_t GameGearFrameBuffer[160 * 144];
|
||||
int32_t OverscanFrameBuffer[1];
|
||||
int32_t ScanLine;
|
||||
|
||||
|
|
|
@ -118,6 +118,8 @@ namespace MSXHawk
|
|||
interruptMode = value;
|
||||
}
|
||||
|
||||
char replacer[32] = {};
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Constant Declarations
|
||||
|
@ -263,8 +265,8 @@ namespace MSXHawk
|
|||
|
||||
Z80A()
|
||||
{
|
||||
//Reset();
|
||||
//InitTableParity();
|
||||
Reset();
|
||||
InitTableParity();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
|
@ -308,7 +310,9 @@ namespace MSXHawk
|
|||
case OP_F:
|
||||
// Read the opcode of the next instruction
|
||||
//if (OnExecFetch != null) OnExecFetch(RegPC);
|
||||
//if (TraceCallback != null) TraceCallback(State());
|
||||
|
||||
if (TraceCallback) { TraceCallback(0); }
|
||||
|
||||
bank_num = bank_offset = RegPCget();
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
|
@ -786,12 +790,9 @@ namespace MSXHawk
|
|||
if (nonMaskableInterruptPending)
|
||||
{
|
||||
nonMaskableInterruptPending = false;
|
||||
/*
|
||||
if (TraceCallback != null)
|
||||
{
|
||||
TraceCallback(new TraceInfo{ Disassembly = "====NMI====", RegisterInfo = "" });
|
||||
}
|
||||
*/
|
||||
|
||||
if (TraceCallback) { TraceCallback(1); }
|
||||
|
||||
IFF2 = IFF1;
|
||||
IFF1 = false;
|
||||
NMI_();
|
||||
|
@ -810,12 +811,9 @@ namespace MSXHawk
|
|||
{
|
||||
IFF1 = IFF2 = false;
|
||||
EI_pending = 0;
|
||||
/*
|
||||
if (TraceCallback != null)
|
||||
{
|
||||
TraceCallback(new TraceInfo{ Disassembly = "====IRQ====", RegisterInfo = "" });
|
||||
}
|
||||
*/
|
||||
|
||||
if (TraceCallback) { TraceCallback(2); }
|
||||
|
||||
switch (interruptMode)
|
||||
{
|
||||
case 0:
|
||||
|
@ -864,64 +862,6 @@ namespace MSXHawk
|
|||
TotalExecutedCycles++;
|
||||
}
|
||||
|
||||
const string TraceHeader = "Z80A: PC, machine code, mnemonic, operands, registers (AF, BC, DE, HL, IX, IY, SP, Cy), flags (CNP3H5ZS)";
|
||||
|
||||
string CPUDisassembly()
|
||||
{
|
||||
return "";
|
||||
|
||||
/*
|
||||
uint32_t bytes_read = 0;
|
||||
|
||||
int* bytes_read_ptr = &bytes_read;
|
||||
|
||||
string disasm = disassemble ? Disassemble(RegPCget(), bytes_read_ptr) : "---";
|
||||
string byte_code = "";
|
||||
|
||||
for (uint32_t i = 0; i < bytes_read; i++)
|
||||
{
|
||||
byte_code += $"{ReadMemory((uint32_t)(RegPC + i)):X2}";
|
||||
if (i < (bytes_read - 1))
|
||||
{
|
||||
byte_code += " ";
|
||||
}
|
||||
}
|
||||
|
||||
return new TraceInfo
|
||||
{
|
||||
Disassembly = $"{RegPC:X4}: {byte_code.PadRight(12)} {disasm.PadRight(26)}",
|
||||
|
||||
};
|
||||
*/
|
||||
}
|
||||
|
||||
string CPURegisterState()
|
||||
{
|
||||
return "";
|
||||
|
||||
/*
|
||||
RegisterInfo = string.Join(" ",
|
||||
$"AF:{(Regs[A] << 8) + Regs[F]:X4}",
|
||||
$"BC:{(Regs[B] << 8) + Regs[C]:X4}",
|
||||
$"DE:{(Regs[D] << 8) + Regs[E]:X4}",
|
||||
$"HL:{(Regs[H] << 8) + Regs[L]:X4}",
|
||||
$"IX:{(Regs[Ixh] << 8) + Regs[Ixl]:X4}",
|
||||
$"IY:{(Regs[Iyh] << 8) + Regs[Iyl]:X4}",
|
||||
$"SP:{Regs[SPl] | (Regs[SPh] << 8):X4}",
|
||||
$"Cy:{TotalExecutedCycles}",
|
||||
string.Concat(
|
||||
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"))
|
||||
*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optimization method to set BUSRQ
|
||||
/// </summary>
|
||||
|
@ -4509,25 +4449,302 @@ namespace MSXHawk
|
|||
|
||||
#pragma region Disassemble
|
||||
|
||||
static string Result(string format, uint32_t addr)
|
||||
const char* TraceHeader = "Z80A: PC, machine code, mnemonic, operands, registers (AF, BC, DE, HL, IX, IY, SP, Cy), flags (CNP3H5ZS)";
|
||||
const char* NMI_event = "====NMI====";
|
||||
const char* IRQ_event = "====IRQ====";
|
||||
const char* No_Reg = "Q";
|
||||
|
||||
void (*TraceCallback)(int);
|
||||
|
||||
string CPURegisterState()
|
||||
{
|
||||
string reg_state = " ";
|
||||
|
||||
char* val_char = replacer;
|
||||
|
||||
int temp_reg = (Regs[A] << 8) + Regs[F];
|
||||
sprintf_s(val_char, 5, "%04X", temp_reg);
|
||||
reg_state.append(val_char, 4);
|
||||
reg_state.append(" ");
|
||||
|
||||
temp_reg = (Regs[B] << 8) + Regs[C];
|
||||
sprintf_s(val_char, 5, "%04X", temp_reg);
|
||||
reg_state.append(val_char, 4);
|
||||
reg_state.append(" ");
|
||||
|
||||
temp_reg = (Regs[D] << 8) + Regs[E];
|
||||
sprintf_s(val_char, 5, "%04X", temp_reg);
|
||||
reg_state.append(val_char, 4);
|
||||
reg_state.append(" ");
|
||||
|
||||
temp_reg = (Regs[H] << 8) + Regs[L];
|
||||
sprintf_s(val_char, 5, "%04X", temp_reg);
|
||||
reg_state.append(val_char, 4);
|
||||
reg_state.append(" ");
|
||||
|
||||
temp_reg = (Regs[Ixh] << 8) + Regs[Ixl];
|
||||
sprintf_s(val_char, 5, "%04X", temp_reg);
|
||||
reg_state.append(val_char, 4);
|
||||
reg_state.append(" ");
|
||||
|
||||
temp_reg = (Regs[Iyh] << 8) + Regs[Iyl];
|
||||
sprintf_s(val_char, 5, "%04X", temp_reg);
|
||||
reg_state.append(val_char, 4);
|
||||
reg_state.append(" ");
|
||||
|
||||
temp_reg = (Regs[SPh] << 8) + Regs[SPl];
|
||||
sprintf_s(val_char, 5, "%04X", temp_reg);
|
||||
reg_state.append(val_char, 4);
|
||||
reg_state.append(" ");
|
||||
|
||||
int tot_long = sprintf_s(val_char, 32, "%16u", TotalExecutedCycles);
|
||||
reg_state.append(val_char, tot_long);
|
||||
reg_state.append(" ");
|
||||
|
||||
reg_state.append(FlagCget() ? "C" : "c");
|
||||
reg_state.append(FlagNget() ? "N" : "n");
|
||||
reg_state.append(FlagPget() ? "P" : "p");
|
||||
reg_state.append(Flag3get() ? "3" : "-");
|
||||
reg_state.append(FlagHget() ? "H" : "h");
|
||||
reg_state.append(Flag5get() ? "5" : "-");
|
||||
reg_state.append(FlagZget() ? "Z" : "z");
|
||||
reg_state.append(FlagSget() ? "S" : "s");
|
||||
reg_state.append(FlagI ? "E" : "e");
|
||||
|
||||
return reg_state;
|
||||
}
|
||||
|
||||
string CPUDisassembly()
|
||||
{
|
||||
uint32_t bytes_read = 0;
|
||||
|
||||
uint32_t* bytes_read_ptr = &bytes_read;
|
||||
|
||||
string disasm = Disassemble(RegPCget(), bytes_read_ptr);
|
||||
string byte_code = "";
|
||||
|
||||
for (uint32_t i = 0; i < bytes_read; i++)
|
||||
{
|
||||
bank_num = bank_offset = (RegPCget() + i) & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
|
||||
char* val_char_1 = replacer;
|
||||
sprintf_s(val_char_1, 5, "%02X", MemoryMap[bank_num][bank_offset]);
|
||||
string val1(val_char_1, 2);
|
||||
|
||||
byte_code.append(val1);
|
||||
if (i < (bytes_read - 1))
|
||||
{
|
||||
byte_code.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
byte_code.append(disasm);
|
||||
|
||||
while (byte_code.length() < 32)
|
||||
{
|
||||
byte_code.append(" ");
|
||||
}
|
||||
|
||||
return byte_code;
|
||||
}
|
||||
|
||||
string Result(string format, uint32_t addr)
|
||||
{
|
||||
//d immediately succeeds the opcode
|
||||
//n immediate succeeds the opcode and the displacement (if present)
|
||||
//nn immediately succeeds the opcode and the displacement (if present)
|
||||
/*
|
||||
if (format.IndexOf("nn") != -1) format = format.Replace("nn", $"{read(addr++) + (read(addr++) << 8):X4}h"); // LSB is read first
|
||||
if (format.IndexOf("n") != -1) format = format.Replace("n", $"{read(addr++):X2}h");
|
||||
|
||||
if (format.IndexOf("+d") != -1) format = format.Replace("+d", "d");
|
||||
if (format.IndexOf("d") != -1)
|
||||
if (format.find("nn") != string::npos)
|
||||
{
|
||||
var b = unchecked((sbyte)read(addr++));
|
||||
format = format.Replace("d", $"{(b < 0 ? '-' : '+')}{(b < 0 ? -b : b):X2}h");
|
||||
size_t str_loc = format.find("nn");
|
||||
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift) & high_mask;
|
||||
addr++;
|
||||
|
||||
char* val_char_1 = replacer;
|
||||
sprintf_s(val_char_1, 5, "%02X", MemoryMap[bank_num][bank_offset]);
|
||||
string val1(val_char_1, 2);
|
||||
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
addr++;
|
||||
|
||||
char* val_char_2 = replacer;
|
||||
sprintf_s(val_char_2, 5, "%02X", MemoryMap[bank_num][bank_offset]);
|
||||
string val2(val_char_2, 2);
|
||||
|
||||
format.erase(str_loc, 2);
|
||||
format.insert(str_loc, val1);
|
||||
format.insert(str_loc, val2);
|
||||
}
|
||||
*/
|
||||
|
||||
if (format.find("n") != string::npos)
|
||||
{
|
||||
size_t str_loc = format.find("n");
|
||||
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
addr++;
|
||||
|
||||
char* val_char_1 = replacer;
|
||||
sprintf_s(val_char_1, 5, "%02X", MemoryMap[bank_num][bank_offset]);
|
||||
string val1(val_char_1, 2);
|
||||
|
||||
format.erase(str_loc, 1);
|
||||
format.insert(str_loc, val1);
|
||||
}
|
||||
|
||||
if (format.find("+d") != string::npos)
|
||||
{
|
||||
size_t str_loc = format.find("+d");
|
||||
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
addr++;
|
||||
|
||||
char* val_char_1 = replacer;
|
||||
sprintf_s(val_char_1, 5, "%u", MemoryMap[bank_num][bank_offset]);
|
||||
string val1(val_char_1, 2);
|
||||
|
||||
format.erase(str_loc + 1, 1);
|
||||
format.insert(str_loc + 1, val1);
|
||||
}
|
||||
if (format.find("d") != string::npos)
|
||||
{
|
||||
size_t str_loc = format.find("d");
|
||||
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
addr++;
|
||||
|
||||
int8_t temp = (int8_t)MemoryMap[bank_num][bank_offset];
|
||||
|
||||
char* val_char_1 = replacer;
|
||||
sprintf_s(val_char_1, 5, "%d", temp);
|
||||
string val1(val_char_1, 3);
|
||||
|
||||
format.erase(str_loc, 1);
|
||||
format.insert(str_loc, val1);
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
string Disassemble(uint32_t addr, uint32_t* size)
|
||||
{
|
||||
uint32_t start_addr = addr;
|
||||
uint32_t extra_inc = 0;
|
||||
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift) & high_mask;
|
||||
addr++;
|
||||
|
||||
uint32_t A = MemoryMap[bank_num][bank_offset];
|
||||
string format;
|
||||
switch (A)
|
||||
{
|
||||
case 0xCB:
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift) & high_mask;
|
||||
addr++;
|
||||
|
||||
A = MemoryMap[bank_num][bank_offset];
|
||||
format = mnemonicsCB[A];
|
||||
break;
|
||||
case 0xDD:
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift) & high_mask;
|
||||
addr++;
|
||||
|
||||
A = MemoryMap[bank_num][bank_offset];
|
||||
switch (A)
|
||||
{
|
||||
case 0xCB:
|
||||
bank_num = bank_offset = (addr + 1) & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift) & high_mask;
|
||||
|
||||
format = mnemonicsDDCB[MemoryMap[bank_num][bank_offset]];
|
||||
extra_inc = 1;
|
||||
break;
|
||||
case 0xED:
|
||||
format = mnemonicsED[A];
|
||||
break;
|
||||
default:
|
||||
format = mnemonicsDD[A];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xED:
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift) & high_mask;
|
||||
addr++;
|
||||
|
||||
A = MemoryMap[bank_num][bank_offset];
|
||||
format = mnemonicsED[A];
|
||||
break;
|
||||
case 0xFD:
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift) & high_mask;
|
||||
addr++;
|
||||
|
||||
A = MemoryMap[bank_num][bank_offset];
|
||||
switch (A)
|
||||
{
|
||||
case 0xCB:
|
||||
bank_num = bank_offset = (addr + 1) & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
|
||||
format = mnemonicsFDCB[MemoryMap[bank_num][bank_offset]];
|
||||
extra_inc = 1;
|
||||
break;
|
||||
case 0xED:
|
||||
format = mnemonicsED[A];
|
||||
break;
|
||||
default:
|
||||
format = mnemonicsFD[A];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default: format = mnemonics[A]; break;
|
||||
}
|
||||
|
||||
string temp = Result(format, addr);
|
||||
|
||||
addr += extra_inc;
|
||||
|
||||
size[0] = addr - start_addr;
|
||||
// handle case of addr wrapping around at 16 bit boundary
|
||||
if (addr < start_addr)
|
||||
{
|
||||
size[0] = (0x10000 + addr) - start_addr;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/*
|
||||
string Disassemble(MemoryDomain m, uuint32_t addr, out uint32_t length)
|
||||
{
|
||||
string ret = Disassemble((uint32_t)addr, a = > m.PeekByte(a), out length);
|
||||
return ret;
|
||||
}
|
||||
*/
|
||||
|
||||
const string mnemonics[256] =
|
||||
{
|
||||
"NOP", "LD BC, nn", "LD (BC), A", "INC BC", //0x04
|
||||
|
@ -4881,112 +5098,6 @@ namespace MSXHawk
|
|||
"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0xF0
|
||||
"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0x100
|
||||
};
|
||||
|
||||
string Disassemble(uint32_t addr, int* size)
|
||||
{
|
||||
uint32_t start_addr = addr;
|
||||
uint32_t extra_inc = 0;
|
||||
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
addr++;
|
||||
|
||||
uint32_t A = MemoryMap[bank_num][bank_offset];
|
||||
string format;
|
||||
switch (A)
|
||||
{
|
||||
case 0xCB:
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
addr++;
|
||||
|
||||
A = MemoryMap[bank_num][bank_offset];
|
||||
format = mnemonicsCB[A];
|
||||
break;
|
||||
case 0xDD:
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
addr++;
|
||||
|
||||
A = MemoryMap[bank_num][bank_offset];
|
||||
switch (A)
|
||||
{
|
||||
case 0xCB:
|
||||
bank_num = bank_offset = (addr + 1) & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
|
||||
format = mnemonicsDDCB[MemoryMap[bank_num][bank_offset]];
|
||||
extra_inc = 1;
|
||||
break;
|
||||
case 0xED:
|
||||
format = mnemonicsED[A];
|
||||
break;
|
||||
default:
|
||||
format = mnemonicsDD[A];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xED:
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
addr++;
|
||||
|
||||
A = MemoryMap[bank_num][bank_offset];
|
||||
format = mnemonicsED[A];
|
||||
break;
|
||||
case 0xFD:
|
||||
bank_num = bank_offset = addr & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
addr++;
|
||||
|
||||
A = MemoryMap[bank_num][bank_offset];
|
||||
switch (A)
|
||||
{
|
||||
case 0xCB:
|
||||
bank_num = bank_offset = (addr + 1) & 0xFFFF;
|
||||
bank_offset &= low_mask;
|
||||
bank_num = (bank_num >> bank_shift)& high_mask;
|
||||
|
||||
format = mnemonicsFDCB[MemoryMap[bank_num][bank_offset]];
|
||||
extra_inc = 1;
|
||||
break;
|
||||
case 0xED:
|
||||
format = mnemonicsED[A];
|
||||
break;
|
||||
default:
|
||||
format = mnemonicsFD[A];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default: format = mnemonics[A]; break;
|
||||
}
|
||||
|
||||
string temp = Result(format, addr);
|
||||
|
||||
addr += extra_inc;
|
||||
|
||||
size[0] = addr - start_addr;
|
||||
// handle case of addr wrapping around at 16 bit boundary
|
||||
if (addr < start_addr)
|
||||
{
|
||||
size[0] = (0x10000 + addr) - start_addr;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
/*
|
||||
string Disassemble(MemoryDomain m, uuint32_t addr, out uint32_t length)
|
||||
{
|
||||
string ret = Disassemble((uint32_t)addr, a = > m.PeekByte(a), out length);
|
||||
return ret;
|
||||
}
|
||||
*/
|
||||
#pragma endregion
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue