mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-04-24 22:34:54 +00:00
Merge bcefc8ba70
into 879a8889aa
This commit is contained in:
commit
90b78d8aa7
23 changed files with 362 additions and 88 deletions
|
@ -681,6 +681,7 @@ void GekkoIRPlugin::EvalTerminalRel(Terminal type, const AssemblerToken& tok)
|
||||||
case Terminal::Bin:
|
case Terminal::Bin:
|
||||||
case Terminal::GPR:
|
case Terminal::GPR:
|
||||||
case Terminal::FPR:
|
case Terminal::FPR:
|
||||||
|
case Terminal::GQR:
|
||||||
case Terminal::SPR:
|
case Terminal::SPR:
|
||||||
case Terminal::CRField:
|
case Terminal::CRField:
|
||||||
case Terminal::Lt:
|
case Terminal::Lt:
|
||||||
|
@ -732,6 +733,7 @@ void GekkoIRPlugin::EvalTerminalAbs(Terminal type, const AssemblerToken& tok)
|
||||||
case Terminal::Bin:
|
case Terminal::Bin:
|
||||||
case Terminal::GPR:
|
case Terminal::GPR:
|
||||||
case Terminal::FPR:
|
case Terminal::FPR:
|
||||||
|
case Terminal::GQR:
|
||||||
case Terminal::SPR:
|
case Terminal::SPR:
|
||||||
case Terminal::CRField:
|
case Terminal::CRField:
|
||||||
case Terminal::Lt:
|
case Terminal::Lt:
|
||||||
|
|
|
@ -187,12 +187,14 @@ std::optional<T> EvalIntegral(TokenType tp, std::string_view val)
|
||||||
if (CaseInsensitiveEquals(val, "rtoc"))
|
if (CaseInsensitiveEquals(val, "rtoc"))
|
||||||
return T{2};
|
return T{2};
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case TokenType::FPR:
|
case TokenType::FPR: // BE CAREFUL WHAT YOU PUT IN BETWEEN fallthrough and FPR
|
||||||
return std::accumulate(val.begin() + 1, val.end(), T{0}, dec_step);
|
return std::accumulate(val.begin() + 1, val.end(), T{0}, dec_step);
|
||||||
case TokenType::CRField:
|
case TokenType::CRField:
|
||||||
return std::accumulate(val.begin() + 2, val.end(), T{0}, dec_step);
|
return std::accumulate(val.begin() + 2, val.end(), T{0}, dec_step);
|
||||||
case TokenType::SPR:
|
case TokenType::SPR:
|
||||||
return static_cast<T>(*sprg_map.Find(val));
|
return static_cast<T>(*sprg_map.Find(val));
|
||||||
|
case TokenType::GQR:
|
||||||
|
return std::accumulate(val.begin() + 2, val.end(), T{0}, dec_step);
|
||||||
case TokenType::Lt:
|
case TokenType::Lt:
|
||||||
return T{0};
|
return T{0};
|
||||||
case TokenType::Gt:
|
case TokenType::Gt:
|
||||||
|
@ -220,6 +222,8 @@ std::string_view TokenTypeToStr(TokenType tp)
|
||||||
return "GPR";
|
return "GPR";
|
||||||
case TokenType::FPR:
|
case TokenType::FPR:
|
||||||
return "FPR";
|
return "FPR";
|
||||||
|
case TokenType::GQR:
|
||||||
|
return "GQR";
|
||||||
case TokenType::SPR:
|
case TokenType::SPR:
|
||||||
return "SPR";
|
return "SPR";
|
||||||
case TokenType::CRField:
|
case TokenType::CRField:
|
||||||
|
@ -668,6 +672,15 @@ TokenType Lexer::ClassifyAlnum() const
|
||||||
{
|
{
|
||||||
return TokenType::FPR;
|
return TokenType::FPR;
|
||||||
}
|
}
|
||||||
|
else if (std::tolower(alnum[0]) == 'p' && valid_regnum(alnum.substr(1)))
|
||||||
|
{
|
||||||
|
return TokenType::FPR;
|
||||||
|
}
|
||||||
|
else if (alnum.length() == 3 && CaseInsensitiveEquals(alnum.substr(0, 2), "qr") &&
|
||||||
|
alnum[2] >= '0' && alnum[2] <= '7')
|
||||||
|
{
|
||||||
|
return TokenType::GQR;
|
||||||
|
}
|
||||||
else if (alnum.length() == 3 && CaseInsensitiveEquals(alnum.substr(0, 2), "cr") &&
|
else if (alnum.length() == 3 && CaseInsensitiveEquals(alnum.substr(0, 2), "cr") &&
|
||||||
alnum[2] >= '0' && alnum[2] <= '7')
|
alnum[2] >= '0' && alnum[2] <= '7')
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,6 +31,7 @@ enum class TokenType
|
||||||
FloatLit,
|
FloatLit,
|
||||||
GPR,
|
GPR,
|
||||||
FPR,
|
FPR,
|
||||||
|
GQR,
|
||||||
CRField,
|
CRField,
|
||||||
SPR,
|
SPR,
|
||||||
Lt,
|
Lt,
|
||||||
|
|
|
@ -127,6 +127,9 @@ void ParsePpcBuiltin(ParseState* state)
|
||||||
case TokenType::FPR:
|
case TokenType::FPR:
|
||||||
state->plugin.OnTerminal(Terminal::FPR, tok);
|
state->plugin.OnTerminal(Terminal::FPR, tok);
|
||||||
break;
|
break;
|
||||||
|
case TokenType::GQR:
|
||||||
|
state->plugin.OnTerminal(Terminal::GQR, tok);
|
||||||
|
break;
|
||||||
case TokenType::SPR:
|
case TokenType::SPR:
|
||||||
state->plugin.OnTerminal(Terminal::SPR, tok);
|
state->plugin.OnTerminal(Terminal::SPR, tok);
|
||||||
break;
|
break;
|
||||||
|
@ -176,6 +179,7 @@ void ParseBaseexpr(ParseState* state)
|
||||||
case TokenType::GPR:
|
case TokenType::GPR:
|
||||||
case TokenType::FPR:
|
case TokenType::FPR:
|
||||||
case TokenType::SPR:
|
case TokenType::SPR:
|
||||||
|
case TokenType::GQR:
|
||||||
case TokenType::CRField:
|
case TokenType::CRField:
|
||||||
case TokenType::Lt:
|
case TokenType::Lt:
|
||||||
case TokenType::Gt:
|
case TokenType::Gt:
|
||||||
|
|
|
@ -56,6 +56,7 @@ enum class Terminal
|
||||||
Id,
|
Id,
|
||||||
GPR,
|
GPR,
|
||||||
FPR,
|
FPR,
|
||||||
|
GQR,
|
||||||
SPR,
|
SPR,
|
||||||
CRField,
|
CRField,
|
||||||
Lt,
|
Lt,
|
||||||
|
|
|
@ -449,7 +449,7 @@ void GekkoDisassembler::trapi(u32 in, unsigned char dmode)
|
||||||
|
|
||||||
if (cnd != nullptr)
|
if (cnd != nullptr)
|
||||||
{
|
{
|
||||||
m_opcode = fmt::format("t{}{}", dmode ? 'd' : 'w', cnd);
|
m_opcode = fmt::format("t{}{}i", dmode ? 'd' : 'w', cnd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -512,8 +512,8 @@ size_t GekkoDisassembler::branch(u32 in, std::string_view bname, int aform, int
|
||||||
char y = (char)(bo & 1);
|
char y = (char)(bo & 1);
|
||||||
const char* ext = b_ext[aform * 2 + (int)(in & 1)];
|
const char* ext = b_ext[aform * 2 + (int)(in & 1)];
|
||||||
|
|
||||||
if (bdisp < 0)
|
/* if (bdisp < 0)
|
||||||
y ^= 1;
|
y ^= 1; */
|
||||||
y = (y != 0) ? '+' : '-';
|
y = (y != 0) ? '+' : '-';
|
||||||
|
|
||||||
if (bo & 4)
|
if (bo & 4)
|
||||||
|
@ -631,7 +631,7 @@ void GekkoDisassembler::nooper(u32 in, std::string_view name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GekkoDisassembler::rlw(u32 in, std::string_view name, int i)
|
void GekkoDisassembler::rlw(u32 in, std::string_view name, int i, bool for_assemble)
|
||||||
{
|
{
|
||||||
int s = (int)PPCGETD(in);
|
int s = (int)PPCGETD(in);
|
||||||
int a = (int)PPCGETA(in);
|
int a = (int)PPCGETA(in);
|
||||||
|
@ -640,8 +640,16 @@ void GekkoDisassembler::rlw(u32 in, std::string_view name, int i)
|
||||||
int me = (int)PPCGETM(in);
|
int me = (int)PPCGETM(in);
|
||||||
|
|
||||||
m_opcode = fmt::format("rlw{}{}", name, (in & 1) ? "." : "");
|
m_opcode = fmt::format("rlw{}{}", name, (in & 1) ? "." : "");
|
||||||
m_operands = fmt::format("{}, {}, {}{}, {}, {} ({:08x})", regnames[a], regnames[s], regsel[i],
|
if (!for_assemble)
|
||||||
bsh, mb, me, HelperRotateMask(bsh, mb, me));
|
{
|
||||||
|
m_operands = fmt::format("{}, {}, {}{}, {}, {} ({:08x})", regnames[a], regnames[s], regsel[i],
|
||||||
|
bsh, mb, me, HelperRotateMask(bsh, mb, me));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands =
|
||||||
|
fmt::format("{}, {}, {}{}, {}, {}", regnames[a], regnames[s], regsel[i], bsh, mb, me);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GekkoDisassembler::ori(u32 in, std::string_view name)
|
void GekkoDisassembler::ori(u32 in, std::string_view name)
|
||||||
|
@ -1019,7 +1027,7 @@ void GekkoDisassembler::mtfsb(u32 in, int n)
|
||||||
#define IX ((inst >> 7) & 0x7)
|
#define IX ((inst >> 7) & 0x7)
|
||||||
#define WX ((inst >> 10) & 0x1)
|
#define WX ((inst >> 10) & 0x1)
|
||||||
|
|
||||||
void GekkoDisassembler::ps(u32 inst)
|
void GekkoDisassembler::ps(u32 inst, bool for_assemble)
|
||||||
{
|
{
|
||||||
switch ((inst >> 1) & 0x1F)
|
switch ((inst >> 1) & 0x1F)
|
||||||
{
|
{
|
||||||
|
@ -1034,88 +1042,200 @@ void GekkoDisassembler::ps(u32 inst)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 18:
|
case 18:
|
||||||
m_opcode = "ps_div";
|
m_opcode = fmt::format("ps_div{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}/p{}", FD, FA, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}/p{}", FD, FA, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 20:
|
case 20:
|
||||||
m_opcode = "ps_sub";
|
m_opcode = fmt::format("ps_sub{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}-p{}", FD, FA, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}-p{}", FD, FA, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 21:
|
case 21:
|
||||||
m_opcode = "ps_add";
|
m_opcode = fmt::format("ps_add{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}+p{}", FD, FA, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}+p{}", FD, FA, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 23:
|
case 23:
|
||||||
m_opcode = "ps_sel";
|
m_opcode = fmt::format("ps_sel{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}>=0?p{}:p{}", FD, FA, FC);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}>=0?p{}:p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 24:
|
case 24:
|
||||||
m_opcode = "ps_res";
|
m_opcode = fmt::format("ps_res{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, (1/p{})", FD, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, (1/p{})", FD, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}", FD, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 25:
|
case 25:
|
||||||
m_opcode = "ps_mul";
|
m_opcode = fmt::format("ps_mul{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}*p{}", FD, FA, FC);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}*p{}", FD, FA, FC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FC);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 26: // rsqrte
|
case 26: // rsqrte
|
||||||
m_opcode = "ps_rsqrte";
|
m_opcode = fmt::format("ps_rsqrte{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}", FD, FB);
|
m_operands = fmt::format("p{}, p{}", FD, FB);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 28: // msub
|
case 28: // msub
|
||||||
m_opcode = "ps_msub";
|
m_opcode = fmt::format("ps_msub{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}*p{}-p{}", FD, FA, FC, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}*p{}-p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 29: // madd
|
case 29: // madd
|
||||||
m_opcode = "ps_madd";
|
m_opcode = fmt::format("ps_madd{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}*p{}+p{}", FD, FA, FC, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}*p{}+p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 30: // nmsub
|
case 30: // nmsub
|
||||||
m_opcode = "ps_nmsub";
|
m_opcode = fmt::format("ps_nmsub{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, -(p{}*p{}-p{})", FD, FA, FC, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, -(p{}*p{}-p{})", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 31: // nmadd
|
case 31: // nmadd
|
||||||
m_opcode = "ps_nmadd";
|
m_opcode = fmt::format("ps_nmadd{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, -(p{}*p{}+p{})", FD, FA, FC, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, -(p{}*p{}+p{})", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 10:
|
case 10:
|
||||||
m_opcode = "ps_sum0";
|
m_opcode = fmt::format("ps_sum0{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, 0=p{}+p{}, 1=p{}", FD, FA, FB, FC);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, 0=p{}+p{}, 1=p{}", FD, FA, FB, FC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 11:
|
case 11:
|
||||||
m_opcode = "ps_sum1";
|
m_opcode = fmt::format("ps_sum1{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, 0=p{}, 1=p{}+p{}", FD, FC, FA, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, 0=p{}, 1=p{}+p{}", FD, FC, FA, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 12:
|
case 12:
|
||||||
m_opcode = "ps_muls0";
|
m_opcode = fmt::format("ps_muls0{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}*p{}[0]", FD, FA, FC);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}*p{}[0]", FD, FA, FC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FC);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 13:
|
case 13:
|
||||||
m_opcode = "ps_muls1";
|
m_opcode = fmt::format("ps_muls1{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}*p{}[1]", FD, FA, FC);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}*p{}[1]", FD, FA, FC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FC);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 14:
|
case 14:
|
||||||
m_opcode = "ps_madds0";
|
m_opcode = fmt::format("ps_madds0{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}*p{}[0]+p{}", FD, FA, FC, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}*p{}[0]+p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 15:
|
case 15:
|
||||||
m_opcode = "ps_madds1";
|
m_opcode = fmt::format("ps_madds1{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}*p{}[1]+p{}", FD, FA, FC, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}*p{}[1]+p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1123,23 +1243,44 @@ void GekkoDisassembler::ps(u32 inst)
|
||||||
{
|
{
|
||||||
// 10-bit suckers (?)
|
// 10-bit suckers (?)
|
||||||
case 40: // nmadd
|
case 40: // nmadd
|
||||||
m_opcode = "ps_neg";
|
m_opcode = fmt::format("ps_neg{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, -p{}", FD, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, -p{}", FD, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}", FD, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 72: // nmadd
|
case 72: // nmadd
|
||||||
m_opcode = "ps_mr";
|
m_opcode = fmt::format("ps_mr{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}", FD, FB);
|
m_operands = fmt::format("p{}, p{}", FD, FB);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 136:
|
case 136:
|
||||||
m_opcode = "ps_nabs";
|
m_opcode = fmt::format("ps_nabs{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, -|p{}|", FD, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, -|p{}|", FD, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}", FD, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 264:
|
case 264:
|
||||||
m_opcode = "ps_abs";
|
m_opcode = fmt::format("ps_abs{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, |p{}|", FD, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, |p{}|", FD, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}", FD, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -1156,23 +1297,51 @@ void GekkoDisassembler::ps(u32 inst)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 528:
|
case 528:
|
||||||
m_opcode = "ps_merge00";
|
m_opcode = fmt::format("ps_merge00{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}[0], p{}[0]", FD, FA, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}[0], p{}[0]", FD, FA, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 560:
|
case 560:
|
||||||
m_opcode = "ps_merge01";
|
m_opcode = fmt::format("ps_merge01{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}[0], p{}[1]", FD, FA, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}[0], p{}[1]", FD, FA, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 592:
|
case 592:
|
||||||
m_opcode = "ps_merge10";
|
m_opcode = fmt::format("ps_merge10{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}[1], p{}[0]", FD, FA, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}[1], p{}[0]", FD, FA, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 624:
|
case 624:
|
||||||
m_opcode = "ps_merge11";
|
m_opcode = fmt::format("ps_merge11{}", rcsel[inst & 1]);
|
||||||
m_operands = fmt::format("p{}, p{}[1], p{}[1]", FD, FA, FB);
|
if (!for_assemble)
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}[1], p{}[1]", FD, FA, FB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 1014:
|
case 1014:
|
||||||
|
@ -1217,7 +1386,7 @@ void GekkoDisassembler::ps_mem(u32 inst)
|
||||||
|
|
||||||
// Disassemble PPC instruction and return a pointer to the next
|
// Disassemble PPC instruction and return a pointer to the next
|
||||||
// instruction, or nullptr if an error occurred.
|
// instruction, or nullptr if an error occurred.
|
||||||
u32* GekkoDisassembler::DoDisassembly(bool big_endian)
|
u32* GekkoDisassembler::DoDisassembly(bool for_assemble, bool big_endian)
|
||||||
{
|
{
|
||||||
u32 in = *m_instr;
|
u32 in = *m_instr;
|
||||||
|
|
||||||
|
@ -1240,7 +1409,7 @@ u32* GekkoDisassembler::DoDisassembly(bool big_endian)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
ps(in);
|
ps(in, for_assemble);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 56:
|
case 56:
|
||||||
|
@ -1361,15 +1530,15 @@ u32* GekkoDisassembler::DoDisassembly(bool big_endian)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 20:
|
case 20:
|
||||||
rlw(in, "imi", 0); // rlwimi
|
rlw(in, "imi", 0, for_assemble); // rlwimi
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 21:
|
case 21:
|
||||||
rlw(in, "inm", 0); // rlwinm
|
rlw(in, "inm", 0, for_assemble); // rlwinm
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 23:
|
case 23:
|
||||||
rlw(in, "nm", 1); // rlwnm
|
rlw(in, "nm", 1, for_assemble); // rlwnm
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 24:
|
case 24:
|
||||||
|
@ -2275,7 +2444,7 @@ u32* GekkoDisassembler::DoDisassembly(bool big_endian)
|
||||||
|
|
||||||
// simplified interface
|
// simplified interface
|
||||||
std::string GekkoDisassembler::Disassemble(u32 opcode, u32 current_instruction_address,
|
std::string GekkoDisassembler::Disassemble(u32 opcode, u32 current_instruction_address,
|
||||||
bool big_endian)
|
bool for_assemble, bool big_endian)
|
||||||
{
|
{
|
||||||
u32 opc = opcode;
|
u32 opc = opcode;
|
||||||
u32 addr = current_instruction_address;
|
u32 addr = current_instruction_address;
|
||||||
|
@ -2283,7 +2452,7 @@ std::string GekkoDisassembler::Disassemble(u32 opcode, u32 current_instruction_a
|
||||||
m_instr = (u32*)&opc;
|
m_instr = (u32*)&opc;
|
||||||
m_iaddr = (u32*)&addr;
|
m_iaddr = (u32*)&addr;
|
||||||
|
|
||||||
DoDisassembly(big_endian);
|
DoDisassembly(for_assemble, big_endian);
|
||||||
|
|
||||||
return m_opcode.append("\t").append(m_operands);
|
return m_opcode.append("\t").append(m_operands);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace Common
|
||||||
class GekkoDisassembler final
|
class GekkoDisassembler final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::string Disassemble(u32 opcode, u32 current_instruction_address,
|
static std::string Disassemble(u32 opcode, u32 current_instruction_address, bool for_assemble,
|
||||||
bool big_endian = true);
|
bool big_endian = true);
|
||||||
static const char* GetGPRName(u32 index);
|
static const char* GetGPRName(u32 index);
|
||||||
static const char* GetFPRName(u32 index);
|
static const char* GetFPRName(u32 index);
|
||||||
|
@ -67,7 +67,7 @@ private:
|
||||||
static void mcrf(u32 in, std::string_view suffix);
|
static void mcrf(u32 in, std::string_view suffix);
|
||||||
static void crop(u32 in, std::string_view n1, std::string_view n2);
|
static void crop(u32 in, std::string_view n1, std::string_view n2);
|
||||||
static void nooper(u32 in, std::string_view name);
|
static void nooper(u32 in, std::string_view name);
|
||||||
static void rlw(u32 in, std::string_view name, int i);
|
static void rlw(u32 in, std::string_view name, int i, bool for_assemble);
|
||||||
static void ori(u32 in, std::string_view name);
|
static void ori(u32 in, std::string_view name);
|
||||||
static void rld(u32 in, std::string_view name, int i);
|
static void rld(u32 in, std::string_view name, int i);
|
||||||
static void cmp(u32 in);
|
static void cmp(u32 in);
|
||||||
|
@ -85,10 +85,10 @@ private:
|
||||||
static void fdab(u32 in, std::string_view name);
|
static void fdab(u32 in, std::string_view name);
|
||||||
static void fcmp(u32 in, char c);
|
static void fcmp(u32 in, char c);
|
||||||
static void mtfsb(u32 in, int n);
|
static void mtfsb(u32 in, int n);
|
||||||
static void ps(u32 inst);
|
static void ps(u32 inst, bool for_assemble);
|
||||||
static void ps_mem(u32 inst);
|
static void ps_mem(u32 inst);
|
||||||
|
|
||||||
static u32* DoDisassembly(bool big_endian);
|
static u32* DoDisassembly(bool for_assemble, bool big_endian);
|
||||||
|
|
||||||
enum Flags
|
enum Flags
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,7 +62,8 @@ public:
|
||||||
// Threads
|
// Threads
|
||||||
virtual Common::Debug::Threads GetThreads(const CPUThreadGuard& guard) const = 0;
|
virtual Common::Debug::Threads GetThreads(const CPUThreadGuard& guard) const = 0;
|
||||||
|
|
||||||
virtual std::string Disassemble(const CPUThreadGuard* /*guard*/, u32 /*address*/) const
|
virtual std::string Disassemble(const CPUThreadGuard* /*guard*/, u32 /*address*/,
|
||||||
|
bool /*for_assemble*/) const
|
||||||
{
|
{
|
||||||
return "NODEBUGGER";
|
return "NODEBUGGER";
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,7 +276,8 @@ Common::Debug::Threads PPCDebugInterface::GetThreads(const Core::CPUThreadGuard&
|
||||||
return threads;
|
return threads;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PPCDebugInterface::Disassemble(const Core::CPUThreadGuard* guard, u32 address) const
|
std::string PPCDebugInterface::Disassemble(const Core::CPUThreadGuard* guard, u32 address,
|
||||||
|
bool for_assemble) const
|
||||||
{
|
{
|
||||||
if (guard)
|
if (guard)
|
||||||
{
|
{
|
||||||
|
@ -286,7 +287,7 @@ std::string PPCDebugInterface::Disassemble(const Core::CPUThreadGuard* guard, u3
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 op = PowerPC::MMU::HostRead_Instruction(*guard, address);
|
const u32 op = PowerPC::MMU::HostRead_Instruction(*guard, address);
|
||||||
std::string disasm = Common::GekkoDisassembler::Disassemble(op, address);
|
std::string disasm = Common::GekkoDisassembler::Disassemble(op, address, for_assemble);
|
||||||
const UGeckoInstruction inst{op};
|
const UGeckoInstruction inst{op};
|
||||||
|
|
||||||
if (inst.OPCD == 1)
|
if (inst.OPCD == 1)
|
||||||
|
|
|
@ -75,7 +75,8 @@ public:
|
||||||
// Threads
|
// Threads
|
||||||
Common::Debug::Threads GetThreads(const Core::CPUThreadGuard& guard) const override;
|
Common::Debug::Threads GetThreads(const Core::CPUThreadGuard& guard) const override;
|
||||||
|
|
||||||
std::string Disassemble(const Core::CPUThreadGuard* guard, u32 address) const override;
|
std::string Disassemble(const Core::CPUThreadGuard* guard, u32 address,
|
||||||
|
bool for_assemble = false) const override;
|
||||||
std::string GetRawMemoryString(const Core::CPUThreadGuard& guard, int memory,
|
std::string GetRawMemoryString(const Core::CPUThreadGuard& guard, int memory,
|
||||||
u32 address) const override;
|
u32 address) const override;
|
||||||
bool IsAlive() const override;
|
bool IsAlive() const override;
|
||||||
|
|
|
@ -454,7 +454,7 @@ void CachedInterpreter::LogGeneratedCode() const
|
||||||
std::span{m_code_buffer.data(), code_block.m_num_instructions})
|
std::span{m_code_buffer.data(), code_block.m_num_instructions})
|
||||||
{
|
{
|
||||||
fmt::print(stream, "0x{:08x}\t\t{}\n", op.address,
|
fmt::print(stream, "0x{:08x}\t\t{}\n", op.address,
|
||||||
Common::GekkoDisassembler::Disassemble(op.inst.hex, op.address));
|
Common::GekkoDisassembler::Disassemble(op.inst.hex, op.address, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
stream << "\nHost Code:\n";
|
stream << "\nHost Code:\n";
|
||||||
|
|
|
@ -97,7 +97,8 @@ void Interpreter::Trace(const UGeckoInstruction& inst)
|
||||||
fregs += fmt::format("f{:02d}: {:08x} {:08x} ", i, ps.PS0AsU64(), ps.PS1AsU64());
|
fregs += fmt::format("f{:02d}: {:08x} {:08x} ", i, ps.PS0AsU64(), ps.PS1AsU64());
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string ppc_inst = Common::GekkoDisassembler::Disassemble(inst.hex, m_ppc_state.pc);
|
const std::string ppc_inst =
|
||||||
|
Common::GekkoDisassembler::Disassemble(inst.hex, m_ppc_state.pc, false);
|
||||||
DEBUG_LOG_FMT(POWERPC,
|
DEBUG_LOG_FMT(POWERPC,
|
||||||
"INTER PC: {:08x} SRR0: {:08x} SRR1: {:08x} CRval: {:016x} "
|
"INTER PC: {:08x} SRR0: {:08x} SRR1: {:08x} CRval: {:016x} "
|
||||||
"FPSCR: {:08x} MSR: {:08x} LR: {:08x} {} {:08x} {}",
|
"FPSCR: {:08x} MSR: {:08x} LR: {:08x} {} {:08x} {}",
|
||||||
|
@ -294,7 +295,7 @@ void Interpreter::unknown_instruction(Interpreter& interpreter, UGeckoInstructio
|
||||||
|
|
||||||
const u32 last_pc = interpreter.m_last_pc;
|
const u32 last_pc = interpreter.m_last_pc;
|
||||||
const u32 opcode = PowerPC::MMU::HostRead_U32(guard, last_pc);
|
const u32 opcode = PowerPC::MMU::HostRead_U32(guard, last_pc);
|
||||||
const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc);
|
const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc, false);
|
||||||
NOTICE_LOG_FMT(POWERPC, "Last PC = {:08x} : {}", last_pc, disasm);
|
NOTICE_LOG_FMT(POWERPC, "Last PC = {:08x} : {}", last_pc, disasm);
|
||||||
Dolphin_Debugger::PrintCallstack(guard, Common::Log::LogType::POWERPC,
|
Dolphin_Debugger::PrintCallstack(guard, Common::Log::LogType::POWERPC,
|
||||||
Common::Log::LogLevel::LNOTICE);
|
Common::Log::LogLevel::LNOTICE);
|
||||||
|
|
|
@ -1177,7 +1177,8 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||||
if (!gpr.SanityCheck() || !fpr.SanityCheck())
|
if (!gpr.SanityCheck() || !fpr.SanityCheck())
|
||||||
{
|
{
|
||||||
const std::string ppc_inst = Common::GekkoDisassembler::Disassemble(op.inst.hex, em_address);
|
const std::string ppc_inst =
|
||||||
|
Common::GekkoDisassembler::Disassemble(op.inst.hex, em_address, false);
|
||||||
NOTICE_LOG_FMT(DYNA_REC, "Unflushed register: {}", ppc_inst);
|
NOTICE_LOG_FMT(DYNA_REC, "Unflushed register: {}", ppc_inst);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1320,7 +1321,7 @@ void Jit64::LogGeneratedCode() const
|
||||||
std::span{m_code_buffer.data(), code_block.m_num_instructions})
|
std::span{m_code_buffer.data(), code_block.m_num_instructions})
|
||||||
{
|
{
|
||||||
fmt::print(stream, "0x{:08x}\t\t{}\n", op.address,
|
fmt::print(stream, "0x{:08x}\t\t{}\n", op.address,
|
||||||
Common::GekkoDisassembler::Disassemble(op.inst.hex, op.address));
|
Common::GekkoDisassembler::Disassemble(op.inst.hex, op.address, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
const JitBlock* const block = js.curBlock;
|
const JitBlock* const block = js.curBlock;
|
||||||
|
|
|
@ -1401,7 +1401,7 @@ void JitArm64::LogGeneratedCode() const
|
||||||
std::span{m_code_buffer.data(), code_block.m_num_instructions})
|
std::span{m_code_buffer.data(), code_block.m_num_instructions})
|
||||||
{
|
{
|
||||||
fmt::print(stream, "0x{:08x}\t\t{}\n", op.address,
|
fmt::print(stream, "0x{:08x}\t\t{}\n", op.address,
|
||||||
Common::GekkoDisassembler::Disassemble(op.inst.hex, op.address));
|
Common::GekkoDisassembler::Disassemble(op.inst.hex, op.address, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
const JitBlock* const block = js.curBlock;
|
const JitBlock* const block = js.curBlock;
|
||||||
|
|
|
@ -38,8 +38,9 @@ QString HtmlFormatErrorLine(const Common::GekkoAssembler::AssemblerError& err)
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
AssembleInstructionDialog::AssembleInstructionDialog(QWidget* parent, u32 address, u32 value)
|
AssembleInstructionDialog::AssembleInstructionDialog(QWidget* parent, u32 address, u32 value,
|
||||||
: QDialog(parent), m_code(value), m_address(address)
|
QString disasm)
|
||||||
|
: QDialog(parent), m_code(value), m_address(address), m_disassembly(disasm)
|
||||||
{
|
{
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
setWindowModality(Qt::WindowModal);
|
setWindowModality(Qt::WindowModal);
|
||||||
|
@ -66,7 +67,7 @@ void AssembleInstructionDialog::CreateWidgets()
|
||||||
layout->addWidget(m_error_line_label);
|
layout->addWidget(m_error_line_label);
|
||||||
layout->addWidget(m_msg_label);
|
layout->addWidget(m_msg_label);
|
||||||
layout->addWidget(m_button_box);
|
layout->addWidget(m_button_box);
|
||||||
m_input_edit->setText(QStringLiteral(".4byte 0x%1").arg(m_code, 8, 16, QLatin1Char('0')));
|
m_input_edit->setText(m_disassembly);
|
||||||
|
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
OnEditChanged();
|
OnEditChanged();
|
||||||
|
@ -86,6 +87,31 @@ void AssembleInstructionDialog::OnEditChanged()
|
||||||
std::string line = m_input_edit->text().toStdString();
|
std::string line = m_input_edit->text().toStdString();
|
||||||
Common::ToLower(&line);
|
Common::ToLower(&line);
|
||||||
|
|
||||||
|
size_t posArrow = line.find("->");
|
||||||
|
if (posArrow != std::string::npos)
|
||||||
|
{
|
||||||
|
std::string start = line.substr(0, posArrow);
|
||||||
|
std::string dest = line.substr(posArrow + 2);
|
||||||
|
u32 destAddress = 0;
|
||||||
|
size_t posHex = dest.find("0x");
|
||||||
|
if (posHex == std::string::npos)
|
||||||
|
{
|
||||||
|
destAddress = (u32)strtoul(dest.c_str(), nullptr, 10);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
destAddress = (u32)strtoul(dest.substr(posHex + 2).c_str(), nullptr, 16);
|
||||||
|
}
|
||||||
|
if (destAddress < m_address)
|
||||||
|
{
|
||||||
|
line = start + " -" + std::to_string(m_address - destAddress);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line = start + " " + std::to_string(destAddress - m_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FailureOr<std::vector<CodeBlock>> asm_result = Assemble(line, m_address);
|
FailureOr<std::vector<CodeBlock>> asm_result = Assemble(line, m_address);
|
||||||
|
|
||||||
if (IsFailure(asm_result))
|
if (IsFailure(asm_result))
|
||||||
|
|
|
@ -15,7 +15,7 @@ class AssembleInstructionDialog : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit AssembleInstructionDialog(QWidget* parent, u32 address, u32 value);
|
explicit AssembleInstructionDialog(QWidget* parent, u32 address, u32 value, QString disasm);
|
||||||
|
|
||||||
u32 GetCode() const;
|
u32 GetCode() const;
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ private:
|
||||||
u32 m_code;
|
u32 m_code;
|
||||||
u32 m_address;
|
u32 m_address;
|
||||||
|
|
||||||
|
QString m_disassembly;
|
||||||
QLineEdit* m_input_edit;
|
QLineEdit* m_input_edit;
|
||||||
QLabel* m_error_loc_label;
|
QLabel* m_error_loc_label;
|
||||||
QLabel* m_error_line_label;
|
QLabel* m_error_line_label;
|
||||||
|
|
|
@ -306,7 +306,7 @@ static QVariant GetValidSymbolStringVariant(const QVariant& symbol_name_v)
|
||||||
|
|
||||||
static QString GetInstructionMnemonic(u32 hex)
|
static QString GetInstructionMnemonic(u32 hex)
|
||||||
{
|
{
|
||||||
const std::string disas = Common::GekkoDisassembler::Disassemble(hex, 0);
|
const std::string disas = Common::GekkoDisassembler::Disassemble(hex, 0, false);
|
||||||
const std::string::size_type split = disas.find('\t');
|
const std::string::size_type split = disas.find('\t');
|
||||||
// I wish I could disassemble just the mnemonic!
|
// I wish I could disassemble just the mnemonic!
|
||||||
if (split == std::string::npos)
|
if (split == std::string::npos)
|
||||||
|
|
|
@ -228,7 +228,7 @@ void CodeViewWidget::FontBasedSizing()
|
||||||
// Similarly, the longest parameter set is 'rtoc, rtoc, r10, 10, 10 (00000800)' (0x5c425294u),
|
// Similarly, the longest parameter set is 'rtoc, rtoc, r10, 10, 10 (00000800)' (0x5c425294u),
|
||||||
// but one is unlikely to encounter that in practice, so let's use a slightly more reasonable
|
// but one is unlikely to encounter that in practice, so let's use a slightly more reasonable
|
||||||
// 'r31, r31, 16, 16, 31 (ffff0000)'. The user can resize the columns as necessary anyway.
|
// 'r31, r31, 16, 16, 31 (ffff0000)'. The user can resize the columns as necessary anyway.
|
||||||
const std::string disas = Common::GekkoDisassembler::Disassemble(0x57ff843fu, 0);
|
const std::string disas = Common::GekkoDisassembler::Disassemble(0x57ff843fu, 0, false);
|
||||||
const auto split = disas.find('\t');
|
const auto split = disas.find('\t');
|
||||||
const std::string ins = (split == std::string::npos ? disas : disas.substr(0, split));
|
const std::string ins = (split == std::string::npos ? disas : disas.substr(0, split));
|
||||||
const std::string param = (split == std::string::npos ? "" : disas.substr(split + 1));
|
const std::string param = (split == std::string::npos ? "" : disas.substr(split + 1));
|
||||||
|
@ -1030,7 +1030,12 @@ void CodeViewWidget::DoPatchInstruction(bool assemble)
|
||||||
|
|
||||||
if (assemble)
|
if (assemble)
|
||||||
{
|
{
|
||||||
AssembleInstructionDialog dialog(this, addr, debug_interface.ReadInstruction(guard, addr));
|
std::string code_line =
|
||||||
|
m_system.GetPowerPC().GetDebugInterface().Disassemble(&guard, addr, true);
|
||||||
|
std::ranges::replace(code_line, '\t', ' ');
|
||||||
|
|
||||||
|
AssembleInstructionDialog dialog(this, addr, debug_interface.ReadInstruction(guard, addr),
|
||||||
|
QString::fromStdString(code_line));
|
||||||
SetQWidgetWindowDecorations(&dialog);
|
SetQWidgetWindowDecorations(&dialog);
|
||||||
if (dialog.exec() == QDialog::Accepted)
|
if (dialog.exec() == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,6 +55,10 @@ public:
|
||||||
HighlightCurToken(HighlightFormat::FPR);
|
HighlightCurToken(HighlightFormat::FPR);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Terminal::GQR:
|
||||||
|
HighlightCurToken(HighlightFormat::GQR);
|
||||||
|
break;
|
||||||
|
|
||||||
case Terminal::SPR:
|
case Terminal::SPR:
|
||||||
HighlightCurToken(HighlightFormat::SPR);
|
HighlightCurToken(HighlightFormat::SPR);
|
||||||
break;
|
break;
|
||||||
|
@ -221,6 +225,7 @@ void GekkoSyntaxHighlight::HighlightSubstr(int start, int len, HighlightFormat f
|
||||||
break;
|
break;
|
||||||
case HighlightFormat::GPR:
|
case HighlightFormat::GPR:
|
||||||
case HighlightFormat::FPR:
|
case HighlightFormat::FPR:
|
||||||
|
case HighlightFormat::GQR:
|
||||||
case HighlightFormat::SPR:
|
case HighlightFormat::SPR:
|
||||||
case HighlightFormat::CRField:
|
case HighlightFormat::CRField:
|
||||||
case HighlightFormat::CRFlag:
|
case HighlightFormat::CRFlag:
|
||||||
|
|
|
@ -18,6 +18,7 @@ enum class HighlightFormat
|
||||||
Immediate,
|
Immediate,
|
||||||
GPR,
|
GPR,
|
||||||
FPR,
|
FPR,
|
||||||
|
GQR,
|
||||||
SPR,
|
SPR,
|
||||||
CRField,
|
CRField,
|
||||||
CRFlag,
|
CRFlag,
|
||||||
|
|
|
@ -213,7 +213,7 @@ static void DisassembleCodeBuffer(const JitBlock& block, PPCSymbolDB& ppc_symbol
|
||||||
next_address = address;
|
next_address = address;
|
||||||
}
|
}
|
||||||
fmt::print(stream, "0x{:08x}\t{}\n", address,
|
fmt::print(stream, "0x{:08x}\t{}\n", address,
|
||||||
Common::GekkoDisassembler::Disassemble(inst.hex, address));
|
Common::GekkoDisassembler::Disassemble(inst.hex, address, false));
|
||||||
next_address += sizeof(UGeckoInstruction);
|
next_address += sizeof(UGeckoInstruction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,9 +55,9 @@ void PatchInstructionDialog::OnEditChanged()
|
||||||
|
|
||||||
m_button_box->button(QDialogButtonBox::Ok)->setEnabled(good);
|
m_button_box->button(QDialogButtonBox::Ok)->setEnabled(good);
|
||||||
|
|
||||||
m_preview_label->setText(
|
m_preview_label->setText(tr("Instruction: %1")
|
||||||
tr("Instruction: %1")
|
.arg(QString::fromStdString(Common::GekkoDisassembler::Disassemble(
|
||||||
.arg(QString::fromStdString(Common::GekkoDisassembler::Disassemble(m_code, m_address))));
|
m_code, m_address, false))));
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 PatchInstructionDialog::GetCode() const
|
u32 PatchInstructionDialog::GetCode() const
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
#include "Common/Assembler/GekkoAssembler.h"
|
#include "Common/Assembler/GekkoAssembler.h"
|
||||||
|
#include "Common/GekkoDisassembler.h"
|
||||||
|
|
||||||
using namespace Common::GekkoAssembler;
|
using namespace Common::GekkoAssembler;
|
||||||
|
|
||||||
|
@ -456,6 +458,45 @@ TEST(Assembler, AllInstructions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Assembler, RoundTripTest)
|
||||||
|
{
|
||||||
|
auto res = Assemble(instructions, 0);
|
||||||
|
ASSERT_TRUE(!IsFailure(res));
|
||||||
|
auto&& code_blocks = GetT(res);
|
||||||
|
ASSERT_EQ(code_blocks.size(), 1);
|
||||||
|
ASSERT_EQ(code_blocks[0].instructions.size(), sizeof(expected_instructions));
|
||||||
|
ASSERT_EQ(code_blocks[0].instructions.size() & 3, 0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < code_blocks[0].instructions.size(); i += sizeof(u32))
|
||||||
|
{
|
||||||
|
const u32 hex_code =
|
||||||
|
(code_blocks[0].instructions[i] << 24) | (code_blocks[0].instructions[i + 1] << 16) |
|
||||||
|
(code_blocks[0].instructions[i + 2] << 8) | code_blocks[0].instructions[i + 3];
|
||||||
|
std::string text_code = Common::GekkoDisassembler::Disassemble(hex_code, 0, true);
|
||||||
|
// NEED TO FIX ABSOLUTE ADDRESSES COMING IN FROM DISASSEMBLER
|
||||||
|
size_t posArrow = text_code.find("->");
|
||||||
|
if (posArrow != std::string::npos)
|
||||||
|
{
|
||||||
|
u32 address = (u32)strtoul(text_code.substr(posArrow + 2).c_str(), nullptr, 16) & 0xFFFF;
|
||||||
|
if (address & 0x8000)
|
||||||
|
{
|
||||||
|
text_code = fmt::format("{} -0x{:04X}", text_code.substr(0, posArrow), 0x10000 - address);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text_code = fmt::format("{} 0x{:04X}", text_code.substr(0, posArrow), address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto recompiled = Assemble(text_code, 0);
|
||||||
|
auto&& code_blocks_reassembled = GetT(recompiled);
|
||||||
|
for (size_t j = 0; j < sizeof(u32); j++)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(code_blocks[0].instructions[i + j], code_blocks_reassembled[0].instructions[j])
|
||||||
|
<< " -> i=" << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr char extended_instructions[] = "subi 0, 4, 8\n"
|
constexpr char extended_instructions[] = "subi 0, 4, 8\n"
|
||||||
"subis 0, 4, 8\n"
|
"subis 0, 4, 8\n"
|
||||||
"subic 0, 4, 8\n"
|
"subic 0, 4, 8\n"
|
||||||
|
|
Loading…
Add table
Reference in a new issue