mirror of https://github.com/bsnes-emu/bsnes.git
Update to v072r04 release.
(there was no r03 release posted to the WIP thread) byuu says: nall/snes/smp.hpp created, ~68 addressing modes compared to the CPU's ~27, ugh. All hooked up, you can step into / step over / trace the S-SMP now as well.
This commit is contained in:
parent
0730f847e5
commit
edac93b800
|
@ -1,13 +1,12 @@
|
|||
#ifndef NALL_SNES_INFO_HPP
|
||||
#define NALL_SNES_INFO_HPP
|
||||
#ifndef NALL_SNES_CARTRIDGE_HPP
|
||||
#define NALL_SNES_CARTRIDGE_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
class snes_information {
|
||||
class SNESCartridge {
|
||||
public:
|
||||
string xml_memory_map;
|
||||
|
||||
inline snes_information(const uint8_t *data, unsigned size);
|
||||
string xmlMemoryMap;
|
||||
inline SNESCartridge(const uint8_t *data, unsigned size);
|
||||
|
||||
//private:
|
||||
inline void read_header(const uint8_t *data, unsigned size);
|
||||
|
@ -106,20 +105,20 @@ public:
|
|||
bool has_st018;
|
||||
};
|
||||
|
||||
snes_information::snes_information(const uint8_t *data, unsigned size) {
|
||||
SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
read_header(data, size);
|
||||
|
||||
string xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
|
||||
|
||||
if(type == TypeBsx) {
|
||||
xml << "<cartridge/>";
|
||||
xml_memory_map = xml;
|
||||
xmlMemoryMap = xml;
|
||||
return;
|
||||
}
|
||||
|
||||
if(type == TypeSufamiTurbo) {
|
||||
xml << "<cartridge/>";
|
||||
xml_memory_map = xml;
|
||||
xmlMemoryMap = xml;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -129,7 +128,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
|
|||
xml << " <ram size='" << strhex(gameboy_ram_size(data, size)) << "'/>\n";
|
||||
}
|
||||
xml << "</cartridge>\n";
|
||||
xml_memory_map = xml;
|
||||
xmlMemoryMap = xml;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -518,10 +517,10 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
|
|||
}
|
||||
|
||||
xml << "</cartridge>\n";
|
||||
xml_memory_map = xml;
|
||||
xmlMemoryMap = xml;
|
||||
}
|
||||
|
||||
void snes_information::read_header(const uint8_t *data, unsigned size) {
|
||||
void SNESCartridge::read_header(const uint8_t *data, unsigned size) {
|
||||
type = TypeUnknown;
|
||||
mapper = LoROM;
|
||||
dsp1_mapper = DSP1Unmapped;
|
||||
|
@ -749,7 +748,7 @@ void snes_information::read_header(const uint8_t *data, unsigned size) {
|
|||
}
|
||||
}
|
||||
|
||||
unsigned snes_information::find_header(const uint8_t *data, unsigned size) {
|
||||
unsigned SNESCartridge::find_header(const uint8_t *data, unsigned size) {
|
||||
unsigned score_lo = score_header(data, size, 0x007fc0);
|
||||
unsigned score_hi = score_header(data, size, 0x00ffc0);
|
||||
unsigned score_ex = score_header(data, size, 0x40ffc0);
|
||||
|
@ -764,7 +763,7 @@ unsigned snes_information::find_header(const uint8_t *data, unsigned size) {
|
|||
}
|
||||
}
|
||||
|
||||
unsigned snes_information::score_header(const uint8_t *data, unsigned size, unsigned addr) {
|
||||
unsigned SNESCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) {
|
||||
if(size < addr + 64) return 0; //image too small to contain header at this location?
|
||||
int score = 0;
|
||||
|
||||
|
@ -845,7 +844,7 @@ unsigned snes_information::score_header(const uint8_t *data, unsigned size, unsi
|
|||
return score;
|
||||
}
|
||||
|
||||
unsigned snes_information::gameboy_ram_size(const uint8_t *data, unsigned size) {
|
||||
unsigned SNESCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) {
|
||||
if(size < 512) return 0;
|
||||
switch(data[0x0149]) {
|
||||
case 0x00: return 0 * 1024;
|
||||
|
@ -858,7 +857,7 @@ unsigned snes_information::gameboy_ram_size(const uint8_t *data, unsigned size)
|
|||
}
|
||||
}
|
||||
|
||||
bool snes_information::gameboy_has_rtc(const uint8_t *data, unsigned size) {
|
||||
bool SNESCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) {
|
||||
if(size < 512) return false;
|
||||
if(data[0x0147] == 0x0f ||data[0x0147] == 0x10) return true;
|
||||
return false;
|
|
@ -40,7 +40,7 @@ struct SNESCPU {
|
|||
|
||||
static const OpcodeInfo opcodeInfo[256];
|
||||
|
||||
static unsigned getOpcodeLength(uint8_t status, uint8_t opcode);
|
||||
static unsigned getOpcodeLength(bool accum, bool index, uint8_t opcode);
|
||||
static string disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb);
|
||||
};
|
||||
|
||||
|
@ -382,12 +382,12 @@ const SNESCPU::OpcodeInfo SNESCPU::opcodeInfo[256] = {
|
|||
{ "sbc", LongX },
|
||||
};
|
||||
|
||||
inline unsigned SNESCPU::getOpcodeLength(uint8_t status, uint8_t opcode) {
|
||||
inline unsigned SNESCPU::getOpcodeLength(bool accum, bool index, uint8_t opcode) {
|
||||
switch(opcodeInfo[opcode].mode) { default:
|
||||
case Implied: return 1;
|
||||
case Constant: return 2;
|
||||
case AccumConstant: return 3 - (bool)(status & 0x20);
|
||||
case IndexConstant: return 3 - (bool)(status & 0x10);
|
||||
case AccumConstant: return 3 - accum;
|
||||
case IndexConstant: return 3 - index;
|
||||
case Direct: return 2;
|
||||
case DirectX: return 2;
|
||||
case DirectY: return 2;
|
||||
|
|
|
@ -0,0 +1,639 @@
|
|||
#ifndef NALL_SNES_SMP_HPP
|
||||
#define NALL_SNES_SMP_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct SNESSMP {
|
||||
enum : unsigned {
|
||||
Implied, //
|
||||
TVector, //0
|
||||
Direct, //$00
|
||||
DirectRelative, //$00,+/-$00
|
||||
ADirect, //a,$00
|
||||
AAbsolute, //a,$0000
|
||||
AIX, //a,(x)
|
||||
AIDirectX, //a,($00+x)
|
||||
AConstant, //a,#$00
|
||||
DirectDirect, //$00,$00
|
||||
CAbsoluteBit, //c,$0000:0
|
||||
Absolute, //$0000
|
||||
P, //p
|
||||
AbsoluteA, //$0000,a
|
||||
Relative, //+/-$00
|
||||
ADirectX, //a,$00+x
|
||||
AAbsoluteX, //a,$0000+x
|
||||
AAbsoluteY, //a,$0000+y
|
||||
AIDirectY, //a,($00)+y
|
||||
DirectConstant, //$00,#$00
|
||||
IXIY, //(x),(y)
|
||||
DirectX, //$00+x
|
||||
A, //a
|
||||
X, //x
|
||||
XAbsolute, //x,$0000
|
||||
IAbsoluteX, //($0000+x)
|
||||
CNAbsoluteBit, //c,!$0000:0
|
||||
XDirect, //x,$00
|
||||
PVector, //$ff00
|
||||
YaDirect, //ya,$00
|
||||
XA, //x,a
|
||||
YAbsolute, //y,$0000
|
||||
Y, //y
|
||||
AX, //a,x
|
||||
YDirect, //y,$00
|
||||
YConstant, //y,#$00
|
||||
XSp, //x,sp
|
||||
YaX, //ya,x
|
||||
IXPA, //(x)+,a
|
||||
SpX, //sp,x
|
||||
AIXP, //a,(x)+
|
||||
DirectA, //$00,a
|
||||
IXA, //(x),a
|
||||
IDirectXA, //($00+x),a
|
||||
XConstant, //x,#$00
|
||||
AbsoluteX, //$0000,x
|
||||
AbsoluteBitC, //$0000:0,c
|
||||
DirectY, //$00,y
|
||||
AbsoluteY, //$0000,y
|
||||
Ya, //ya
|
||||
DirectXA, //$00+x,a
|
||||
AbsoluteXA, //$0000+x,a
|
||||
AbsoluteYA, //$0000+y,a
|
||||
IDirectYA, //($00)+y,a
|
||||
DirectYX, //$00+y,x
|
||||
DirectYa, //$00,ya
|
||||
DirectXY, //$00+x,y
|
||||
AY, //a,y
|
||||
DirectXRelative, //$00+x,+/-$00
|
||||
XDirectY, //x,$00+y
|
||||
YDirectX, //y,$00+x
|
||||
YA, //y,a
|
||||
YRelative, //y,+/-$00
|
||||
};
|
||||
|
||||
struct OpcodeInfo {
|
||||
char name[6];
|
||||
unsigned mode;
|
||||
};
|
||||
|
||||
static const OpcodeInfo opcodeInfo[256];
|
||||
|
||||
static unsigned getOpcodeLength(uint8_t opcode);
|
||||
static string disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph);
|
||||
static string disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph);
|
||||
};
|
||||
|
||||
const SNESSMP::OpcodeInfo SNESSMP::opcodeInfo[256] = {
|
||||
//0x00 - 0x0f
|
||||
{ "nop ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set0 ", Direct },
|
||||
{ "bbs0 ", DirectRelative },
|
||||
|
||||
{ "or ", ADirect },
|
||||
{ "or ", AAbsolute },
|
||||
{ "or ", AIX },
|
||||
{ "or ", AIDirectX },
|
||||
|
||||
{ "or ", AConstant },
|
||||
{ "or ", DirectDirect },
|
||||
{ "or1 ", CAbsoluteBit },
|
||||
{ "asl ", Direct },
|
||||
|
||||
{ "asl ", Absolute },
|
||||
{ "push ", P },
|
||||
{ "tset ", AbsoluteA },
|
||||
{ "brk ", Implied },
|
||||
|
||||
//0x10 - 0x1f
|
||||
{ "bpl ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr0 ", Direct },
|
||||
{ "bbc0 ", DirectRelative },
|
||||
|
||||
{ "or ", ADirectX },
|
||||
{ "or ", AAbsoluteX },
|
||||
{ "or ", AAbsoluteY },
|
||||
{ "or ", AIDirectY },
|
||||
|
||||
{ "or ", DirectConstant },
|
||||
{ "or ", IXIY },
|
||||
{ "decw ", Direct },
|
||||
{ "asl ", DirectX },
|
||||
|
||||
{ "asl ", A },
|
||||
{ "dec ", X },
|
||||
{ "cmp ", XAbsolute },
|
||||
{ "jmp ", IAbsoluteX },
|
||||
|
||||
//0x20 - 0x2f
|
||||
{ "clrp ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set1 ", Direct },
|
||||
{ "bbs1 ", DirectRelative },
|
||||
|
||||
{ "and ", ADirect },
|
||||
{ "and ", AAbsolute },
|
||||
{ "and ", AIX },
|
||||
{ "and ", AIDirectX },
|
||||
|
||||
{ "and ", AConstant },
|
||||
{ "and ", DirectDirect },
|
||||
{ "or1 ", CNAbsoluteBit },
|
||||
{ "rol ", Direct },
|
||||
|
||||
{ "rol ", Absolute },
|
||||
{ "push ", A },
|
||||
{ "cbne ", DirectRelative },
|
||||
{ "bra ", Relative },
|
||||
|
||||
//0x30 - 0x3f
|
||||
{ "bmi ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr1 ", Direct },
|
||||
{ "bbc1 ", DirectRelative },
|
||||
|
||||
{ "and ", ADirectX },
|
||||
{ "and ", AAbsoluteX },
|
||||
{ "and ", AAbsoluteY },
|
||||
{ "and ", AIDirectY },
|
||||
|
||||
{ "and ", DirectConstant },
|
||||
{ "and ", IXIY },
|
||||
{ "incw ", Direct },
|
||||
{ "rol ", DirectX },
|
||||
|
||||
{ "rol ", A },
|
||||
{ "inc ", X },
|
||||
{ "cmp ", XDirect },
|
||||
{ "call ", Absolute },
|
||||
|
||||
//0x40 - 0x4f
|
||||
{ "setp ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set2 ", Direct },
|
||||
{ "bbs2 ", DirectRelative },
|
||||
|
||||
{ "eor ", ADirect },
|
||||
{ "eor ", AAbsolute },
|
||||
{ "eor ", AIX },
|
||||
{ "eor ", AIDirectX },
|
||||
|
||||
{ "eor ", AConstant },
|
||||
{ "eor ", DirectDirect },
|
||||
{ "and1 ", CAbsoluteBit },
|
||||
{ "lsr ", Direct },
|
||||
|
||||
{ "lsr ", Absolute },
|
||||
{ "push ", X },
|
||||
{ "tclr ", AbsoluteA },
|
||||
{ "pcall", PVector },
|
||||
|
||||
//0x50 - 0x5f
|
||||
{ "bvc ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr2 ", Direct },
|
||||
{ "bbc2 ", DirectRelative },
|
||||
|
||||
{ "eor ", ADirectX },
|
||||
{ "eor ", AAbsoluteX },
|
||||
{ "eor ", AAbsoluteY },
|
||||
{ "eor ", AIDirectY },
|
||||
|
||||
{ "eor ", DirectConstant },
|
||||
{ "eor ", IXIY },
|
||||
{ "cmpw ", YaDirect },
|
||||
{ "lsr ", DirectX },
|
||||
|
||||
{ "lsr ", A },
|
||||
{ "mov ", XA },
|
||||
{ "cmp ", YAbsolute },
|
||||
{ "jmp ", Absolute },
|
||||
|
||||
//0x60 - 0x6f
|
||||
{ "clrc ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set3 ", Direct },
|
||||
{ "bbs3 ", DirectRelative },
|
||||
|
||||
{ "cmp ", ADirect },
|
||||
{ "cmp ", AAbsolute },
|
||||
{ "cmp ", AIX },
|
||||
{ "cmp ", AIDirectX },
|
||||
|
||||
{ "cmp ", AConstant },
|
||||
{ "cmp ", DirectDirect },
|
||||
{ "and1 ", CNAbsoluteBit },
|
||||
{ "ror ", Direct },
|
||||
|
||||
{ "ror ", Absolute },
|
||||
{ "push ", Y },
|
||||
{ "dbnz ", DirectRelative },
|
||||
{ "ret ", Implied },
|
||||
|
||||
//0x70 - 0x7f
|
||||
{ "bvs ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr3 ", Direct },
|
||||
{ "bbc3 ", DirectRelative },
|
||||
|
||||
{ "cmp ", ADirectX },
|
||||
{ "cmp ", AAbsoluteX },
|
||||
{ "cmp ", AAbsoluteY },
|
||||
{ "cmp ", AIDirectY },
|
||||
|
||||
{ "cmp ", DirectConstant },
|
||||
{ "cmp ", IXIY },
|
||||
{ "addw ", YaDirect },
|
||||
{ "ror ", DirectX },
|
||||
|
||||
{ "ror ", A },
|
||||
{ "mov ", AX },
|
||||
{ "cmp ", YDirect },
|
||||
{ "reti ", Implied },
|
||||
|
||||
//0x80 - 0x8f
|
||||
{ "setc ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set4 ", Direct },
|
||||
{ "bbs4 ", DirectRelative },
|
||||
|
||||
{ "adc ", ADirect },
|
||||
{ "adc ", AAbsolute },
|
||||
{ "adc ", AIX },
|
||||
{ "adc ", AIDirectX },
|
||||
|
||||
{ "adc ", AConstant },
|
||||
{ "adc ", DirectDirect },
|
||||
{ "eor1 ", CAbsoluteBit },
|
||||
{ "dec ", Direct },
|
||||
|
||||
{ "dec ", Absolute },
|
||||
{ "mov ", YConstant },
|
||||
{ "pop ", P },
|
||||
{ "mov ", DirectConstant },
|
||||
|
||||
//0x90 - 0x9f
|
||||
{ "bcc ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr4 ", Direct },
|
||||
{ "bbc4 ", DirectRelative },
|
||||
|
||||
{ "adc ", ADirectX },
|
||||
{ "adc ", AAbsoluteX },
|
||||
{ "adc ", AAbsoluteY },
|
||||
{ "adc ", AIDirectY },
|
||||
|
||||
{ "adc ", DirectRelative },
|
||||
{ "adc ", IXIY },
|
||||
{ "subw ", YaDirect },
|
||||
{ "dec ", DirectX },
|
||||
|
||||
{ "dec ", A },
|
||||
{ "mov ", XSp },
|
||||
{ "div ", YaX },
|
||||
{ "xcn ", A },
|
||||
|
||||
//0xa0 - 0xaf
|
||||
{ "ei ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set5 ", Direct },
|
||||
{ "bbs5 ", DirectRelative },
|
||||
|
||||
{ "sbc ", ADirect },
|
||||
{ "sbc ", AAbsolute },
|
||||
{ "sbc ", AIX },
|
||||
{ "sbc ", AIDirectX },
|
||||
|
||||
{ "sbc ", AConstant },
|
||||
{ "sbc ", DirectDirect },
|
||||
{ "mov1 ", CAbsoluteBit },
|
||||
{ "inc ", Direct },
|
||||
|
||||
{ "inc ", Absolute },
|
||||
{ "cmp ", YConstant },
|
||||
{ "pop ", A },
|
||||
{ "mov ", IXPA },
|
||||
|
||||
//0xb0 - 0xbf
|
||||
{ "bcs ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr5 ", Direct },
|
||||
{ "bbc5 ", DirectRelative },
|
||||
|
||||
{ "sbc ", ADirectX },
|
||||
{ "sbc ", AAbsoluteX },
|
||||
{ "sbc ", AAbsoluteY },
|
||||
{ "sbc ", AIDirectY },
|
||||
|
||||
{ "sbc ", DirectConstant },
|
||||
{ "sbc ", IXIY },
|
||||
{ "movw ", YaDirect },
|
||||
{ "inc ", DirectX },
|
||||
|
||||
{ "inc ", A },
|
||||
{ "mov ", SpX },
|
||||
{ "das ", A },
|
||||
{ "mov ", AIXP },
|
||||
|
||||
//0xc0 - 0xcf
|
||||
{ "di ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set6 ", Direct },
|
||||
{ "bbs6 ", DirectRelative },
|
||||
|
||||
{ "mov ", DirectA },
|
||||
{ "mov ", AbsoluteA },
|
||||
{ "mov ", IXA },
|
||||
{ "mov ", IDirectXA },
|
||||
|
||||
{ "cmp ", XConstant },
|
||||
{ "mov ", AbsoluteX },
|
||||
{ "mov1 ", AbsoluteBitC },
|
||||
{ "mov ", DirectY },
|
||||
|
||||
{ "mov ", AbsoluteY },
|
||||
{ "mov ", XConstant },
|
||||
{ "pop ", X },
|
||||
{ "mul ", Ya },
|
||||
|
||||
//0xd0 - 0xdf
|
||||
{ "bne ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr6 ", Relative },
|
||||
{ "bbc6 ", DirectRelative },
|
||||
|
||||
{ "mov ", DirectXA },
|
||||
{ "mov ", AbsoluteXA },
|
||||
{ "mov ", AbsoluteYA },
|
||||
{ "mov ", IDirectYA },
|
||||
|
||||
{ "mov ", DirectX },
|
||||
{ "mov ", DirectYX },
|
||||
{ "movw ", DirectYa },
|
||||
{ "mov ", DirectXY },
|
||||
|
||||
{ "dec ", Y },
|
||||
{ "mov ", AY },
|
||||
{ "cbne ", DirectXRelative },
|
||||
{ "daa ", A },
|
||||
|
||||
//0xe0 - 0xef
|
||||
{ "clrv ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set7 ", Direct },
|
||||
{ "bbs7 ", DirectRelative },
|
||||
|
||||
{ "mov ", ADirect },
|
||||
{ "mov ", AAbsolute },
|
||||
{ "mov ", AIX },
|
||||
{ "mov ", AIDirectX },
|
||||
|
||||
{ "mov ", AConstant },
|
||||
{ "mov ", XAbsolute },
|
||||
{ "not1 ", CAbsoluteBit },
|
||||
{ "mov ", YDirect },
|
||||
|
||||
{ "mov ", YAbsolute },
|
||||
{ "notc ", Implied },
|
||||
{ "pop ", Y },
|
||||
{ "sleep", Implied },
|
||||
|
||||
//0xf0 - 0xff
|
||||
{ "beq ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr7 ", Direct },
|
||||
{ "bbc7 ", DirectRelative },
|
||||
|
||||
{ "mov ", ADirectX },
|
||||
{ "mov ", AAbsoluteX },
|
||||
{ "mov ", AAbsoluteY },
|
||||
{ "mov ", AIDirectY },
|
||||
|
||||
{ "mov ", XDirect },
|
||||
{ "mov ", XDirectY },
|
||||
{ "mov ", DirectDirect },
|
||||
{ "mov ", YDirectX },
|
||||
|
||||
{ "inc ", Y },
|
||||
{ "mov ", YA },
|
||||
{ "dbz ", YRelative },
|
||||
{ "stop ", Implied },
|
||||
};
|
||||
|
||||
inline unsigned SNESSMP::getOpcodeLength(uint8_t opcode) {
|
||||
switch(opcodeInfo[opcode].mode) { default:
|
||||
case Implied: return 1; //
|
||||
case TVector: return 1; //0
|
||||
case Direct: return 2; //$00
|
||||
case DirectRelative: return 3; //$00,+/-$00
|
||||
case ADirect: return 2; //a,$00
|
||||
case AAbsolute: return 3; //a,$0000
|
||||
case AIX: return 1; //a,(x)
|
||||
case AIDirectX: return 2; //a,($00+x)
|
||||
case AConstant: return 2; //a,#$00
|
||||
case DirectDirect: return 3; //$00,$00
|
||||
case CAbsoluteBit: return 3; //c,$0000:0
|
||||
case Absolute: return 3; //$0000
|
||||
case P: return 1; //p
|
||||
case AbsoluteA: return 3; //$0000,a
|
||||
case Relative: return 2; //+/-$00
|
||||
case ADirectX: return 2; //a,$00+x
|
||||
case AAbsoluteX: return 3; //a,$0000+x
|
||||
case AAbsoluteY: return 3; //a,$0000+y
|
||||
case AIDirectY: return 2; //a,($00)+y
|
||||
case DirectConstant: return 3; //$00,#$00
|
||||
case IXIY: return 1; //(x),(y)
|
||||
case DirectX: return 2; //$00+x
|
||||
case A: return 1; //a
|
||||
case X: return 1; //x
|
||||
case XAbsolute: return 3; //x,$0000
|
||||
case IAbsoluteX: return 3; //($0000+x)
|
||||
case CNAbsoluteBit: return 3; //c,!$0000:0
|
||||
case XDirect: return 2; //x,$00
|
||||
case PVector: return 2; //$ff00
|
||||
case YaDirect: return 2; //ya,$00
|
||||
case XA: return 1; //x,a
|
||||
case YAbsolute: return 3; //y,$0000
|
||||
case Y: return 1; //y
|
||||
case AX: return 1; //a,x
|
||||
case YDirect: return 2; //y,$00
|
||||
case YConstant: return 2; //y,#$00
|
||||
case XSp: return 1; //x,sp
|
||||
case YaX: return 1; //ya,x
|
||||
case IXPA: return 1; //(x)+,a
|
||||
case SpX: return 1; //sp,x
|
||||
case AIXP: return 1; //a,(x)+
|
||||
case DirectA: return 2; //$00,a
|
||||
case IXA: return 1; //(x),a
|
||||
case IDirectXA: return 2; //($00+x),a
|
||||
case XConstant: return 2; //x,#$00
|
||||
case AbsoluteX: return 3; //$0000,x
|
||||
case AbsoluteBitC: return 3; //$0000:0,c
|
||||
case DirectY: return 2; //$00,y
|
||||
case AbsoluteY: return 3; //$0000,y
|
||||
case Ya: return 1; //ya
|
||||
case DirectXA: return 2; //$00+x,a
|
||||
case AbsoluteXA: return 3; //$0000+x,a
|
||||
case AbsoluteYA: return 3; //$0000+y,a
|
||||
case IDirectYA: return 2; //($00)+y,a
|
||||
case DirectYX: return 2; //$00+y,x
|
||||
case DirectYa: return 2; //$00,ya
|
||||
case DirectXY: return 2; //$00+x,y
|
||||
case AY: return 1; //a,y
|
||||
case DirectXRelative: return 3; //$00+x,+/-$00
|
||||
case XDirectY: return 2; //x,$00+y
|
||||
case YDirectX: return 2; //y,$00+x
|
||||
case YA: return 1; //y,a
|
||||
case YRelative: return 2; //y,+/-$00
|
||||
}
|
||||
}
|
||||
|
||||
inline string SNESSMP::disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph) {
|
||||
string name = opcodeInfo[opcode].name;
|
||||
unsigned mode = opcodeInfo[opcode].mode;
|
||||
unsigned pa = (ph << 8) + pl;
|
||||
|
||||
if(mode == Implied) return name;
|
||||
if(mode == TVector) return { name, " ", opcode >> 4 };
|
||||
if(mode == Direct) return { name, " $", strhex<2>(pl) };
|
||||
if(mode == DirectRelative) return { name, " $", strhex<2>(pl), ",$", strhex<4>(pc + 3 + (int8_t)ph) };
|
||||
if(mode == ADirect) return { name, " a,$", strhex<2>(pl) };
|
||||
if(mode == AAbsolute) return { name, " a,$", strhex<4>(pa) };
|
||||
if(mode == AIX) return { name, "a,(x)" };
|
||||
if(mode == AIDirectX) return { name, " a,($", strhex<2>(pl), "+x)" };
|
||||
if(mode == AConstant) return { name, " a,#$", strhex<2>(pl) };
|
||||
if(mode == DirectDirect) return { name, " $", strhex<2>(ph), ",$", strhex<2>(pl) };
|
||||
if(mode == CAbsoluteBit) return { name, " c,$", strhex<4>(pa & 0x1fff), ":", pa >> 13 };
|
||||
if(mode == Absolute) return { name, " $", strhex<4>(pa) };
|
||||
if(mode == P) return { name, " p" };
|
||||
if(mode == AbsoluteA) return { name, " $", strhex<4>(pa), ",a" };
|
||||
if(mode == Relative) return { name, " $", strhex<4>(pc + 2 + (int8_t)pl) };
|
||||
if(mode == ADirectX) return { name, " a,$", strhex<2>(pl), "+x" };
|
||||
if(mode == AAbsoluteX) return { name, " a,$", strhex<4>(pa), "+x" };
|
||||
if(mode == AAbsoluteY) return { name, " a,$", strhex<4>(pa), "+y" };
|
||||
if(mode == AIDirectY) return { name, " a,($", strhex<2>(pl), ")+y" };
|
||||
if(mode == DirectConstant) return { name, " $", strhex<2>(ph), ",#$", strhex<2>(pl) };
|
||||
if(mode == IXIY) return { name, " (x),(y)" };
|
||||
if(mode == DirectX) return { name, " $", strhex<2>(pl), "+x" };
|
||||
if(mode == A) return { name, " a" };
|
||||
if(mode == X) return { name, " x" };
|
||||
if(mode == XAbsolute) return { name, " x,$", strhex<4>(pa) };
|
||||
if(mode == IAbsoluteX) return { name, " ($", strhex<4>(pa), "+x)" };
|
||||
if(mode == CNAbsoluteBit) return { name, " c,!$", strhex<4>(pa & 0x1fff), ":", pa >> 13 };
|
||||
if(mode == XDirect) return { name, " x,$", strhex<2>(pl) };
|
||||
if(mode == PVector) return { name, " $ff", strhex<2>(pl) };
|
||||
if(mode == YaDirect) return { name, " ya,$", strhex<2>(pl) };
|
||||
if(mode == XA) return { name, " x,a" };
|
||||
if(mode == YAbsolute) return { name, " y,$", strhex<4>(pa) };
|
||||
if(mode == Y) return { name, " y" };
|
||||
if(mode == AX) return { name, " a,x" };
|
||||
if(mode == YDirect) return { name, " y,$", strhex<2>(pl) };
|
||||
if(mode == YConstant) return { name, " y,#$", strhex<2>(pl) };
|
||||
if(mode == XSp) return { name, " x,sp" };
|
||||
if(mode == YaX) return { name, " ya,x" };
|
||||
if(mode == IXPA) return { name, " (x)+,a" };
|
||||
if(mode == SpX) return { name, " sp,x" };
|
||||
if(mode == AIXP) return { name, " a,(x)+" };
|
||||
if(mode == DirectA) return { name, " $", strhex<2>(pl), ",a" };
|
||||
if(mode == IXA) return { name, " (x),a" };
|
||||
if(mode == IDirectXA) return { name, " ($", strhex<2>(pl), "+x),a" };
|
||||
if(mode == XConstant) return { name, " x,#$", strhex<2>(pl) };
|
||||
if(mode == AbsoluteX) return { name, " $", strhex<4>(pa), ",x" };
|
||||
if(mode == AbsoluteBitC) return { name, " $", strhex<4>(pa & 0x1fff), ":", pa >> 13, ",c" };
|
||||
if(mode == DirectY) return { name, " $", strhex<2>(pl), ",y" };
|
||||
if(mode == AbsoluteY) return { name, " $", strhex<4>(pa), ",y" };
|
||||
if(mode == Ya) return { name, " ya" };
|
||||
if(mode == DirectXA) return { name, " $", strhex<2>(pl), "+x,a" };
|
||||
if(mode == AbsoluteXA) return { name, " $", strhex<4>(pa), "+x,a" };
|
||||
if(mode == AbsoluteYA) return { name, " $", strhex<4>(pa), "+y,a" };
|
||||
if(mode == IDirectYA) return { name, " ($", strhex<2>(pl), ")+y,a" };
|
||||
if(mode == DirectYX) return { name, " $", strhex<2>(pl), "+y,x" };
|
||||
if(mode == DirectYa) return { name, " $", strhex<2>(pl), ",ya" };
|
||||
if(mode == DirectXY) return { name, " $", strhex<2>(pl), "+x,y" };
|
||||
if(mode == AY) return { name, " a,y" };
|
||||
if(mode == DirectXRelative) return { name, " $", strhex<2>(pl), ",$", strhex<4>(pc + 3 + (int8_t)ph) };
|
||||
if(mode == XDirectY) return { name, " x,$", strhex<2>(pl), "+y" };
|
||||
if(mode == YDirectX) return { name, " y,$", strhex<2>(pl), "+x" };
|
||||
if(mode == YA) return { name, " y,a" };
|
||||
if(mode == YRelative) return { name, " y,$", strhex<4>(pc + 2 + (int8_t)pl) };
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
inline string SNESSMP::disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph) {
|
||||
string name = opcodeInfo[opcode].name;
|
||||
unsigned mode = opcodeInfo[opcode].mode;
|
||||
unsigned pdl = (p << 8) + pl;
|
||||
unsigned pdh = (p << 8) + ph;
|
||||
unsigned pa = (ph << 8) + pl;
|
||||
|
||||
if(mode == Implied) return name;
|
||||
if(mode == TVector) return { name, " ", opcode >> 4 };
|
||||
if(mode == Direct) return { name, " $", strhex<3>(pdl) };
|
||||
if(mode == DirectRelative) return { name, " $", strhex<3>(pdl), ",$", strhex<4>(pc + 3 + (int8_t)ph) };
|
||||
if(mode == ADirect) return { name, " a,$", strhex<3>(pdl) };
|
||||
if(mode == AAbsolute) return { name, " a,$", strhex<4>(pa) };
|
||||
if(mode == AIX) return { name, "a,(x)" };
|
||||
if(mode == AIDirectX) return { name, " a,($", strhex<3>(pdl), "+x)" };
|
||||
if(mode == AConstant) return { name, " a,#$", strhex<2>(pl) };
|
||||
if(mode == DirectDirect) return { name, " $", strhex<3>(pdh), ",$", strhex<3>(pdl) };
|
||||
if(mode == CAbsoluteBit) return { name, " c,$", strhex<4>(pa & 0x1fff), ":", pa >> 13 };
|
||||
if(mode == Absolute) return { name, " $", strhex<4>(pa) };
|
||||
if(mode == P) return { name, " p" };
|
||||
if(mode == AbsoluteA) return { name, " $", strhex<4>(pa), ",a" };
|
||||
if(mode == Relative) return { name, " $", strhex<4>(pc + 2 + (int8_t)pl) };
|
||||
if(mode == ADirectX) return { name, " a,$", strhex<3>(pdl), "+x" };
|
||||
if(mode == AAbsoluteX) return { name, " a,$", strhex<4>(pa), "+x" };
|
||||
if(mode == AAbsoluteY) return { name, " a,$", strhex<4>(pa), "+y" };
|
||||
if(mode == AIDirectY) return { name, " a,($", strhex<3>(pdl), ")+y" };
|
||||
if(mode == DirectConstant) return { name, " $", strhex<3>(pdh), ",#$", strhex<2>(pl) };
|
||||
if(mode == IXIY) return { name, " (x),(y)" };
|
||||
if(mode == DirectX) return { name, " $", strhex<3>(pdl), "+x" };
|
||||
if(mode == A) return { name, " a" };
|
||||
if(mode == X) return { name, " x" };
|
||||
if(mode == XAbsolute) return { name, " x,$", strhex<4>(pa) };
|
||||
if(mode == IAbsoluteX) return { name, " ($", strhex<4>(pa), "+x)" };
|
||||
if(mode == CNAbsoluteBit) return { name, " c,!$", strhex<4>(pa & 0x1fff), ":", pa >> 13 };
|
||||
if(mode == XDirect) return { name, " x,$", strhex<3>(pdl) };
|
||||
if(mode == PVector) return { name, " $ff", strhex<2>(pl) };
|
||||
if(mode == YaDirect) return { name, " ya,$", strhex<3>(pdl) };
|
||||
if(mode == XA) return { name, " x,a" };
|
||||
if(mode == YAbsolute) return { name, " y,$", strhex<4>(pa) };
|
||||
if(mode == Y) return { name, " y" };
|
||||
if(mode == AX) return { name, " a,x" };
|
||||
if(mode == YDirect) return { name, " y,$", strhex<3>(pdl) };
|
||||
if(mode == YConstant) return { name, " y,#$", strhex<2>(pl) };
|
||||
if(mode == XSp) return { name, " x,sp" };
|
||||
if(mode == YaX) return { name, " ya,x" };
|
||||
if(mode == IXPA) return { name, " (x)+,a" };
|
||||
if(mode == SpX) return { name, " sp,x" };
|
||||
if(mode == AIXP) return { name, " a,(x)+" };
|
||||
if(mode == DirectA) return { name, " $", strhex<3>(pdl), ",a" };
|
||||
if(mode == IXA) return { name, " (x),a" };
|
||||
if(mode == IDirectXA) return { name, " ($", strhex<3>(pdl), "+x),a" };
|
||||
if(mode == XConstant) return { name, " x,#$", strhex<2>(pl) };
|
||||
if(mode == AbsoluteX) return { name, " $", strhex<4>(pa), ",x" };
|
||||
if(mode == AbsoluteBitC) return { name, " $", strhex<4>(pa & 0x1fff), ":", pa >> 13, ",c" };
|
||||
if(mode == DirectY) return { name, " $", strhex<3>(pdl), ",y" };
|
||||
if(mode == AbsoluteY) return { name, " $", strhex<4>(pa), ",y" };
|
||||
if(mode == Ya) return { name, " ya" };
|
||||
if(mode == DirectXA) return { name, " $", strhex<3>(pdl), "+x,a" };
|
||||
if(mode == AbsoluteXA) return { name, " $", strhex<4>(pa), "+x,a" };
|
||||
if(mode == AbsoluteYA) return { name, " $", strhex<4>(pa), "+y,a" };
|
||||
if(mode == IDirectYA) return { name, " ($", strhex<3>(pdl), ")+y,a" };
|
||||
if(mode == DirectYX) return { name, " $", strhex<3>(pdl), "+y,x" };
|
||||
if(mode == DirectYa) return { name, " $", strhex<3>(pdl), ",ya" };
|
||||
if(mode == DirectXY) return { name, " $", strhex<3>(pdl), "+x,y" };
|
||||
if(mode == AY) return { name, " a,y" };
|
||||
if(mode == DirectXRelative) return { name, " $", strhex<3>(pdl), ",$", strhex<4>(pc + 3 + (int8_t)ph) };
|
||||
if(mode == XDirectY) return { name, " x,$", strhex<3>(pdl), "+y" };
|
||||
if(mode == YDirectX) return { name, " y,$", strhex<3>(pdl), "+x" };
|
||||
if(mode == YA) return { name, " y,a" };
|
||||
if(mode == YRelative) return { name, " y,$", strhex<4>(pc + 2 + (int8_t)pl) };
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -5,7 +5,7 @@ static bool HexEditor_keyPress(GtkWidget *widget, GdkEventKey *event, HexEditor
|
|||
void HexEditor::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
object->widget = gtk_scrolled_window_new(0, 0);
|
||||
widget->parent = &parent;
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
object->subWidget = gtk_text_view_new();
|
||||
|
|
|
@ -36,6 +36,11 @@ uint8 Debugger::read(Debugger::MemorySource source, unsigned addr) {
|
|||
return bus.read(addr & 0xffffff);
|
||||
} break;
|
||||
|
||||
case MemorySource::APUBus: {
|
||||
if((addr & 0xffc0) == 0xffc0) return smp.iplrom[addr & 0x3f];
|
||||
return memory::apuram.read(addr & 0xffff);
|
||||
} break;
|
||||
|
||||
case MemorySource::APURAM: {
|
||||
return memory::apuram.read(addr & 0xffff);
|
||||
} break;
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
bool step_cpu;
|
||||
bool step_smp;
|
||||
|
||||
enum class MemorySource : unsigned { CPUBus, APURAM, VRAM, OAM, CGRAM };
|
||||
enum class MemorySource : unsigned { CPUBus, APUBus, APURAM, VRAM, OAM, CGRAM };
|
||||
uint8 read(MemorySource, unsigned addr);
|
||||
void write(MemorySource, unsigned addr, uint8 data);
|
||||
|
||||
|
|
|
@ -16,12 +16,12 @@ public:
|
|||
SMP();
|
||||
~SMP();
|
||||
|
||||
static const uint8 iplrom[64];
|
||||
|
||||
private:
|
||||
#include "memory/memory.hpp"
|
||||
#include "timing/timing.hpp"
|
||||
|
||||
static const uint8 iplrom[64];
|
||||
|
||||
struct {
|
||||
//timing
|
||||
unsigned clock_counter;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "072.02";
|
||||
static const char Version[] = "072.04";
|
||||
static const unsigned SerializerVersion = 14;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <nall/filemap.hpp>
|
||||
#include <nall/input.hpp>
|
||||
#include <nall/ups.hpp>
|
||||
#include <nall/snes/info.hpp>
|
||||
#include <nall/snes/cartridge.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <ruby/ruby.hpp>
|
||||
|
|
|
@ -107,7 +107,7 @@ bool Cartridge::loadCartridge(SNES::MappedRAM &memory, string &XML, const char *
|
|||
}
|
||||
}
|
||||
|
||||
if(XML == "") XML = snes_information(data, size).xml_memory_map;
|
||||
if(XML == "") XML = SNESCartridge(data, size).xmlMemoryMap;
|
||||
memory.copy(data, size);
|
||||
delete[] data;
|
||||
return true;
|
||||
|
|
|
@ -15,8 +15,14 @@ void Console::create() {
|
|||
traceToDisk.setEnabled(false);
|
||||
traceCPU.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace S-CPU"); y += Style::CheckBoxHeight;
|
||||
traceCPU.setChecked(true);
|
||||
traceSMP.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace S-SMP"); y += Style::CheckBoxHeight;
|
||||
|
||||
setGeometry(0, 0, 775, 338);
|
||||
|
||||
onClose = []() {
|
||||
debugger.showConsole.setChecked(false);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
void Console::eventTraceCPU() {
|
||||
|
@ -28,3 +34,13 @@ void Console::eventTraceCPU() {
|
|||
buffer.append(string(buffer == "" ? "" : "\n", text));
|
||||
output.setText(buffer);
|
||||
}
|
||||
|
||||
void Console::eventTraceSMP() {
|
||||
if(traceSMP.checked() == false) return;
|
||||
if(traceToConsole.checked() == false) return;
|
||||
|
||||
char text[256];
|
||||
SNES::smp.disassemble_opcode(text, SNES::smp.regs.pc);
|
||||
buffer.append(string(buffer == "" ? "" : "\n", text));
|
||||
output.setText(buffer);
|
||||
}
|
||||
|
|
|
@ -3,11 +3,13 @@ struct Console : TopLevelWindow {
|
|||
CheckBox traceToConsole;
|
||||
CheckBox traceToDisk;
|
||||
CheckBox traceCPU;
|
||||
CheckBox traceSMP;
|
||||
|
||||
string buffer;
|
||||
|
||||
void create();
|
||||
void eventTraceCPU();
|
||||
void eventTraceSMP();
|
||||
};
|
||||
|
||||
extern Console console;
|
||||
|
|
|
@ -16,6 +16,11 @@ void CPUdebugger::create() {
|
|||
|
||||
setGeometry(0, 0, 490, 205);
|
||||
|
||||
onClose = []() {
|
||||
debugger.showCPUDebugger.setChecked(false);
|
||||
return true;
|
||||
};
|
||||
|
||||
stepInto.onTick = []() {
|
||||
SNES::debugger.step_cpu = true;
|
||||
debugger.debugMode = Debugger::DebugMode::StepIntoCPU;
|
||||
|
@ -88,7 +93,7 @@ void CPUdebugger::eventStepInto() {
|
|||
|
||||
void CPUdebugger::eventStepOver() {
|
||||
uint8_t opcode = read(SNES::cpu.regs.pc);
|
||||
unsigned length = SNESCPU::getOpcodeLength(opcode, SNES::cpu.regs.p);
|
||||
unsigned length = SNESCPU::getOpcodeLength(SNES::cpu.regs.p.m, SNES::cpu.regs.p.x, opcode);
|
||||
SNES::cpu.regs.pc += length;
|
||||
refreshDisassembly();
|
||||
}
|
||||
|
|
|
@ -2,28 +2,57 @@
|
|||
#if defined(DEBUGGER)
|
||||
|
||||
#include <nall/snes/cpu.hpp>
|
||||
#include <nall/snes/smp.hpp>
|
||||
|
||||
#include "console.cpp"
|
||||
#include "cpu/debugger.cpp"
|
||||
#include "smp/debugger.cpp"
|
||||
#include "tools/memory-editor.cpp"
|
||||
Debugger debugger;
|
||||
|
||||
void Debugger::create() {
|
||||
console.create();
|
||||
cpuDebugger.create();
|
||||
smpDebugger.create();
|
||||
memoryEditor.create();
|
||||
|
||||
Window::create(0, 0, 256, 256, "Debugger");
|
||||
application.addWindow(this, "Debugger", "160,160");
|
||||
|
||||
unsigned x = 5, y = 5;
|
||||
enableDebugger.create(*this, x, y, 390, Style::CheckBoxHeight, "Enable debugger"); y += Style::CheckBoxHeight;
|
||||
showMemoryEditor.create(*this, x, y, 390, Style::CheckBoxHeight, "Memory editor"); y += Style::CheckBoxHeight;
|
||||
enableDebugger.create(*this, x, y, 240, Style::CheckBoxHeight, "Enable debugger"); y += Style::CheckBoxHeight;
|
||||
showConsole.create(*this, x, y, 240, Style::CheckBoxHeight, "Console"); y += Style::CheckBoxHeight;
|
||||
showCPUDebugger.create(*this, x, y, 240, Style::CheckBoxHeight, "CPU debugger"); y += Style::CheckBoxHeight;
|
||||
showSMPDebugger.create(*this, x, y, 240, Style::CheckBoxHeight, "SMP debugger"); y += Style::CheckBoxHeight;
|
||||
showMemoryEditor.create(*this, x, y, 240, Style::CheckBoxHeight, "Memory editor"); y += Style::CheckBoxHeight;
|
||||
|
||||
setGeometry(0, 0, 400, y);
|
||||
//windows shown by default
|
||||
showConsole.setChecked();
|
||||
showCPUDebugger.setChecked();
|
||||
showSMPDebugger.setChecked();
|
||||
|
||||
setGeometry(0, 0, 250, y);
|
||||
|
||||
enableDebugger.onTick = []() {
|
||||
debugger.enable(debugger.enableDebugger.checked());
|
||||
};
|
||||
|
||||
showConsole.onTick = []() {
|
||||
console.setVisible(debugger.showConsole.checked());
|
||||
};
|
||||
|
||||
showCPUDebugger.onTick = []() {
|
||||
cpuDebugger.setVisible(debugger.showCPUDebugger.checked());
|
||||
};
|
||||
|
||||
showSMPDebugger.onTick = []() {
|
||||
smpDebugger.setVisible(debugger.showSMPDebugger.checked());
|
||||
};
|
||||
|
||||
showMemoryEditor.onTick = []() {
|
||||
memoryEditor.setVisible(debugger.showMemoryEditor.checked());
|
||||
};
|
||||
|
||||
onClose = []() {
|
||||
debugger.enable(false);
|
||||
return true;
|
||||
|
@ -32,8 +61,10 @@ void Debugger::create() {
|
|||
|
||||
void Debugger::setVisible(bool visible) {
|
||||
Window::setVisible(visible);
|
||||
console.setVisible(visible);
|
||||
cpuDebugger.setVisible(visible);
|
||||
console.setVisible(showConsole.checked() & visible);
|
||||
cpuDebugger.setVisible(showCPUDebugger.checked() & visible);
|
||||
smpDebugger.setVisible(showSMPDebugger.checked() & visible);
|
||||
memoryEditor.setVisible(showMemoryEditor.checked() & visible);
|
||||
}
|
||||
|
||||
void Debugger::enable(bool state) {
|
||||
|
@ -56,8 +87,16 @@ void Debugger::run() {
|
|||
if(debugMode == DebugMode::StepIntoCPU) {
|
||||
if(SNES::debugger.break_event == SNES::Debugger::BreakEvent::CPUStep) {
|
||||
debugMode = DebugMode::None;
|
||||
cpuDebugger.eventStepInto();
|
||||
console.eventTraceCPU();
|
||||
cpuDebugger.eventStepInto();
|
||||
}
|
||||
}
|
||||
|
||||
if(debugMode == DebugMode::StepIntoSMP) {
|
||||
if(SNES::debugger.break_event == SNES::Debugger::BreakEvent::SMPStep) {
|
||||
debugMode = DebugMode::None;
|
||||
console.eventTraceSMP();
|
||||
smpDebugger.eventStepInto();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
#include "console.hpp"
|
||||
#include "cpu/debugger.hpp"
|
||||
#include "smp/debugger.hpp"
|
||||
#include "tools/memory-editor.hpp"
|
||||
|
||||
struct Debugger : TopLevelWindow {
|
||||
enum class DebugMode : unsigned {
|
||||
None,
|
||||
StepIntoCPU,
|
||||
StepIntoSMP,
|
||||
} debugMode;
|
||||
|
||||
CheckBox enableDebugger;
|
||||
CheckBox showConsole;
|
||||
CheckBox showCPUDebugger;
|
||||
CheckBox showSMPDebugger;
|
||||
CheckBox showMemoryEditor;
|
||||
|
||||
void create();
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
SMPDebugger smpDebugger;
|
||||
|
||||
void SMPDebugger::create() {
|
||||
Window::create(0, 0, 256, 256, "SMP Debugger");
|
||||
application.addWindow(this, "Debugger.SMPDebugger", "192,192");
|
||||
|
||||
unsigned x = 5, y = 5;
|
||||
output.create(*this, x, y, 400, 200); x += 400 + 5;
|
||||
output.setFont(application.monospaceFont);
|
||||
output.setEditable(false);
|
||||
|
||||
stepInto.create(*this, x, y, 80, Style::ButtonHeight, "Step Into"); y += Style::ButtonHeight;
|
||||
stepOver.create(*this, x, y, 80, Style::ButtonHeight, "Step Over"); y += Style::ButtonHeight;
|
||||
proceed.create(*this, x, y, 80, Style::ButtonHeight, "Proceed"); y += Style::ButtonHeight;
|
||||
proceed.setEnabled(false);
|
||||
|
||||
setGeometry(0, 0, 490, 205);
|
||||
|
||||
onClose = []() {
|
||||
debugger.showSMPDebugger.setChecked(false);
|
||||
return true;
|
||||
};
|
||||
|
||||
stepInto.onTick = []() {
|
||||
SNES::debugger.step_smp = true;
|
||||
debugger.debugMode = Debugger::DebugMode::StepIntoSMP;
|
||||
};
|
||||
|
||||
stepOver.onTick = { &SMPDebugger::eventStepOver, this };
|
||||
}
|
||||
|
||||
void SMPDebugger::refreshDisassembly() {
|
||||
uint16_t addr = SNES::smp.regs.pc;
|
||||
uint8_t *usage = SNES::smp.usage;
|
||||
|
||||
signed offset[15];
|
||||
foreach(n, offset) n = -1;
|
||||
|
||||
offset[7] = addr;
|
||||
|
||||
//reverse disassembly
|
||||
for(signed n = 6; n >= 0; n--) {
|
||||
signed base = offset[n + 1];
|
||||
if(base == -1) break;
|
||||
|
||||
for(unsigned r = 1; r <= 3; r++) {
|
||||
if(usage[(base - r) & 0xffff] & 0x20) {
|
||||
offset[n] = base - r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//forward disassembly
|
||||
for(signed n = 8; n <= 14; n++) {
|
||||
signed base = offset[n - 1];
|
||||
if(base == -1) break;
|
||||
|
||||
for(unsigned r = 1; r <= 3; r++) {
|
||||
if(usage[(base + r) & 0xffff] & 0x20) {
|
||||
offset[n] = base + r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string buffer;
|
||||
for(unsigned n = 0; n < 15; n++) {
|
||||
buffer.append(n == 7 ? "> " : " ");
|
||||
if(offset[n] == -1) {
|
||||
buffer.append("...\n");
|
||||
} else {
|
||||
uint16_t addr = offset[n];
|
||||
buffer.append(strhex<4>(addr));
|
||||
buffer.append(" ");
|
||||
string text = SNESSMP::disassemble(
|
||||
addr, read(addr + 0), read(addr + 1), read(addr + 2)
|
||||
);
|
||||
|
||||
buffer.append(text);
|
||||
buffer.append("\n");
|
||||
}
|
||||
}
|
||||
buffer.rtrim<1>("\n");
|
||||
output.setText(buffer);
|
||||
}
|
||||
|
||||
void SMPDebugger::eventStepInto() {
|
||||
SNES::debugger.step_smp = false;
|
||||
refreshDisassembly();
|
||||
}
|
||||
|
||||
void SMPDebugger::eventStepOver() {
|
||||
uint8_t opcode = read(SNES::smp.regs.pc);
|
||||
unsigned length = SNESSMP::getOpcodeLength(opcode);
|
||||
SNES::smp.regs.pc += length;
|
||||
refreshDisassembly();
|
||||
}
|
||||
|
||||
uint8_t SMPDebugger::read(uint16_t addr) {
|
||||
return SNES::debugger.read(SNES::Debugger::MemorySource::APUBus, addr);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
struct SMPDebugger : TopLevelWindow {
|
||||
EditBox output;
|
||||
Button stepInto;
|
||||
Button stepOver;
|
||||
Button proceed;
|
||||
|
||||
void create();
|
||||
void refreshDisassembly();
|
||||
void eventStepInto();
|
||||
void eventStepOver();
|
||||
|
||||
uint8_t read(uint16_t addr);
|
||||
};
|
||||
|
||||
extern SMPDebugger smpDebugger;
|
|
@ -0,0 +1,78 @@
|
|||
MemoryEditor memoryEditor;
|
||||
|
||||
void MemoryEditor::create() {
|
||||
Window::create(0, 0, 256, 256, "Memory Editor");
|
||||
application.addWindow(this, "Debugger.MemoryEditor", "192,192");
|
||||
|
||||
unsigned x = 5, y = 5;
|
||||
editor.create(*this, x, y, 455, 210); x += 455 + 5;
|
||||
editor.setFont(application.monospaceFont);
|
||||
editor.setColumns(16);
|
||||
editor.setRows(16);
|
||||
|
||||
sourceBox.create(*this, x, y, 80, Style::ComboBoxHeight); y += Style::ComboBoxHeight;
|
||||
sourceBox.addItem("CPU");
|
||||
sourceBox.addItem("APU");
|
||||
sourceBox.addItem("VRAM");
|
||||
sourceBox.addItem("OAM");
|
||||
sourceBox.addItem("CGRAM");
|
||||
|
||||
gotoBox.create(*this, x, y, 80, Style::TextBoxHeight); y += Style::TextBoxHeight;
|
||||
|
||||
refreshButton.create(*this, x, y, 80, Style::ButtonHeight, "Refresh"); y += Style::ButtonHeight;
|
||||
|
||||
setGeometry(0, 0, 545, 220);
|
||||
|
||||
onClose = []() {
|
||||
debugger.showMemoryEditor.setChecked(false);
|
||||
return true;
|
||||
};
|
||||
|
||||
editor.onRead = { &MemoryEditor::read, this };
|
||||
editor.onWrite = { &MemoryEditor::write, this };
|
||||
|
||||
sourceBox.onChange = []() {
|
||||
switch(memoryEditor.sourceBox.selection()) {
|
||||
case 0: memoryEditor.setSource(SNES::Debugger::MemorySource::CPUBus); break;
|
||||
case 1: memoryEditor.setSource(SNES::Debugger::MemorySource::APURAM); break;
|
||||
case 2: memoryEditor.setSource(SNES::Debugger::MemorySource::VRAM); break;
|
||||
case 3: memoryEditor.setSource(SNES::Debugger::MemorySource::OAM); break;
|
||||
case 4: memoryEditor.setSource(SNES::Debugger::MemorySource::CGRAM); break;
|
||||
}
|
||||
};
|
||||
|
||||
gotoBox.onChange = []() {
|
||||
unsigned addr = strhex(memoryEditor.gotoBox.text());
|
||||
memoryEditor.editor.setOffset(addr % memoryEditor.size);
|
||||
memoryEditor.editor.update();
|
||||
};
|
||||
|
||||
refreshButton.onTick = []() {
|
||||
memoryEditor.editor.update();
|
||||
};
|
||||
|
||||
setSource(SNES::Debugger::MemorySource::CPUBus);
|
||||
}
|
||||
|
||||
void MemoryEditor::setSource(SNES::Debugger::MemorySource source_) {
|
||||
switch(source = source_) {
|
||||
case SNES::Debugger::MemorySource::CPUBus: size = 1 << 24; break;
|
||||
case SNES::Debugger::MemorySource::APURAM: size = 1 << 16; break;
|
||||
case SNES::Debugger::MemorySource::VRAM: size = 1 << 16; break;
|
||||
case SNES::Debugger::MemorySource::OAM: size = 544; break;
|
||||
case SNES::Debugger::MemorySource::CGRAM: size = 512; break;
|
||||
}
|
||||
editor.setSize(size);
|
||||
editor.setOffset(0);
|
||||
editor.update();
|
||||
}
|
||||
|
||||
uint8_t MemoryEditor::read(unsigned addr) {
|
||||
if(SNES::cartridge.loaded() == false) return 0x00;
|
||||
return SNES::debugger.read(source, addr % size);
|
||||
}
|
||||
|
||||
void MemoryEditor::write(unsigned addr, uint8_t data) {
|
||||
if(SNES::cartridge.loaded() == false) return;
|
||||
SNES::debugger.write(source, addr % size, data);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
struct MemoryEditor : TopLevelWindow {
|
||||
HexEditor editor;
|
||||
ComboBox sourceBox;
|
||||
TextBox gotoBox;
|
||||
Button refreshButton;
|
||||
|
||||
SNES::Debugger::MemorySource source;
|
||||
unsigned size;
|
||||
|
||||
void create();
|
||||
void setSource(SNES::Debugger::MemorySource source);
|
||||
uint8_t read(unsigned addr);
|
||||
void write(unsigned addr, uint8_t data);
|
||||
};
|
||||
|
||||
extern MemoryEditor memoryEditor;
|
|
@ -248,7 +248,7 @@ bool Cartridge::loadCartridge(string &filename, string &xml, SNES::MappedRAM &me
|
|||
xml.readfile(name);
|
||||
} else {
|
||||
//generate XML mapping from data via heuristics
|
||||
xml = snes_information(data, size).xml_memory_map;
|
||||
xml = SNESCartridge(data, size).xmlMemoryMap;
|
||||
}
|
||||
|
||||
memory.copy(data, size);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <nall/config.hpp>
|
||||
#include <nall/input.hpp>
|
||||
#include <nall/ups.hpp>
|
||||
#include <nall/snes/info.hpp>
|
||||
#include <nall/snes/cartridge.hpp>
|
||||
#include "template/concept.hpp"
|
||||
#include "template/check-action.moc.hpp"
|
||||
#include "template/file-dialog.moc.hpp"
|
||||
|
|
Loading…
Reference in New Issue