diff --git a/bsnes/nall/snes/info.hpp b/bsnes/nall/snes/cartridge.hpp
similarity index 97%
rename from bsnes/nall/snes/info.hpp
rename to bsnes/nall/snes/cartridge.hpp
index df8b5f59..4a3e153c 100755
--- a/bsnes/nall/snes/info.hpp
+++ b/bsnes/nall/snes/cartridge.hpp
@@ -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 = "\n";
if(type == TypeBsx) {
xml << "";
- xml_memory_map = xml;
+ xmlMemoryMap = xml;
return;
}
if(type == TypeSufamiTurbo) {
xml << "";
- xml_memory_map = xml;
+ xmlMemoryMap = xml;
return;
}
@@ -129,7 +128,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " \n";
}
xml << "\n";
- xml_memory_map = xml;
+ xmlMemoryMap = xml;
return;
}
@@ -518,10 +517,10 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
}
xml << "\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;
diff --git a/bsnes/nall/snes/cpu.hpp b/bsnes/nall/snes/cpu.hpp
index dd26a365..f6a1c8ff 100755
--- a/bsnes/nall/snes/cpu.hpp
+++ b/bsnes/nall/snes/cpu.hpp
@@ -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;
diff --git a/bsnes/nall/snes/smp.hpp b/bsnes/nall/snes/smp.hpp
new file mode 100755
index 00000000..83c9696a
--- /dev/null
+++ b/bsnes/nall/snes/smp.hpp
@@ -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
diff --git a/bsnes/phoenix/gtk/hexeditor.cpp b/bsnes/phoenix/gtk/hexeditor.cpp
index 6327626e..793a7ae4 100755
--- a/bsnes/phoenix/gtk/hexeditor.cpp
+++ b/bsnes/phoenix/gtk/hexeditor.cpp
@@ -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();
diff --git a/bsnes/snes/debugger/debugger.cpp b/bsnes/snes/debugger/debugger.cpp
index dc70dfec..77783fa5 100755
--- a/bsnes/snes/debugger/debugger.cpp
+++ b/bsnes/snes/debugger/debugger.cpp
@@ -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;
diff --git a/bsnes/snes/debugger/debugger.hpp b/bsnes/snes/debugger/debugger.hpp
index 28ee52eb..5994f1ed 100755
--- a/bsnes/snes/debugger/debugger.hpp
+++ b/bsnes/snes/debugger/debugger.hpp
@@ -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);
diff --git a/bsnes/snes/smp/smp.hpp b/bsnes/snes/smp/smp.hpp
index a7da3867..a3bec580 100755
--- a/bsnes/snes/smp/smp.hpp
+++ b/bsnes/snes/smp/smp.hpp
@@ -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;
diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp
index bd6b11a6..f73b6065 100755
--- a/bsnes/snes/snes.hpp
+++ b/bsnes/snes/snes.hpp
@@ -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;
}
}
diff --git a/bsnes/ui-phoenix/base.hpp b/bsnes/ui-phoenix/base.hpp
index ad66b8ac..e7bfa272 100755
--- a/bsnes/ui-phoenix/base.hpp
+++ b/bsnes/ui-phoenix/base.hpp
@@ -6,7 +6,7 @@
#include
#include
#include
-#include
+#include
using namespace nall;
#include
diff --git a/bsnes/ui-phoenix/cartridge/cartridge.cpp b/bsnes/ui-phoenix/cartridge/cartridge.cpp
index 0f887ea0..67ae3a26 100755
--- a/bsnes/ui-phoenix/cartridge/cartridge.cpp
+++ b/bsnes/ui-phoenix/cartridge/cartridge.cpp
@@ -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;
diff --git a/bsnes/ui-phoenix/debugger/console.cpp b/bsnes/ui-phoenix/debugger/console.cpp
index 8745715e..96ffc02a 100755
--- a/bsnes/ui-phoenix/debugger/console.cpp
+++ b/bsnes/ui-phoenix/debugger/console.cpp
@@ -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);
+}
diff --git a/bsnes/ui-phoenix/debugger/console.hpp b/bsnes/ui-phoenix/debugger/console.hpp
index 549a5562..6861447d 100755
--- a/bsnes/ui-phoenix/debugger/console.hpp
+++ b/bsnes/ui-phoenix/debugger/console.hpp
@@ -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;
diff --git a/bsnes/ui-phoenix/debugger/cpu/debugger.cpp b/bsnes/ui-phoenix/debugger/cpu/debugger.cpp
index 6ad86531..4167d2c1 100755
--- a/bsnes/ui-phoenix/debugger/cpu/debugger.cpp
+++ b/bsnes/ui-phoenix/debugger/cpu/debugger.cpp
@@ -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();
}
diff --git a/bsnes/ui-phoenix/debugger/debugger.cpp b/bsnes/ui-phoenix/debugger/debugger.cpp
index 897be90f..102aab8e 100755
--- a/bsnes/ui-phoenix/debugger/debugger.cpp
+++ b/bsnes/ui-phoenix/debugger/debugger.cpp
@@ -2,28 +2,57 @@
#if defined(DEBUGGER)
#include
+#include
#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();
}
}
diff --git a/bsnes/ui-phoenix/debugger/debugger.hpp b/bsnes/ui-phoenix/debugger/debugger.hpp
index 852c179e..f890141b 100755
--- a/bsnes/ui-phoenix/debugger/debugger.hpp
+++ b/bsnes/ui-phoenix/debugger/debugger.hpp
@@ -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();
diff --git a/bsnes/ui-phoenix/debugger/smp/debugger.cpp b/bsnes/ui-phoenix/debugger/smp/debugger.cpp
new file mode 100755
index 00000000..875ca7bb
--- /dev/null
+++ b/bsnes/ui-phoenix/debugger/smp/debugger.cpp
@@ -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);
+}
diff --git a/bsnes/ui-phoenix/debugger/smp/debugger.hpp b/bsnes/ui-phoenix/debugger/smp/debugger.hpp
new file mode 100755
index 00000000..ccd498cc
--- /dev/null
+++ b/bsnes/ui-phoenix/debugger/smp/debugger.hpp
@@ -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;
diff --git a/bsnes/ui-phoenix/debugger/tools/memory-editor.cpp b/bsnes/ui-phoenix/debugger/tools/memory-editor.cpp
new file mode 100755
index 00000000..665a8d77
--- /dev/null
+++ b/bsnes/ui-phoenix/debugger/tools/memory-editor.cpp
@@ -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);
+}
diff --git a/bsnes/ui-phoenix/debugger/tools/memory-editor.hpp b/bsnes/ui-phoenix/debugger/tools/memory-editor.hpp
new file mode 100755
index 00000000..9bcfb899
--- /dev/null
+++ b/bsnes/ui-phoenix/debugger/tools/memory-editor.hpp
@@ -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;
diff --git a/bsnes/ui-qt/cartridge/cartridge.cpp b/bsnes/ui-qt/cartridge/cartridge.cpp
index 47d14d87..520848c7 100755
--- a/bsnes/ui-qt/cartridge/cartridge.cpp
+++ b/bsnes/ui-qt/cartridge/cartridge.cpp
@@ -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);
diff --git a/bsnes/ui-qt/ui-base.hpp b/bsnes/ui-qt/ui-base.hpp
index 05b3b6b2..b8d0fc37 100755
--- a/bsnes/ui-qt/ui-base.hpp
+++ b/bsnes/ui-qt/ui-base.hpp
@@ -13,7 +13,7 @@
#include
#include
#include
-#include
+#include
#include "template/concept.hpp"
#include "template/check-action.moc.hpp"
#include "template/file-dialog.moc.hpp"