bsnes-plus/common/nall/snes/cpu.hpp

473 lines
13 KiB
C++

#ifndef NALL_SNES_CPU_HPP
#define NALL_SNES_CPU_HPP
namespace nall {
struct SNESCPU {
enum : unsigned {
Implied, //
Constant, //#$00
AccumConstant, //#$00
IndexConstant, //#$00
Direct, //$00
DirectX, //$00,x
DirectY, //$00,y
IDirect, //($00)
IDirectX, //($00,x)
IDirectY, //($00),y
ILDirect, //[$00]
ILDirectY, //[$00],y
Address, //$0000
AddressX, //$0000,x
AddressY, //$0000,y
IAddressX, //($0000,x)
ILAddress, //[$0000]
PAddress, //PBR:$0000
PIAddress, //PBR:($0000)
Long, //$000000
LongX, //$000000,x
Stack, //$00,s
IStackY, //($00,s),y
BlockMove, //$00,$00
RelativeShort, //+/- $00
RelativeLong, //+/- $0000
};
struct OpcodeInfo {
char name[4];
unsigned mode;
};
static unsigned getOpcodeLength(bool accum, bool index, uint8_t opcode);
static bool getOpcodeIndirect(uint8_t opcode);
static string disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb);
};
static const SNESCPU::OpcodeInfo cpuOpcodeInfo[256] = {
//0x00 - 0x0f
{ "brk", SNESCPU::Constant },
{ "ora", SNESCPU::IDirectX },
{ "cop", SNESCPU::Constant },
{ "ora", SNESCPU::Stack },
{ "tsb", SNESCPU::Direct },
{ "ora", SNESCPU::Direct },
{ "asl", SNESCPU::Direct },
{ "ora", SNESCPU::ILDirect },
{ "php", SNESCPU::Implied },
{ "ora", SNESCPU::AccumConstant },
{ "asl", SNESCPU::Implied },
{ "phd", SNESCPU::Implied },
{ "tsb", SNESCPU::Address },
{ "ora", SNESCPU::Address },
{ "asl", SNESCPU::Address },
{ "ora", SNESCPU::Long },
//0x10 - 0x1f
{ "bpl", SNESCPU::RelativeShort },
{ "ora", SNESCPU::IDirectY },
{ "ora", SNESCPU::IDirect },
{ "ora", SNESCPU::IStackY },
{ "trb", SNESCPU::Direct },
{ "ora", SNESCPU::DirectX },
{ "asl", SNESCPU::DirectX },
{ "ora", SNESCPU::ILDirectY },
{ "clc", SNESCPU::Implied },
{ "ora", SNESCPU::AddressY },
{ "inc", SNESCPU::Implied },
{ "tcs", SNESCPU::Implied },
{ "trb", SNESCPU::Address },
{ "ora", SNESCPU::AddressX },
{ "asl", SNESCPU::AddressX },
{ "ora", SNESCPU::LongX },
//0x20 - 0x2f
{ "jsr", SNESCPU::PAddress },
{ "and", SNESCPU::IDirectX },
{ "jsl", SNESCPU::Long },
{ "and", SNESCPU::Stack },
{ "bit", SNESCPU::Direct },
{ "and", SNESCPU::Direct },
{ "rol", SNESCPU::Direct },
{ "and", SNESCPU::ILDirect },
{ "plp", SNESCPU::Implied },
{ "and", SNESCPU::AccumConstant },
{ "rol", SNESCPU::Implied },
{ "pld", SNESCPU::Implied },
{ "bit", SNESCPU::Address },
{ "and", SNESCPU::Address },
{ "rol", SNESCPU::Address },
{ "and", SNESCPU::Long },
//0x30 - 0x3f
{ "bmi", SNESCPU::RelativeShort },
{ "and", SNESCPU::IDirectY },
{ "and", SNESCPU::IDirect },
{ "and", SNESCPU::IStackY },
{ "bit", SNESCPU::DirectX },
{ "and", SNESCPU::DirectX },
{ "rol", SNESCPU::DirectX },
{ "and", SNESCPU::ILDirectY },
{ "sec", SNESCPU::Implied },
{ "and", SNESCPU::AddressY },
{ "dec", SNESCPU::Implied },
{ "tsc", SNESCPU::Implied },
{ "bit", SNESCPU::AddressX },
{ "and", SNESCPU::AddressX },
{ "rol", SNESCPU::AddressX },
{ "and", SNESCPU::LongX },
//0x40 - 0x4f
{ "rti", SNESCPU::Implied },
{ "eor", SNESCPU::IDirectX },
{ "wdm", SNESCPU::Constant },
{ "eor", SNESCPU::Stack },
{ "mvp", SNESCPU::BlockMove },
{ "eor", SNESCPU::Direct },
{ "lsr", SNESCPU::Direct },
{ "eor", SNESCPU::ILDirect },
{ "pha", SNESCPU::Implied },
{ "eor", SNESCPU::AccumConstant },
{ "lsr", SNESCPU::Implied },
{ "phk", SNESCPU::Implied },
{ "jmp", SNESCPU::PAddress },
{ "eor", SNESCPU::Address },
{ "lsr", SNESCPU::Address },
{ "eor", SNESCPU::Long },
//0x50 - 0x5f
{ "bvc", SNESCPU::RelativeShort },
{ "eor", SNESCPU::IDirectY },
{ "eor", SNESCPU::IDirect },
{ "eor", SNESCPU::IStackY },
{ "mvn", SNESCPU::BlockMove },
{ "eor", SNESCPU::DirectX },
{ "lsr", SNESCPU::DirectX },
{ "eor", SNESCPU::ILDirectY },
{ "cli", SNESCPU::Implied },
{ "eor", SNESCPU::AddressY },
{ "phy", SNESCPU::Implied },
{ "tcd", SNESCPU::Implied },
{ "jml", SNESCPU::Long },
{ "eor", SNESCPU::AddressX },
{ "lsr", SNESCPU::AddressX },
{ "eor", SNESCPU::LongX },
//0x60 - 0x6f
{ "rts", SNESCPU::Implied },
{ "adc", SNESCPU::IDirectX },
{ "per", SNESCPU::Address },
{ "adc", SNESCPU::Stack },
{ "stz", SNESCPU::Direct },
{ "adc", SNESCPU::Direct },
{ "ror", SNESCPU::Direct },
{ "adc", SNESCPU::ILDirect },
{ "pla", SNESCPU::Implied },
{ "adc", SNESCPU::AccumConstant },
{ "ror", SNESCPU::Implied },
{ "rtl", SNESCPU::Implied },
{ "jmp", SNESCPU::PIAddress },
{ "adc", SNESCPU::Address },
{ "ror", SNESCPU::Address },
{ "adc", SNESCPU::Long },
//0x70 - 0x7f
{ "bvs", SNESCPU::RelativeShort },
{ "adc", SNESCPU::IDirectY },
{ "adc", SNESCPU::IDirect },
{ "adc", SNESCPU::IStackY },
{ "stz", SNESCPU::DirectX },
{ "adc", SNESCPU::DirectX },
{ "ror", SNESCPU::DirectX },
{ "adc", SNESCPU::ILDirectY },
{ "sei", SNESCPU::Implied },
{ "adc", SNESCPU::AddressY },
{ "ply", SNESCPU::Implied },
{ "tdc", SNESCPU::Implied },
{ "jmp", SNESCPU::IAddressX },
{ "adc", SNESCPU::AddressX },
{ "ror", SNESCPU::AddressX },
{ "adc", SNESCPU::LongX },
//0x80 - 0x8f
{ "bra", SNESCPU::RelativeShort },
{ "sta", SNESCPU::IDirectX },
{ "brl", SNESCPU::RelativeLong },
{ "sta", SNESCPU::Stack },
{ "sty", SNESCPU::Direct },
{ "sta", SNESCPU::Direct },
{ "stx", SNESCPU::Direct },
{ "sta", SNESCPU::ILDirect },
{ "dey", SNESCPU::Implied },
{ "bit", SNESCPU::AccumConstant },
{ "txa", SNESCPU::Implied },
{ "phb", SNESCPU::Implied },
{ "sty", SNESCPU::Address },
{ "sta", SNESCPU::Address },
{ "stx", SNESCPU::Address },
{ "sta", SNESCPU::Long },
//0x90 - 0x9f
{ "bcc", SNESCPU::RelativeShort },
{ "sta", SNESCPU::IDirectY },
{ "sta", SNESCPU::IDirect },
{ "sta", SNESCPU::IStackY },
{ "sty", SNESCPU::DirectX },
{ "sta", SNESCPU::DirectX },
{ "stx", SNESCPU::DirectY },
{ "sta", SNESCPU::ILDirectY },
{ "tya", SNESCPU::Implied },
{ "sta", SNESCPU::AddressY },
{ "txs", SNESCPU::Implied },
{ "txy", SNESCPU::Implied },
{ "stz", SNESCPU::Address },
{ "sta", SNESCPU::AddressX },
{ "stz", SNESCPU::AddressX },
{ "sta", SNESCPU::LongX },
//0xa0 - 0xaf
{ "ldy", SNESCPU::IndexConstant },
{ "lda", SNESCPU::IDirectX },
{ "ldx", SNESCPU::IndexConstant },
{ "lda", SNESCPU::Stack },
{ "ldy", SNESCPU::Direct },
{ "lda", SNESCPU::Direct },
{ "ldx", SNESCPU::Direct },
{ "lda", SNESCPU::ILDirect },
{ "tay", SNESCPU::Implied },
{ "lda", SNESCPU::AccumConstant },
{ "tax", SNESCPU::Implied },
{ "plb", SNESCPU::Implied },
{ "ldy", SNESCPU::Address },
{ "lda", SNESCPU::Address },
{ "ldx", SNESCPU::Address },
{ "lda", SNESCPU::Long },
//0xb0 - 0xbf
{ "bcs", SNESCPU::RelativeShort },
{ "lda", SNESCPU::IDirectY },
{ "lda", SNESCPU::IDirect },
{ "lda", SNESCPU::IStackY },
{ "ldy", SNESCPU::DirectX },
{ "lda", SNESCPU::DirectX },
{ "ldx", SNESCPU::DirectY },
{ "lda", SNESCPU::ILDirectY },
{ "clv", SNESCPU::Implied },
{ "lda", SNESCPU::AddressY },
{ "tsx", SNESCPU::Implied },
{ "tyx", SNESCPU::Implied },
{ "ldy", SNESCPU::AddressX },
{ "lda", SNESCPU::AddressX },
{ "ldx", SNESCPU::AddressY },
{ "lda", SNESCPU::LongX },
//0xc0 - 0xcf
{ "cpy", SNESCPU::IndexConstant },
{ "cmp", SNESCPU::IDirectX },
{ "rep", SNESCPU::Constant },
{ "cmp", SNESCPU::Stack },
{ "cpy", SNESCPU::Direct },
{ "cmp", SNESCPU::Direct },
{ "dec", SNESCPU::Direct },
{ "cmp", SNESCPU::ILDirect },
{ "iny", SNESCPU::Implied },
{ "cmp", SNESCPU::AccumConstant },
{ "dex", SNESCPU::Implied },
{ "wai", SNESCPU::Implied },
{ "cpy", SNESCPU::Address },
{ "cmp", SNESCPU::Address },
{ "dec", SNESCPU::Address },
{ "cmp", SNESCPU::Long },
//0xd0 - 0xdf
{ "bne", SNESCPU::RelativeShort },
{ "cmp", SNESCPU::IDirectY },
{ "cmp", SNESCPU::IDirect },
{ "cmp", SNESCPU::IStackY },
{ "pei", SNESCPU::IDirect },
{ "cmp", SNESCPU::DirectX },
{ "dec", SNESCPU::DirectX },
{ "cmp", SNESCPU::ILDirectY },
{ "cld", SNESCPU::Implied },
{ "cmp", SNESCPU::AddressY },
{ "phx", SNESCPU::Implied },
{ "stp", SNESCPU::Implied },
{ "jmp", SNESCPU::ILAddress },
{ "cmp", SNESCPU::AddressX },
{ "dec", SNESCPU::AddressX },
{ "cmp", SNESCPU::LongX },
//0xe0 - 0xef
{ "cpx", SNESCPU::IndexConstant },
{ "sbc", SNESCPU::IDirectX },
{ "sep", SNESCPU::Constant },
{ "sbc", SNESCPU::Stack },
{ "cpx", SNESCPU::Direct },
{ "sbc", SNESCPU::Direct },
{ "inc", SNESCPU::Direct },
{ "sbc", SNESCPU::ILDirect },
{ "inx", SNESCPU::Implied },
{ "sbc", SNESCPU::AccumConstant },
{ "nop", SNESCPU::Implied },
{ "xba", SNESCPU::Implied },
{ "cpx", SNESCPU::Address },
{ "sbc", SNESCPU::Address },
{ "inc", SNESCPU::Address },
{ "sbc", SNESCPU::Long },
//0xf0 - 0xff
{ "beq", SNESCPU::RelativeShort },
{ "sbc", SNESCPU::IDirectY },
{ "sbc", SNESCPU::IDirect },
{ "sbc", SNESCPU::IStackY },
{ "pea", SNESCPU::Address },
{ "sbc", SNESCPU::DirectX },
{ "inc", SNESCPU::DirectX },
{ "sbc", SNESCPU::ILDirectY },
{ "sed", SNESCPU::Implied },
{ "sbc", SNESCPU::AddressY },
{ "plx", SNESCPU::Implied },
{ "xce", SNESCPU::Implied },
{ "jsr", SNESCPU::IAddressX },
{ "sbc", SNESCPU::AddressX },
{ "inc", SNESCPU::AddressX },
{ "sbc", SNESCPU::LongX },
};
inline unsigned SNESCPU::getOpcodeLength(bool accum, bool index, uint8_t opcode) {
switch(cpuOpcodeInfo[opcode].mode) { default:
case Implied: return 1;
case Constant: return 2;
case AccumConstant: return 3 - accum;
case IndexConstant: return 3 - index;
case Direct: return 2;
case DirectX: return 2;
case DirectY: return 2;
case IDirect: return 2;
case IDirectX: return 2;
case IDirectY: return 2;
case ILDirect: return 2;
case ILDirectY: return 2;
case Address: return 3;
case AddressX: return 3;
case AddressY: return 3;
case IAddressX: return 3;
case ILAddress: return 3;
case PAddress: return 3;
case PIAddress: return 3;
case Long: return 4;
case LongX: return 4;
case Stack: return 2;
case IStackY: return 2;
case BlockMove: return 3;
case RelativeShort: return 2;
case RelativeLong: return 3;
}
}
inline bool SNESCPU::getOpcodeIndirect(uint8_t opcode) {
switch(cpuOpcodeInfo[opcode].mode) {
case IDirect:
case IDirectX:
case IDirectY:
case ILDirect:
case ILDirectY:
case IAddressX:
case ILAddress:
return true;
default:
return false;
}
}
inline string SNESCPU::disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb) {
string name = cpuOpcodeInfo[opcode].name;
unsigned mode = cpuOpcodeInfo[opcode].mode;
if(mode == Implied) return name;
if(mode == Constant) return { name, " #$", hex<2>(pl) };
if(mode == AccumConstant) return { name, " #$", accum ? "" : hex<2>(ph), hex<2>(pl) };
if(mode == IndexConstant) return { name, " #$", index ? "" : hex<2>(ph), hex<2>(pl) };
if(mode == Direct) return { name, " $", hex<2>(pl) };
if(mode == DirectX) return { name, " $", hex<2>(pl), ",x" };
if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" };
if(mode == IDirect) return { name, " ($", hex<2>(pl), ")" };
if(mode == IDirectX) return { name, " ($", hex<2>(pl), ",x)" };
if(mode == IDirectY) return { name, " ($", hex<2>(pl), "),y" };
if(mode == ILDirect) return { name, " [$", hex<2>(pl), "]" };
if(mode == ILDirectY) return { name, " [$", hex<2>(pl), "],y" };
if(mode == Address) return { name, " $", hex<2>(ph), hex<2>(pl) };
if(mode == AddressX) return { name, " $", hex<2>(ph), hex<2>(pl), ",x" };
if(mode == AddressY) return { name, " $", hex<2>(ph), hex<2>(pl), ",y" };
if(mode == IAddressX) return { name, " ($", hex<2>(ph), hex<2>(pl), ",x)" };
if(mode == ILAddress) return { name, " [$", hex<2>(ph), hex<2>(pl), "]" };
if(mode == PAddress) return { name, " $", hex<2>(ph), hex<2>(pl) };
if(mode == PIAddress) return { name, " ($", hex<2>(ph), hex<2>(pl), ")" };
if(mode == Long) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl) };
if(mode == LongX) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl), ",x" };
if(mode == Stack) return { name, " $", hex<2>(pl), ",s" };
if(mode == IStackY) return { name, " ($", hex<2>(pl), ",s),y" };
if(mode == BlockMove) return { name, " $", hex<2>(ph), ", $", hex<2>(pl) };
if(mode == RelativeShort) {
unsigned addr = (uint16_t)(pc + 2) + (int8_t)(pl << 0);
return { name, " $", hex<4>(addr) };
}
if(mode == RelativeLong) {
unsigned addr = (uint16_t)(pc + 3) + (int16_t)((ph << 8) + (pl << 0));
return { name, " $", hex<4>(addr) };
}
return "";
}
}
#endif