From edac93b80090a507966ac341ebabe4b1b15fee87 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sat, 30 Oct 2010 19:18:43 +1100 Subject: [PATCH] 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. --- bsnes/nall/snes/{info.hpp => cartridge.hpp} | 31 +- bsnes/nall/snes/cpu.hpp | 8 +- bsnes/nall/snes/smp.hpp | 639 ++++++++++++++++++ bsnes/phoenix/gtk/hexeditor.cpp | 2 +- bsnes/snes/debugger/debugger.cpp | 5 + bsnes/snes/debugger/debugger.hpp | 2 +- bsnes/snes/smp/smp.hpp | 4 +- bsnes/snes/snes.hpp | 2 +- bsnes/ui-phoenix/base.hpp | 2 +- bsnes/ui-phoenix/cartridge/cartridge.cpp | 2 +- bsnes/ui-phoenix/debugger/console.cpp | 16 + bsnes/ui-phoenix/debugger/console.hpp | 2 + bsnes/ui-phoenix/debugger/cpu/debugger.cpp | 7 +- bsnes/ui-phoenix/debugger/debugger.cpp | 51 +- bsnes/ui-phoenix/debugger/debugger.hpp | 6 + bsnes/ui-phoenix/debugger/smp/debugger.cpp | 102 +++ bsnes/ui-phoenix/debugger/smp/debugger.hpp | 15 + .../debugger/tools/memory-editor.cpp | 78 +++ .../debugger/tools/memory-editor.hpp | 16 + bsnes/ui-qt/cartridge/cartridge.cpp | 2 +- bsnes/ui-qt/ui-base.hpp | 2 +- 21 files changed, 958 insertions(+), 36 deletions(-) rename bsnes/nall/snes/{info.hpp => cartridge.hpp} (97%) create mode 100755 bsnes/nall/snes/smp.hpp create mode 100755 bsnes/ui-phoenix/debugger/smp/debugger.cpp create mode 100755 bsnes/ui-phoenix/debugger/smp/debugger.hpp create mode 100755 bsnes/ui-phoenix/debugger/tools/memory-editor.cpp create mode 100755 bsnes/ui-phoenix/debugger/tools/memory-editor.hpp 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"