Mesen-S/Core/SpcDisUtils.cpp

156 lines
11 KiB
C++

#include "stdafx.h"
#include "SpcDisUtils.h"
#include "Console.h"
#include "DummySpc.h"
#include "DisassemblyInfo.h"
#include "EmuSettings.h"
#include "LabelManager.h"
#include "../Utilities/FastString.h"
#include "../Utilities/HexUtilities.h"
constexpr const char* _altOpTemplate[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 e,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,q", "STOP"
};
constexpr const char* _opTemplate[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", "CMY #i","PLA", "STA (X)+,A",
"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", "INC Y", "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
};
void SpcDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings)
{
FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly));
AddressInfo addrInfo { 0, SnesMemoryType::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->CheckDebuggerFlag(DebuggerFlags::UseAltSpcOpNames) ? _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();
}
int32_t SpcDisUtils::GetEffectiveAddress(DisassemblyInfo &info, Console *console, SpcState &state)
{
if(_needAddress[info.GetOpCode()]) {
Spc* spc = console->GetSpc().get();
DummySpc dummySpc(spc->GetSpcRam(), state);
dummySpc.Step();
uint32_t addr;
uint8_t value;
uint32_t writeCount = dummySpc.GetWriteCount();
if(writeCount > 0) {
dummySpc.GetWriteInfo(writeCount - 1, addr, value);
} else {
uint32_t readCount = dummySpc.GetReadCount();
dummySpc.GetReadInfo(readCount - 1, addr, value);
}
return addr;
}
return -1;
}
uint8_t SpcDisUtils::GetOpSize(uint8_t opCode)
{
return _opSize[opCode];
}