mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
276 lines
No EOL
15 KiB
C++
276 lines
No EOL
15 KiB
C++
#include "pch.h"
|
|
#include "SNES/SnesConsole.h"
|
|
#include "SNES/Spc.h"
|
|
#include "SNES/Debugger/SpcDisUtils.h"
|
|
#include "SNES/Debugger/DummySpc.h"
|
|
#include "Debugger/DisassemblyInfo.h"
|
|
#include "Debugger/LabelManager.h"
|
|
#include "Shared/EmuSettings.h"
|
|
#include "Utilities/FastString.h"
|
|
#include "Utilities/HexUtilities.h"
|
|
|
|
constexpr const char* _opTemplate[256] = {
|
|
"NOP", "TCALL 0", "SET1 d.0", "BBS d.0,q", "OR A,d", "OR A,!a", "OR A,(X)", "OR A,[d+X]", "OR A,#i", "OR t,s", "OR1 C,m.b", "ASL d", "ASL !a", "PUSH PSW", "TSET1 !a", "BRK",
|
|
"BPL r", "TCALL 1", "CLR1 d.0", "BBC d.0,q", "OR A,d+X", "OR A,!a+X", "OR A,!a+Y", "OR A,[d]+Y", "OR e,#i", "OR (X),(Y)", "DECW d", "ASL d+X", "ASL A", "DEC X", "CMP X,!a", "JMP [!a+X]",
|
|
"CLRP", "TCALL 2", "SET1 d.1", "BBS d.1,q", "AND A,d", "AND A,!a", "AND A,(X)", "AND A,[d+X]", "AND A,#i", "AND t,s", "OR1 C,/m.b", "ROL d", "ROL !a", "PUSH A", "CBNE d,q", "BRA r",
|
|
"BMI r", "TCALL 3", "CLR1 d.1", "BBC d.1,q", "AND A,d+X", "AND A,!a+X", "AND A,!a+Y", "AND A,[d]+Y", "AND e,#i", "AND (X),(Y)", "INCW d", "ROL d+X", "ROL A", "INC X", "CMP X,d", "CALL !a",
|
|
"SETP", "TCALL 4", "SET1 d.2", "BBS d.2,q", "EOR A,d", "EOR A,!a", "EOR A,(X)", "EOR A,[d+X]", "EOR A,#i", "EOR t,s", "AND1 C,m.b", "LSR d", "LSR !a", "PUSH X", "TCLR1 !a", "PCALL u",
|
|
"BVC r", "TCALL 5", "CLR1 d.2", "BBC d.2,q", "EOR A,d+X", "EOR A,!a+X", "EOR A,!a+Y", "EOR A,[d]+Y", "EOR e,#i", "EOR (X),(Y)", "CMPW YA,d", "LSR d+X", "LSR A", "MOV X,A", "CMP Y,!a", "JMP !a",
|
|
"CLRC", "TCALL 6", "SET1 d.3", "BBS d.3,q", "CMP A,d", "CMP A,!a", "CMP A,(X)", "CMP A,[d+X]", "CMP A,#i", "CMP t,s", "AND1 C,/m.b", "ROR d", "ROR !a", "PUSH Y", "DBNZ d,q", "RET",
|
|
"BVS r", "TCALL 7", "CLR1 d.3", "BBC d.3,q", "CMP A,d+X", "CMP A,!a+X", "CMP A,!a+Y", "CMP A,[d]+Y", "CMP e,#i", "CMP (X),(Y)", "ADDW YA,d", "ROR d+X", "ROR A", "MOV A,X", "CMP Y,d", "RET1",
|
|
"SETC", "TCALL 8", "SET1 d.4", "BBS d.4,q", "ADC A,d", "ADC A,!a", "ADC A,(X)", "ADC A,[d+X]", "ADC A,#i", "ADC t,s", "EOR1 C,m.b", "DEC d", "DEC !a", "MOV Y,#i", "POP PSW", "MOV e,#i",
|
|
"BCC r", "TCALL 9", "CLR1 d.4", "BBC d.4,q", "ADC A,d+X", "ADC A,!a+X", "ADC A,!a+Y", "ADC A,[d]+Y", "ADC e,#i", "ADC (X),(Y)", "SUBW YA,d", "DEC d+X", "DEC A", "MOV X,SP", "DIV YA,X", "XCN A",
|
|
"EI", "TCALL 10", "SET1 d.5", "BBS d.5,q", "SBC A,d", "SBC A,!a", "SBC A,(X)", "SBC A,[d+X]", "SBC A,#i", "SBC t,s", "MOV1 C,m.b", "INC d", "INC !a", "CMP Y,#i", "POP A", "MOV (X)+,A",
|
|
"BCS r", "TCALL 11", "CLR1 d.5", "BBC d.5,q", "SBC A,d+X", "SBC A,!a+X", "SBC A,!a+Y", "SBC A,[d]+Y", "SBC e,#i", "SBC (X),(Y)", "MOVW YA,d", "INC d+X", "INC A", "MOV SP,X", "DAS A", "MOV A,(X)+",
|
|
"DI", "TCALL 12", "SET1 d.6", "BBS d.6,q", "MOV d,A", "MOV !a,A", "MOV (X),A", "MOV [d+X],A", "CMP X,#i", "MOV !a,X", "MOV1 m.b,C", "MOV d,Y", "MOV !a,Y", "MOV X,#i", "POP X", "MUL YA",
|
|
"BNE r", "TCALL 13", "CLR1 d.6", "BBC d.6,q", "MOV d+X,A", "MOV !a+X,A", "MOV !a+Y,A", "MOV [d]+Y,A", "MOV d,X", "MOV d+Y,X", "MOVW d,YA", "MOV d+X,Y", "DEC Y", "MOV A,Y", "CBNE d+X,q", "DAA A",
|
|
"CLRV", "TCALL 14", "SET1 d.7", "BBS d.7,q", "MOV A,d", "MOV A,!a", "MOV A,(X)", "MOV A,[d+X]", "MOV A,#i", "MOV X,!a", "NOT1 m.b", "MOV Y,d", "MOV Y,!a", "NOTC", "POP Y", "SLEEP",
|
|
"BEQ r", "TCALL 15", "CLR1 d.7", "BBC d.7,q", "MOV A,d+X", "MOV A,!a+X", "MOV A,!a+Y", "MOV A,[d]+Y", "MOV X,d", "MOV X,d+Y", "MOV t,s", "MOV Y,d+X", "INC Y", "MOV Y,A", "DBNZ Y,r", "STOP"
|
|
};
|
|
|
|
constexpr const char* _altOpTemplate[256] = {
|
|
"NOP", "JST0", "SET1 d.0", "BBS d.0,q", "ORA d", "ORA a", "ORA (X)", "ORA [d,X]", "ORA #i", "OR t,s", "ORC m.b", "ASL d", "ASL a", "PHP", "SET1 a", "BRK",
|
|
"BPL r", "JST1", "CLR1 d.0", "BBC d.0,q", "ORA d,X", "ORA a,X", "ORA a,Y", "ORA [d],Y", "OR e,#i", "OR (X),(Y)", "DEW d", "ASL d,X", "ASL A", "DEX", "CPX a", "JMP [a,X]",
|
|
"CLP", "JST2", "SET1 d.1", "BBS d.1,q", "AND d", "AND a", "AND (X)", "AND [d,X]", "AND #i", "AND t,s", "ORC /m.b", "ROL d", "ROL a", "PHA", "CBNE d,q", "BRA r",
|
|
"BMI r", "JST3", "CLR1 d.1", "BBC d.1,q", "AND d,X", "AND a,X", "AND a,Y", "AND [d],Y", "AND e,#i", "AND (X),(Y)", "INW d", "ROL d,X", "ROL A", "INX", "CPX d", "JSR a",
|
|
"SEP", "JST4", "SET1 d.2", "BBS d.2,q", "EOR d", "EOR a", "EOR (X)", "EOR [d,X]", "EOR #i", "EOR t,s", "ANDC m.b", "LSR d", "LSR a", "PHX", "CLR1 a", "JSP u",
|
|
"BVC r", "JST5", "CLR1 d.2", "BBC d.2,q", "EOR d,X", "EOR a,X", "EOR a,Y", "EOR [d],Y", "EOR e,#i", "EOR (X),(Y)", "CPW d", "LSR d,X", "LSR A", "TAX", "CPY a", "JMP a",
|
|
"CLC", "JST6", "SET1 d.3", "BBS d.3,q", "CMP d", "CMP a", "CMP (X)", "CMP [d,X]", "CMP #i", "CMP t,s", "ANDC /m.b", "ROR d", "ROR a", "PHY", "DBNZ d,q", "RTS",
|
|
"BVS r", "JST7", "CLR1 d.3", "BBC d.3,q", "CMP d,X", "CMP a,X", "CMP a,Y", "CMP [d],Y", "CMP e,#i", "CMP (X),(Y)", "ADW d", "ROR d,X", "ROR A", "TXA", "CPY d", "RTI",
|
|
"SEC", "JST8", "SET1 d.4", "BBS d.4,q", "ADC d", "ADC a", "ADC (X)", "ADC [d,X]", "ADC #i", "ADC t,s", "EORC m.b", "DEC d", "DEC a", "LDY #i","PLP", "MOV e,#i",
|
|
"BCC r", "JST9", "CLR1 d.4", "BBC d.4,q", "ADC d,X", "ADC a,X", "ADC a,Y", "ADC [d],Y", "ADC e,#i", "ADC (X),(Y)", "SBW d", "DEC d,X", "DEC A", "TSX", "DIV YA,X", "XCN A",
|
|
"CLI", "JSTA", "SET1 d.5", "BBS d.5,q", "SBC d", "SBC a", "SBC (X)", "SBC [d,X]", "SBC #i", "SBC t,s", "LDC m.b", "INC d", "INC a", "CPY #i","PLA", "STA (X)+",
|
|
"BCS r", "JSTB", "CLR1 d.5", "BBC d.5,q", "SBC d,X", "SBC a,X", "SBC a,Y", "SBC [d],Y", "SBC e,#i", "SBC (X),(Y)", "LDW d", "INC d,X", "INC A", "TXS", "DAS A", "LDA (X)+",
|
|
"SEI", "JSTC", "SET1 d.6", "BBS d.6,q", "STA d", "STA a", "STA (X)", "STA [d,X]", "CPX #i", "STX a", "STC m.b", "STY d", "STY a", "LDX #i","PLX", "MUL YA",
|
|
"BNE r", "JSTD", "CLR1 d.6", "BBC d.6,q", "STA d,X", "STA a,X", "STA a,Y", "STA [d],Y", "STX d", "STX d,Y", "STW d", "STY d,X", "DEY", "TYA", "CBNE d,X, q", "DAA A",
|
|
"CLV", "JSTE", "SET1 d.7", "BBS d.7,q", "LDA d", "LDA a", "LDA (X)", "LDA [d,X]", "LDA #i", "LDX a", "NOT m.b", "LDY d", "LDY a", "NOTC", "PLY", "WAI",
|
|
"BEQ r", "JSTF", "CLR1 d.7", "BBC d.7,q", "LDA d,X", "LDA a,X", "LDA a,Y", "LDA [d],Y", "LDX d", "LDX d,Y", "MOV t,s", "LDY d,X", "INY", "TAY", "DBNZ Y,r", "STP"
|
|
};
|
|
|
|
constexpr const uint8_t _opSize[256] = {
|
|
1, 1, 2, 3, 2, 3, 1, 2, 2, 3, 3, 2, 3, 1, 3, 1,
|
|
2, 1, 2, 3, 2, 3, 3, 2, 3, 1, 2, 2, 1, 1, 3, 3,
|
|
1, 1, 2, 3, 2, 3, 1, 2, 2, 3, 3, 2, 3, 1, 3, 2,
|
|
2, 1, 2, 3, 2, 3, 3, 2, 3, 1, 2, 2, 1, 1, 2, 3,
|
|
1, 1, 2, 3, 2, 3, 1, 2, 2, 3, 3, 2, 3, 1, 3, 2,
|
|
2, 1, 2, 3, 2, 3, 3, 2, 3, 1, 2, 2, 1, 1, 3, 3,
|
|
1, 1, 2, 3, 2, 3, 1, 2, 2, 3, 3, 2, 3, 1, 3, 1,
|
|
2, 1, 2, 3, 2, 3, 3, 2, 3, 1, 2, 2, 1, 1, 2, 1,
|
|
1, 1, 2, 3, 2, 3, 1, 2, 2, 3, 3, 2, 3, 2, 1, 3,
|
|
2, 1, 2, 3, 2, 3, 3, 2, 3, 1, 2, 2, 1, 1, 1, 1,
|
|
1, 1, 2, 3, 2, 3, 1, 2, 2, 3, 3, 2, 3, 2, 1, 1,
|
|
2, 1, 2, 3, 2, 3, 3, 2, 3, 1, 2, 2, 1, 1, 1, 1,
|
|
1, 1, 2, 3, 2, 3, 1, 2, 2, 3, 3, 2, 3, 2, 1, 1,
|
|
2, 1, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 1, 1, 3, 1,
|
|
1, 1, 2, 3, 2, 3, 1, 2, 2, 3, 3, 2, 3, 1, 1, 1,
|
|
2, 1, 2, 3, 2, 3, 3, 2, 2, 2, 3, 2, 1, 1, 2, 1,
|
|
};
|
|
|
|
constexpr bool _needAddress[256] = {
|
|
false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, false,
|
|
false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, true,
|
|
false, true, true, true, true, false, true, true, false, false, false, true, false, false, true, false,
|
|
false, true, true, true, true, true, true, true, true, false, true, true, false, false, true, false,
|
|
false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, false,
|
|
false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, false,
|
|
false, true, true, true, true, false, true, true, false, false, false, true, false, false, true, false,
|
|
false, true, true, true, true, true, true, true, true, false, true, true, false, false, true, false,
|
|
false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, true,
|
|
false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, false,
|
|
false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, true,
|
|
false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, true,
|
|
false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, false,
|
|
false, true, true, true, true, true, true, true, true, true, true, true, false, false, true, false,
|
|
false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, false,
|
|
false, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false
|
|
};
|
|
|
|
constexpr bool _showValue[256] = {
|
|
false, false, true, true, true, true, true, true, false, true, true, true, true, false, true, false,
|
|
false, false, true, true, true, true, true, true, true, true, true, true, false, false, true, false,
|
|
false, false, true, true, true, true, true, true, false, true, true, true, true, false, true, false,
|
|
false, false, true, true, true, true, true, true, true, true, true, true, false, false, true, false,
|
|
false, false, true, true, true, true, true, true, false, true, true, true, true, false, true, false,
|
|
false, false, true, true, true, true, true, true, true, true, true, true, false, false, true, false,
|
|
false, false, true, true, true, true, true, true, false, true, true, true, true, false, true, false,
|
|
false, false, true, true, true, true, true, true, true, true, true, true, false, false, true, false,
|
|
false, false, true, true, true, true, true, true, false, true, true, true, true, false, false, true,
|
|
false, false, true, true, true, true, true, true, true, true, true, true, false, false, false, false,
|
|
false, false, true, true, true, true, true, true, false, true, true, true, true, false, false, true,
|
|
false, false, true, true, true, true, true, true, true, true, true, true, false, false, false, true,
|
|
false, false, true, true, true, true, true, true, false, true, true, true, true, false, false, false,
|
|
false, false, true, true, true, true, true, true, true, true, true, true, false, false, true, false,
|
|
false, false, true, true, true, true, true, true, false, true, true, true, true, false, false, false,
|
|
false, false, true, true, true, true, true, true, true, true, true, true, false, false, true, false
|
|
};
|
|
|
|
void SpcDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings)
|
|
{
|
|
FastString str(settings->GetDebugConfig().UseLowerCaseDisassembly);
|
|
|
|
AddressInfo addrInfo { 0, MemoryType::SpcMemory };
|
|
auto getOperand = [&str, &addrInfo, labelManager](uint16_t addr) {
|
|
addrInfo.Address = addr;
|
|
string label = labelManager ? labelManager->GetLabel(addrInfo) : "";
|
|
if(label.empty()) {
|
|
str.WriteAll('$', HexUtilities::ToHex(addr));
|
|
} else {
|
|
str.Write(label, true);
|
|
}
|
|
};
|
|
|
|
uint8_t* byteCode = info.GetByteCode();
|
|
const char* op = settings->GetDebugConfig().SnesUseAltSpcOpNames ? _altOpTemplate[byteCode[0]] : _opTemplate[byteCode[0]];
|
|
int i = 0;
|
|
while(op[i]) {
|
|
switch(op[i]) {
|
|
case 'r': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[1] + GetOpSize(byteCode[0]))); break;
|
|
case 'q': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[2] + GetOpSize(byteCode[0]))); break; //relative 2nd byte
|
|
|
|
case 'a': getOperand((uint16_t)(byteCode[1] | (byteCode[2] << 8))); break;
|
|
|
|
case 'd': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); break;
|
|
case 'e': str.WriteAll('$', HexUtilities::ToHex(byteCode[2])); break; //direct 2nd byte
|
|
|
|
case 's': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); break;
|
|
case 't': str.WriteAll('$', HexUtilities::ToHex(byteCode[2])); break;
|
|
|
|
case 'i': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); break;
|
|
|
|
case 'm': getOperand((uint16_t)((byteCode[1] | (byteCode[2] << 8)) & 0x1FFF)); break;
|
|
case 'b': str.WriteAll((char)('0' + (byteCode[2] >> 5))); break;
|
|
|
|
default: str.Write(op[i]); break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
out += str.ToString();
|
|
}
|
|
|
|
EffectiveAddressInfo SpcDisUtils::GetEffectiveAddress(DisassemblyInfo &info, SnesConsole *console, SpcState &state)
|
|
{
|
|
if(SpcDisUtils::IsConditionalJump(info.GetOpCode()) || SpcDisUtils::IsUnconditionalJump(info.GetOpCode())) {
|
|
//Show nothing for jumps
|
|
return {};
|
|
} else if(!_showValue[info.GetOpCode()]) {
|
|
return {};
|
|
}
|
|
|
|
Spc* spc = console->GetSpc();
|
|
DummySpc dummySpc(spc->GetSpcRam());
|
|
dummySpc.SetDummyState(state);
|
|
dummySpc.Step();
|
|
|
|
uint32_t count = dummySpc.GetOperationCount();
|
|
for(int i = count - 1; i > 0; i--) {
|
|
MemoryOperationInfo opInfo = dummySpc.GetOperationInfo(i);
|
|
if(opInfo.Type != MemoryOperationType::ExecOperand && opInfo.Type != MemoryOperationType::DummyRead) {
|
|
MemoryOperationInfo prevOpInfo = dummySpc.GetOperationInfo(i - 1);
|
|
EffectiveAddressInfo result;
|
|
if(prevOpInfo.Type == opInfo.Type && prevOpInfo.Address == opInfo.Address - 1) {
|
|
//For 16-bit read/writes, return the first address
|
|
result.Address = prevOpInfo.Address;
|
|
result.Type = prevOpInfo.MemType;
|
|
result.ValueSize = 2;
|
|
} else {
|
|
result.Address = opInfo.Address;
|
|
result.Type = opInfo.MemType;
|
|
result.ValueSize = 1;
|
|
}
|
|
result.ShowAddress = _needAddress[info.GetOpCode()];
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
uint8_t SpcDisUtils::GetOpSize(uint8_t opCode)
|
|
{
|
|
return _opSize[opCode];
|
|
}
|
|
|
|
bool SpcDisUtils::IsUnconditionalJump(uint8_t opCode)
|
|
{
|
|
switch(opCode) {
|
|
case 0x01: //TCALL0
|
|
case 0x0F: //BRK
|
|
case 0x11: //TCALL1
|
|
case 0x1F: //JMP
|
|
case 0x21: //TCALL2
|
|
case 0x2F: //BRA
|
|
case 0x31: //TCALL3
|
|
case 0x3F: //CALL
|
|
case 0x41: //TCALL4
|
|
case 0x4F: //PCALL
|
|
case 0x51: //TCALL5
|
|
case 0x5F: //JMP
|
|
case 0x61: //TCALL6
|
|
case 0x6F: //RET
|
|
case 0x71: //TCALL7
|
|
case 0x7F: //RETI
|
|
case 0x81: //TCALL8
|
|
case 0x91: //TCALL9
|
|
case 0xA1: //TCALLA
|
|
case 0xB1: //TCALLB
|
|
case 0xC1: //TCALLC
|
|
case 0xD1: //TCALLD
|
|
case 0xE1: //TCALLE
|
|
case 0xEF: //SLEEP
|
|
case 0xF1: //TCALLF
|
|
case 0xFF: //STOP
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool SpcDisUtils::IsConditionalJump(uint8_t opCode)
|
|
{
|
|
switch(opCode) {
|
|
case 0x03: //BBS0
|
|
case 0x10: //BPL
|
|
case 0x13: //BBC0
|
|
case 0x23: //BBS1
|
|
case 0x2E: //CBNE
|
|
case 0x30: //BMI
|
|
case 0x33: //BBC1
|
|
case 0x43: //BBS2
|
|
case 0x50: //BVC
|
|
case 0x53: //BBC2
|
|
case 0x63: //BBS3
|
|
case 0x6E: //DBNZ
|
|
case 0x70: //BVS
|
|
case 0x73: //BBC3
|
|
case 0x83: //BBS4
|
|
case 0x90: //BCC
|
|
case 0x93: //BBC4
|
|
case 0xA3: //BBS5
|
|
case 0xB0: //BCS
|
|
case 0xB3: //BBC5
|
|
case 0xC3: //BBS6
|
|
case 0xD0: //BNE
|
|
case 0xD3: //BBC6
|
|
case 0xDE: //CBNE
|
|
case 0xE3: //BBS7
|
|
case 0xF0: //BEQ
|
|
case 0xF3: //BBC7
|
|
case 0xFE: //DBNZ
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool SpcDisUtils::IsJumpToSub(uint8_t opCode)
|
|
{
|
|
return opCode == 0x3F || opCode == 0x0F || opCode == 0x4F || (opCode&0x0F) == 0x01; //JSR, BRK, PCALL, TCALL
|
|
}
|
|
|
|
bool SpcDisUtils::IsReturnInstruction(uint8_t opCode)
|
|
{
|
|
return opCode == 0x6F || opCode == 0x7F;
|
|
} |