MSXHawk: Tracer Support

This commit is contained in:
alyosha-tas 2020-01-15 20:47:50 -05:00
parent 1e195243be
commit ce7d6cdcf5
7 changed files with 504 additions and 203 deletions

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}
};
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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
};
}