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:
Tim Allen 2010-10-30 19:18:43 +11:00
parent 0730f847e5
commit edac93b800
21 changed files with 958 additions and 36 deletions

View File

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

View File

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

639
bsnes/nall/snes/smp.hpp Executable file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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