544 lines
8.6 KiB
C++
544 lines
8.6 KiB
C++
#include "stdafx.h"
|
|
#include "GsuDisUtils.h"
|
|
#include "DisassemblyInfo.h"
|
|
#include "LabelManager.h"
|
|
#include "EmuSettings.h"
|
|
#include "../Utilities/FastString.h"
|
|
#include "../Utilities/HexUtilities.h"
|
|
|
|
void GsuDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager,
|
|
EmuSettings* settings)
|
|
{
|
|
constexpr const char* registerNames[16] = {
|
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"
|
|
};
|
|
bool alt1 = (info.GetFlags() & 0x01) != 0;
|
|
bool alt2 = (info.GetFlags() & 0x02) != 0;
|
|
bool prefix = (info.GetFlags() & 0x10) != 0;
|
|
|
|
uint8_t opCode = info.GetOpCode();
|
|
|
|
FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly));
|
|
|
|
auto getJumpTarget = [&str, labelManager, memoryAddr, &info]()
|
|
{
|
|
uint32_t jmpTarget = memoryAddr + (int8_t)info.GetByteCode()[1] + 2;
|
|
AddressInfo address = {(int32_t)jmpTarget, SnesMemoryType::GsuMemory};
|
|
string label = labelManager->GetLabel(address);
|
|
if (label.empty())
|
|
{
|
|
str.WriteAll('$', HexUtilities::ToHex24(jmpTarget));
|
|
}
|
|
else
|
|
{
|
|
str.Write(label, true);
|
|
}
|
|
};
|
|
|
|
const char* reg = registerNames[opCode & 0x0F];
|
|
|
|
switch (opCode)
|
|
{
|
|
case 0x00: str.Write("STOP");
|
|
break;
|
|
case 0x01: str.Write("NOP");
|
|
break;
|
|
case 0x02: str.Write("CACHE");
|
|
break;
|
|
case 0x03: str.Write("LSR");
|
|
break;
|
|
case 0x04: str.Write("ROL");
|
|
break;
|
|
|
|
case 0x05: str.WriteAll("BRA ");
|
|
getJumpTarget();
|
|
break;
|
|
case 0x06: str.WriteAll("BLT ");
|
|
getJumpTarget();
|
|
break;
|
|
case 0x07: str.WriteAll("BGE ");
|
|
getJumpTarget();
|
|
break;
|
|
case 0x08: str.WriteAll("BNE ");
|
|
getJumpTarget();
|
|
break;
|
|
case 0x09: str.WriteAll("BEQ ");
|
|
getJumpTarget();
|
|
break;
|
|
case 0x0A: str.WriteAll("BPL ");
|
|
getJumpTarget();
|
|
break;
|
|
case 0x0B: str.WriteAll("BMI ");
|
|
getJumpTarget();
|
|
break;
|
|
case 0x0C: str.WriteAll("BCC ");
|
|
getJumpTarget();
|
|
break;
|
|
case 0x0D: str.WriteAll("BCS ");
|
|
getJumpTarget();
|
|
break;
|
|
case 0x0E: str.WriteAll("BCV ");
|
|
getJumpTarget();
|
|
break;
|
|
case 0x0F: str.WriteAll("BVS ");
|
|
getJumpTarget();
|
|
break;
|
|
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
case 0x14:
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0x17:
|
|
case 0x18:
|
|
case 0x19:
|
|
case 0x1A:
|
|
case 0x1B:
|
|
case 0x1C:
|
|
case 0x1D:
|
|
case 0x1E:
|
|
case 0x1F:
|
|
str.WriteAll(prefix ? "MOVE R" : "TO R", reg);
|
|
break;
|
|
|
|
case 0x20:
|
|
case 0x21:
|
|
case 0x22:
|
|
case 0x23:
|
|
case 0x24:
|
|
case 0x25:
|
|
case 0x26:
|
|
case 0x27:
|
|
case 0x28:
|
|
case 0x29:
|
|
case 0x2A:
|
|
case 0x2B:
|
|
case 0x2C:
|
|
case 0x2D:
|
|
case 0x2E:
|
|
case 0x2F:
|
|
str.WriteAll("WITH R", reg);
|
|
break;
|
|
|
|
case 0x30:
|
|
case 0x31:
|
|
case 0x32:
|
|
case 0x33:
|
|
case 0x34:
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37:
|
|
case 0x38:
|
|
case 0x39:
|
|
case 0x3A:
|
|
case 0x3B:
|
|
str.WriteAll(alt1 ? "STB (R" : "STW (R", reg, ')');
|
|
break;
|
|
|
|
case 0x3C: str.Write("LOOP");
|
|
break;
|
|
case 0x3D: str.Write("ALT1");
|
|
break;
|
|
case 0x3E: str.Write("ALT2");
|
|
break;
|
|
case 0x3F: str.Write("ALT3");
|
|
break;
|
|
|
|
case 0x40:
|
|
case 0x41:
|
|
case 0x42:
|
|
case 0x43:
|
|
case 0x44:
|
|
case 0x45:
|
|
case 0x46:
|
|
case 0x47:
|
|
case 0x48:
|
|
case 0x49:
|
|
case 0x4A:
|
|
case 0x4B:
|
|
str.WriteAll(alt1 ? "LDB (R" : "LDW (R", reg, ')');
|
|
break;
|
|
|
|
case 0x4C: str.Write(alt1 ? "RPIX" : "PLOT");
|
|
break;
|
|
|
|
case 0x4D: str.Write("SWAP");
|
|
break;
|
|
case 0x4E: str.Write(alt1 ? "CMODE" : "COLOR");
|
|
break;
|
|
|
|
case 0x4F: str.Write("NOT");
|
|
break;
|
|
|
|
case 0x50:
|
|
case 0x51:
|
|
case 0x52:
|
|
case 0x53:
|
|
case 0x54:
|
|
case 0x55:
|
|
case 0x56:
|
|
case 0x57:
|
|
case 0x58:
|
|
case 0x59:
|
|
case 0x5A:
|
|
case 0x5B:
|
|
case 0x5C:
|
|
case 0x5D:
|
|
case 0x5E:
|
|
case 0x5F:
|
|
str.Write(alt1 ? "ADC " : "ADD ");
|
|
str.WriteAll(alt2 ? '#' : 'R', reg);
|
|
break;
|
|
|
|
case 0x60:
|
|
case 0x61:
|
|
case 0x62:
|
|
case 0x63:
|
|
case 0x64:
|
|
case 0x65:
|
|
case 0x66:
|
|
case 0x67:
|
|
case 0x68:
|
|
case 0x69:
|
|
case 0x6A:
|
|
case 0x6B:
|
|
case 0x6C:
|
|
case 0x6D:
|
|
case 0x6E:
|
|
case 0x6F:
|
|
if (alt2 && alt1)
|
|
{
|
|
str.WriteAll("CMP R", reg);
|
|
}
|
|
else
|
|
{
|
|
if (!alt2 && alt1)
|
|
{
|
|
str.Write("SBC ");
|
|
}
|
|
else
|
|
{
|
|
str.Write("SUB ");
|
|
}
|
|
if (alt2 && !alt1)
|
|
{
|
|
str.WriteAll('#', reg);
|
|
}
|
|
else
|
|
{
|
|
str.WriteAll('R', reg);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x70: str.Write("MERGE");
|
|
break;
|
|
|
|
case 0x71:
|
|
case 0x72:
|
|
case 0x73:
|
|
case 0x74:
|
|
case 0x75:
|
|
case 0x76:
|
|
case 0x77:
|
|
case 0x78:
|
|
case 0x79:
|
|
case 0x7A:
|
|
case 0x7B:
|
|
case 0x7C:
|
|
case 0x7D:
|
|
case 0x7E:
|
|
case 0x7F:
|
|
str.Write(alt1 ? "BIC " : "AND ");
|
|
str.WriteAll(alt2 ? '#' : 'R', reg);
|
|
break;
|
|
|
|
case 0x80:
|
|
case 0x81:
|
|
case 0x82:
|
|
case 0x83:
|
|
case 0x84:
|
|
case 0x85:
|
|
case 0x86:
|
|
case 0x87:
|
|
case 0x88:
|
|
case 0x89:
|
|
case 0x8A:
|
|
case 0x8B:
|
|
case 0x8C:
|
|
case 0x8D:
|
|
case 0x8E:
|
|
case 0x8F:
|
|
str.Write(alt1 ? "UMULT " : "MULT ");
|
|
str.WriteAll(alt2 ? '#' : 'R', reg);
|
|
break;
|
|
|
|
case 0x90: str.Write("SBK");
|
|
break;
|
|
|
|
case 0x91:
|
|
case 0x92:
|
|
case 0x93:
|
|
case 0x94:
|
|
str.WriteAll("LINK #", reg);
|
|
break;
|
|
|
|
case 0x95: str.Write("SEX");
|
|
break;
|
|
|
|
case 0x96: str.Write(alt1 ? "DIV2" : "ASR");
|
|
break;
|
|
case 0x97: str.Write("ROR");
|
|
break;
|
|
|
|
case 0x98:
|
|
case 0x99:
|
|
case 0x9A:
|
|
case 0x9B:
|
|
case 0x9C:
|
|
case 0x9D:
|
|
str.WriteAll(alt1 ? "LJMP R" : "JMP R", reg);
|
|
break;
|
|
|
|
case 0x9E: str.Write("LOB");
|
|
break;
|
|
case 0x9F: str.Write(alt1 ? "LMULT" : "FMULT");
|
|
break;
|
|
|
|
case 0xA0:
|
|
case 0xA1:
|
|
case 0xA2:
|
|
case 0xA3:
|
|
case 0xA4:
|
|
case 0xA5:
|
|
case 0xA6:
|
|
case 0xA7:
|
|
case 0xA8:
|
|
case 0xA9:
|
|
case 0xAA:
|
|
case 0xAB:
|
|
case 0xAC:
|
|
case 0xAD:
|
|
case 0xAE:
|
|
case 0xAF:
|
|
if (alt1)
|
|
{
|
|
str.WriteAll("LMS R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[1] << 1), ')');
|
|
}
|
|
else if (alt2)
|
|
{
|
|
str.WriteAll("SMS R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[1] << 1), ')');
|
|
}
|
|
else
|
|
{
|
|
str.WriteAll("IBT R", reg, ",#$", HexUtilities::ToHex(info.GetByteCode()[1]));
|
|
}
|
|
break;
|
|
|
|
case 0xB0:
|
|
case 0xB1:
|
|
case 0xB2:
|
|
case 0xB3:
|
|
case 0xB4:
|
|
case 0xB5:
|
|
case 0xB6:
|
|
case 0xB7:
|
|
case 0xB8:
|
|
case 0xB9:
|
|
case 0xBA:
|
|
case 0xBB:
|
|
case 0xBC:
|
|
case 0xBD:
|
|
case 0xBE:
|
|
case 0xBF:
|
|
str.WriteAll(prefix ? "MOVES R" : "FROM R", reg);
|
|
break;
|
|
|
|
case 0xC0: str.Write("HIB");
|
|
break;
|
|
|
|
case 0xC1:
|
|
case 0xC2:
|
|
case 0xC3:
|
|
case 0xC4:
|
|
case 0xC5:
|
|
case 0xC6:
|
|
case 0xC7:
|
|
case 0xC8:
|
|
case 0xC9:
|
|
case 0xCA:
|
|
case 0xCB:
|
|
case 0xCC:
|
|
case 0xCD:
|
|
case 0xCE:
|
|
case 0xCF:
|
|
str.Write(alt1 ? "XOR " : "OR ");
|
|
str.WriteAll(alt2 ? '#' : 'R', reg);
|
|
break;
|
|
|
|
case 0xD0:
|
|
case 0xD1:
|
|
case 0xD2:
|
|
case 0xD3:
|
|
case 0xD4:
|
|
case 0xD5:
|
|
case 0xD6:
|
|
case 0xD7:
|
|
case 0xD8:
|
|
case 0xD9:
|
|
case 0xDA:
|
|
case 0xDB:
|
|
case 0xDC:
|
|
case 0xDD:
|
|
case 0xDE:
|
|
str.WriteAll("INC R", reg);
|
|
break;
|
|
|
|
case 0xDF:
|
|
if (!alt2)
|
|
{
|
|
//GETC - "Get byte from ROM to color register"
|
|
str.Write("GETC");
|
|
}
|
|
else if (!alt1)
|
|
{
|
|
//RAMB - "Set RAM data bank"
|
|
str.Write("RAMB");
|
|
}
|
|
else
|
|
{
|
|
str.Write("ROMB");
|
|
}
|
|
break;
|
|
|
|
case 0xE0:
|
|
case 0xE1:
|
|
case 0xE2:
|
|
case 0xE3:
|
|
case 0xE4:
|
|
case 0xE5:
|
|
case 0xE6:
|
|
case 0xE7:
|
|
case 0xE8:
|
|
case 0xE9:
|
|
case 0xEA:
|
|
case 0xEB:
|
|
case 0xEC:
|
|
case 0xED:
|
|
case 0xEE:
|
|
str.WriteAll("DEC R", reg);
|
|
break;
|
|
|
|
case 0xEF:
|
|
if (alt2 && alt1)
|
|
{
|
|
str.Write("GETBS");
|
|
}
|
|
else if (alt2)
|
|
{
|
|
str.Write("GETBL");
|
|
}
|
|
else if (alt1)
|
|
{
|
|
str.Write("GETBH");
|
|
}
|
|
else
|
|
{
|
|
str.Write("GETB");
|
|
}
|
|
break;
|
|
|
|
case 0xF0:
|
|
case 0xF1:
|
|
case 0xF2:
|
|
case 0xF3:
|
|
case 0xF4:
|
|
case 0xF5:
|
|
case 0xF6:
|
|
case 0xF7:
|
|
case 0xF8:
|
|
case 0xF9:
|
|
case 0xFA:
|
|
case 0xFB:
|
|
case 0xFC:
|
|
case 0xFD:
|
|
case 0xFE:
|
|
case 0xFF:
|
|
if (alt1)
|
|
{
|
|
str.WriteAll("LM R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[2]),
|
|
HexUtilities::ToHex(info.GetByteCode()[1]), ')');
|
|
}
|
|
else if (alt2)
|
|
{
|
|
str.WriteAll("SM R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[2]),
|
|
HexUtilities::ToHex(info.GetByteCode()[1]), ')');
|
|
}
|
|
else
|
|
{
|
|
str.WriteAll("IWT R", reg, ",#$", HexUtilities::ToHex(info.GetByteCode()[2]),
|
|
HexUtilities::ToHex(info.GetByteCode()[1]));
|
|
}
|
|
break;
|
|
}
|
|
|
|
out += str.ToString();
|
|
}
|
|
|
|
int32_t GsuDisUtils::GetEffectiveAddress(DisassemblyInfo& info, Console* console, GsuState& state)
|
|
{
|
|
uint8_t opCode = info.GetOpCode();
|
|
bool alt1 = (info.GetFlags() & 0x01) != 0;
|
|
bool alt2 = (info.GetFlags() & 0x02) != 0;
|
|
|
|
switch (opCode)
|
|
{
|
|
case 0xA0:
|
|
case 0xA1:
|
|
case 0xA2:
|
|
case 0xA3:
|
|
case 0xA4:
|
|
case 0xA5:
|
|
case 0xA6:
|
|
case 0xA7:
|
|
case 0xA8:
|
|
case 0xA9:
|
|
case 0xAA:
|
|
case 0xAB:
|
|
case 0xAC:
|
|
case 0xAD:
|
|
case 0xAE:
|
|
case 0xAF:
|
|
if (alt1 || alt2)
|
|
{
|
|
return 0x700000 | (info.GetByteCode()[1] << 1) | (state.RamBank << 16);
|
|
}
|
|
break;
|
|
|
|
case 0xF0:
|
|
case 0xF1:
|
|
case 0xF2:
|
|
case 0xF3:
|
|
case 0xF4:
|
|
case 0xF5:
|
|
case 0xF6:
|
|
case 0xF7:
|
|
case 0xF8:
|
|
case 0xF9:
|
|
case 0xFA:
|
|
case 0xFB:
|
|
case 0xFC:
|
|
case 0xFD:
|
|
case 0xFE:
|
|
case 0xFF:
|
|
if (alt1 || alt2)
|
|
{
|
|
return 0x700000 | info.GetByteCode()[1] | (info.GetByteCode()[2] << 8) | (state.RamBank << 16);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return -1;
|
|
}
|