mirror of
https://github.com/devinacker/bsnes-plus.git
synced 2025-04-02 10:52:46 -04:00
498 lines
16 KiB
C++
498 lines
16 KiB
C++
#include "smp_processor.hpp"
|
|
|
|
// ------------------------------------------------------------------------
|
|
SmpDisasmProcessor::SmpDisasmProcessor(SymbolMap* map) : symbols(map) {
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
string SmpDisasmProcessor::getBreakpointBusName() {
|
|
return "smp";
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
uint32_t SmpDisasmProcessor::getCurrentAddress() {
|
|
return SNES::smp.opcode_pc;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
uint32_t SmpDisasmProcessor::findStartLineAddress(uint32_t currentAddress, uint32_t linesBelow) {
|
|
unsigned line, i;
|
|
|
|
for (line=0; line<linesBelow; line++) {
|
|
for (i=1; i<=4; i++) {
|
|
if ((SNES::smp.usage[(currentAddress + i) & 0xFFFF] & SNES::SMPDebugger::UsageOpcode) == 0) {
|
|
continue;
|
|
}
|
|
|
|
currentAddress += i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return currentAddress;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
uint32_t SmpDisasmProcessor::decode(uint32_t type, uint32_t address, uint32_t pc) {
|
|
return SNES::smp.decode(type, address, pc);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
void SmpDisasmProcessor::setOpcodeParams(DisassemblerLine &result, SNES::SMP::Opcode &opcode, uint32_t pc) {
|
|
uint16_t directAddr = decode(SNESSMP::Direct, opcode.op8(), pc);
|
|
DisassemblerParam directParam = DisassemblerParam::createAddress(opcode.op8(), directAddr);
|
|
|
|
uint16_t absoluteAddr = opcode.op16();
|
|
DisassemblerParam absoluteParam = DisassemblerParam::createAddress(absoluteAddr, absoluteAddr);
|
|
|
|
switch (opcode.optype) {
|
|
case SNESSMP::Implied:
|
|
result.paramFormat = "";
|
|
break;
|
|
|
|
case SNESSMP::Direct:
|
|
result.paramFormat = "%1X2";
|
|
result.params.append(directParam);
|
|
break;
|
|
|
|
case SNESSMP::DirectRelative:
|
|
result.paramFormat = "%1X2, %2X4";
|
|
result.params.append(directParam);
|
|
result.params.append(DisassemblerParam::createAddress(decode(opcode.optype, opcode.op8(1), pc),
|
|
decode(opcode.optype, opcode.op8(1), pc)));
|
|
break;
|
|
|
|
case SNESSMP::DirectDirect:
|
|
result.paramFormat = "%1X2, %2X2";
|
|
result.params.append(DisassemblerParam::createAddress(opcode.op8(1),
|
|
decode(SNESSMP::Direct, opcode.op8(1), pc)));
|
|
result.params.append(directParam);
|
|
break;
|
|
|
|
case SNESSMP::DirectConstant:
|
|
result.paramFormat = "%1X2, #%2X2";
|
|
result.params.append(DisassemblerParam::createAddress(opcode.op8(1),
|
|
decode(SNESSMP::Direct, opcode.op8(1), pc)));
|
|
result.params.append(DisassemblerParam::createValue(opcode.op8(0)));
|
|
break;
|
|
|
|
case SNESSMP::DirectIndX:
|
|
result.paramFormat = "%1X2+x";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op8(),
|
|
directAddr, decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::DirectA:
|
|
result.paramFormat = "%1X2, a";
|
|
result.params.append(directParam);
|
|
break;
|
|
|
|
case SNESSMP::DirectY:
|
|
result.paramFormat = "%1X2, y";
|
|
result.params.append(directParam);
|
|
break;
|
|
|
|
case SNESSMP::DirectIndXA:
|
|
result.paramFormat = "%1X2+x, a";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op8(),
|
|
directAddr, decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::DirectX:
|
|
result.paramFormat = "%1X2, x";
|
|
result.params.append(directParam);
|
|
break;
|
|
|
|
case SNESSMP::DirectIndYX:
|
|
result.paramFormat = "%1X2+y, x";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op8(),
|
|
directAddr, decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::DirectYa:
|
|
result.paramFormat = "%1X2, ya";
|
|
result.params.append(directParam);
|
|
break;
|
|
|
|
case SNESSMP::DirectIndXY:
|
|
result.paramFormat = "%1X2+x, y";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op8(),
|
|
directAddr, decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::DirectIndXRelative:
|
|
result.paramFormat = "%1X2+x, %2X4";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op8(),
|
|
directAddr, decode(SNESSMP::DirectIndX, opcode.op8(), pc)));
|
|
result.params.append(DisassemblerParam::createAddress(decode(opcode.optype, opcode.op8(1), pc),
|
|
decode(opcode.optype, opcode.op8(1), pc)));
|
|
break;
|
|
|
|
case SNESSMP::Absolute:
|
|
result.paramFormat = "%1X4";
|
|
result.params.append(absoluteParam);
|
|
break;
|
|
|
|
case SNESSMP::AbsoluteA:
|
|
result.paramFormat = "%1X4, a";
|
|
result.params.append(absoluteParam);
|
|
break;
|
|
|
|
case SNESSMP::AbsoluteX:
|
|
result.paramFormat = "%1X4, x";
|
|
result.params.append(absoluteParam);
|
|
break;
|
|
|
|
case SNESSMP::AbsoluteBitC:
|
|
result.paramFormat = "%1X4:";
|
|
result.paramFormat << (opcode.op16() >> 13) << ", C";
|
|
result.params.append(DisassemblerParam::createAddress(opcode.op16() & 0x1fff,
|
|
decode(SNESSMP::Absolute, opcode.op16() & 0x1fff, pc)));
|
|
break;
|
|
|
|
case SNESSMP::AbsoluteY:
|
|
result.paramFormat = "%1X4, y";
|
|
result.params.append(absoluteParam);
|
|
break;
|
|
|
|
case SNESSMP::AbsoluteXA:
|
|
result.paramFormat = "%1X4+x, a";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op16(),
|
|
absoluteAddr, decode(opcode.optype, opcode.op16(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::AbsoluteYA:
|
|
result.paramFormat = "%1X4+y, a";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op16(),
|
|
absoluteAddr, decode(opcode.optype, opcode.op16(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::ADirect:
|
|
result.paramFormat = "a, %1X2";
|
|
result.params.append(directParam);
|
|
break;
|
|
|
|
case SNESSMP::AAbsolute:
|
|
result.paramFormat = "a, %1X4";
|
|
result.params.append(absoluteParam);
|
|
break;
|
|
|
|
case SNESSMP::AIDirectIndX:
|
|
result.paramFormat = "a, (%1X2+x)";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op8(),
|
|
directAddr, decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::AConstant:
|
|
result.paramFormat = "a, #%1X2";
|
|
result.params.append(DisassemblerParam::createValue(opcode.op8()));
|
|
break;
|
|
|
|
case SNESSMP::CAbsoluteBit:
|
|
result.paramFormat = "c, %1X4:";
|
|
result.paramFormat << (opcode.op16() >> 13);
|
|
result.params.append(DisassemblerParam::createAddress(opcode.op16() & 0x1fff,
|
|
decode(SNESSMP::Absolute, opcode.op16() & 0x1fff, pc)));
|
|
break;
|
|
|
|
case SNESSMP::CNAbsoluteBit:
|
|
result.paramFormat = "c, !%1X4:";
|
|
result.paramFormat << (opcode.op16() >> 13);
|
|
result.params.append(DisassemblerParam::createAddress(opcode.op16() & 0x1fff,
|
|
decode(SNESSMP::Absolute, opcode.op16() & 0x1fff, pc)));
|
|
break;
|
|
|
|
case SNESSMP::Relative:
|
|
result.paramFormat = "%1X4";
|
|
result.params.append(DisassemblerParam::createAddress(decode(opcode.optype, opcode.op8(), pc),
|
|
decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::ADirectIndX:
|
|
result.paramFormat = "a, %1X2+x";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op8(),
|
|
directAddr, decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::AAbsoluteX:
|
|
result.paramFormat = "a, %1X4+x";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op16(),
|
|
absoluteAddr, decode(opcode.optype, opcode.op16(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::AAbsoluteY:
|
|
result.paramFormat = "a, %1X4+y";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op16(),
|
|
absoluteAddr, decode(opcode.optype, opcode.op16(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::AIDirectIndY:
|
|
result.paramFormat = "a, (%1X2)+y";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op8(),
|
|
directAddr, decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::XAbsolute:
|
|
result.paramFormat = "x, %1X4";
|
|
result.params.append(absoluteParam);
|
|
break;
|
|
|
|
case SNESSMP::IAbsoluteX:
|
|
result.paramFormat = "(%1X4+x)";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op16(),
|
|
absoluteAddr, decode(opcode.optype, opcode.op16(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::IDirectIndXA:
|
|
result.paramFormat = "(%1X2+x), a";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op8(),
|
|
directAddr, decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::IDirectIndYA:
|
|
result.paramFormat = "(%1X2)+y, a";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op8(),
|
|
directAddr, decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::XDirect:
|
|
result.paramFormat = "x, %1X2";
|
|
result.params.append(directParam);
|
|
break;
|
|
|
|
case SNESSMP::XDirectIndY:
|
|
result.paramFormat = "x, %1X2+y";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op8(),
|
|
directAddr, decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::XConstant:
|
|
result.paramFormat = "x, #%1X2";
|
|
result.params.append(DisassemblerParam::createValue(opcode.op8()));
|
|
break;
|
|
|
|
case SNESSMP::PVector:
|
|
result.paramFormat = "%1X4";
|
|
result.params.append(DisassemblerParam::createAddress(opcode.op8(),
|
|
decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::TVector:
|
|
result.paramFormat = string() << (opcode.op() >> 4);
|
|
break;
|
|
|
|
case SNESSMP::YaDirect:
|
|
result.paramFormat = "ya, %1X2";
|
|
result.params.append(directParam);
|
|
break;
|
|
|
|
case SNESSMP::YAbsolute:
|
|
result.paramFormat = "y, %1X4";
|
|
result.params.append(absoluteParam);
|
|
break;
|
|
|
|
case SNESSMP::YDirect:
|
|
result.paramFormat = "y, %1X2";
|
|
result.params.append(directParam);
|
|
break;
|
|
|
|
case SNESSMP::YConstant:
|
|
result.paramFormat = "y, #%1X2";
|
|
result.params.append(DisassemblerParam::createValue(opcode.op8()));
|
|
break;
|
|
|
|
case SNESSMP::YDirectIndX:
|
|
result.paramFormat = "y, %1X2+x";
|
|
result.params.append(DisassemblerParam::createTargetAddress(opcode.op8(),
|
|
directAddr, decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::YRelative:
|
|
result.paramFormat = "y, %1X4";
|
|
result.params.append(DisassemblerParam::createAddress(decode(opcode.optype, opcode.op8(), pc),
|
|
decode(opcode.optype, opcode.op8(), pc)));
|
|
break;
|
|
|
|
case SNESSMP::A:
|
|
result.paramFormat = "a";
|
|
break;
|
|
|
|
case SNESSMP::AX:
|
|
result.paramFormat = "a, x";
|
|
break;
|
|
|
|
case SNESSMP::AIX:
|
|
result.paramFormat = "a, (x)";
|
|
break;
|
|
|
|
case SNESSMP::P:
|
|
result.paramFormat = "p";
|
|
break;
|
|
|
|
case SNESSMP::IXIY:
|
|
result.paramFormat = "(x), (y)";
|
|
break;
|
|
|
|
case SNESSMP::X:
|
|
result.paramFormat = "x";
|
|
break;
|
|
|
|
case SNESSMP::XA:
|
|
result.paramFormat = "x, a";
|
|
break;
|
|
|
|
case SNESSMP::XSp:
|
|
result.paramFormat = "x, sp";
|
|
break;
|
|
|
|
case SNESSMP::Y:
|
|
result.paramFormat = "y";
|
|
break;
|
|
|
|
case SNESSMP::YaX:
|
|
result.paramFormat = "ya, x";
|
|
break;
|
|
|
|
case SNESSMP::IXPA:
|
|
result.paramFormat = "(x)+, a";
|
|
break;
|
|
|
|
case SNESSMP::SpX:
|
|
result.paramFormat = "sp, x";
|
|
break;
|
|
|
|
case SNESSMP::AIXP:
|
|
result.paramFormat = "a, (x)+";
|
|
break;
|
|
|
|
case SNESSMP::IXA:
|
|
result.paramFormat = "(x), a";
|
|
break;
|
|
|
|
case SNESSMP::Ya:
|
|
result.paramFormat = "ya";
|
|
break;
|
|
|
|
case SNESSMP::AY:
|
|
result.paramFormat = "a, y";
|
|
break;
|
|
|
|
case SNESSMP::YA:
|
|
result.paramFormat = "y, a";
|
|
break;
|
|
|
|
default: result.paramFormat = "???"; break;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
bool SmpDisasmProcessor::getLine(DisassemblerLine &result, uint32_t &address) {
|
|
SNES::SMP::Opcode opcode;
|
|
|
|
SNES::smp.disassemble_opcode_ex(opcode, address);
|
|
|
|
result.setOpcode(address, opcode.opcode);
|
|
setOpcodeParams(result, opcode, address);
|
|
|
|
if (opcode.isBra() || opcode.isBraWithContinue()) {
|
|
if (opcode.optype == SNESSMP::DirectRelative ||
|
|
opcode.optype == SNESSMP::DirectIndXRelative) {
|
|
result.setBra(decode(opcode.optype, opcode.op8(1), address));
|
|
} else {
|
|
result.setBra(decode(opcode.optype, opcode.opall(), address));
|
|
}
|
|
}
|
|
if (opcode.returns()) {
|
|
result.flags |= DisassemblerLine::FLAG_RETURN;
|
|
}
|
|
|
|
// Advance to next
|
|
if ((SNES::smp.usage[(address + opcode.size()) & 0xFFFF] & SNES::SMPDebugger::UsageOpcode) != 0) {
|
|
address += opcode.size();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
void SmpDisasmProcessor::findKnownRange(uint32_t currentAddress, uint32_t &startAddress, uint32_t &endAddress, uint32_t ¤tAddressLine, uint32_t &numLines) {
|
|
bool result;
|
|
unsigned line, i;
|
|
|
|
startAddress = currentAddress;
|
|
endAddress = currentAddress;
|
|
currentAddressLine = 0;
|
|
numLines = 1;
|
|
|
|
// Search upwards
|
|
for (line=0; line<MAX_LINES_PER_DIRECTION; line++) {
|
|
result = false;
|
|
|
|
for (i=1; i<=4; i++) {
|
|
if ((SNES::smp.usage[(startAddress - i) & 0xFFFF] & SNES::SMPDebugger::UsageOpcode) == 0) {
|
|
continue;
|
|
}
|
|
|
|
startAddress -= i;
|
|
numLines++;
|
|
currentAddressLine++;
|
|
result = true;
|
|
break;
|
|
}
|
|
|
|
if (!result) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Search downwards
|
|
for (line=0; line<MAX_LINES_PER_DIRECTION; line++) {
|
|
result = false;
|
|
|
|
for (i=1; i<=4; i++) {
|
|
if ((SNES::smp.usage[(endAddress + i) & 0xFFFF] & SNES::SMPDebugger::UsageOpcode) == 0) {
|
|
continue;
|
|
}
|
|
|
|
endAddress += i;
|
|
numLines++;
|
|
result = true;
|
|
break;
|
|
}
|
|
|
|
if (!result) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
uint8_t SmpDisasmProcessor::usage(uint32_t address) {
|
|
return SNES::smp.usage[address & 0xFFFF];
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
uint8_t SmpDisasmProcessor::read(uint32_t address) {
|
|
if (SNES::cartridge.loaded()) {
|
|
SNES::debugger.bus_access = true;
|
|
uint8_t data = SNES::debugger.read(SNES::Debugger::MemorySource::APUBus, address & 0xFFFF);
|
|
SNES::debugger.bus_access = false;
|
|
return data;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
void SmpDisasmProcessor::write(uint32_t address, uint8_t data) {
|
|
if (SNES::cartridge.loaded()) {
|
|
SNES::debugger.bus_access = true;
|
|
SNES::debugger.write(SNES::Debugger::MemorySource::APUBus, address & 0xFFFF, data);
|
|
SNES::debugger.bus_access = false;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
uint32_t SmpDisasmProcessor::getBusSize() {
|
|
return 0x10000;
|
|
}
|