mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 06:39:46 -06:00
Merge pull request #10750 from Pokechu22/hermes-test
Enhance DSPAssemblyTest, and fix various DSPTool bugs discovered while doing so
This commit is contained in:
@ -57,10 +57,12 @@ bool Disassemble(const std::vector<u16>& code, bool line_numbers, std::string& t
|
||||
return success;
|
||||
}
|
||||
|
||||
// NOTE: This code is called from DSPTool and UnitTests, which do not use the logging system.
|
||||
// Thus, fmt::print is used instead of the log system.
|
||||
bool Compare(const std::vector<u16>& code1, const std::vector<u16>& code2)
|
||||
{
|
||||
if (code1.size() != code2.size())
|
||||
WARN_LOG_FMT(AUDIO, "Size difference! 1={} 2={}\n", code1.size(), code2.size());
|
||||
fmt::print("Size difference! 1={} 2={}\n", code1.size(), code2.size());
|
||||
u32 count_equal = 0;
|
||||
const u16 min_size = static_cast<u16>(std::min(code1.size(), code2.size()));
|
||||
|
||||
@ -76,26 +78,47 @@ bool Compare(const std::vector<u16>& code1, const std::vector<u16>& code2)
|
||||
{
|
||||
std::string line1, line2;
|
||||
u16 pc = i;
|
||||
disassembler.DisassembleOpcode(&code1[0], &pc, line1);
|
||||
disassembler.DisassembleOpcode(code1, &pc, line1);
|
||||
pc = i;
|
||||
disassembler.DisassembleOpcode(&code2[0], &pc, line2);
|
||||
WARN_LOG_FMT(AUDIO, "!! {:04x} : {:04x} vs {:04x} - {} vs {}\n", i, code1[i], code2[i],
|
||||
line1, line2);
|
||||
disassembler.DisassembleOpcode(code2, &pc, line2);
|
||||
fmt::print("!! {:04x} : {:04x} vs {:04x} - {} vs {}\n", i, code1[i], code2[i], line1,
|
||||
line2);
|
||||
|
||||
// Also do a comparison one word back if the previous word corresponded to an instruction with
|
||||
// a large immediate. (Compare operates on individual words, so both the main word and the
|
||||
// immediate following it are compared separately; we don't use DisassembleOpcode's ability to
|
||||
// increment pc by 2 for two-word instructions because code1 may have a 1-word instruction
|
||||
// where code2 has a 2-word instruction.)
|
||||
if (i >= 1 && code1[i - 1] == code2[i - 1])
|
||||
{
|
||||
const DSPOPCTemplate* opc = FindOpInfoByOpcode(code1[i - 1]);
|
||||
if (opc != nullptr && opc->size == 2)
|
||||
{
|
||||
line1.clear();
|
||||
line2.clear();
|
||||
pc = i - 1;
|
||||
disassembler.DisassembleOpcode(code1, &pc, line1);
|
||||
pc = i - 1;
|
||||
disassembler.DisassembleOpcode(code2, &pc, line2);
|
||||
fmt::print(" (or {:04x} : {:04x} {:04x} vs {:04x} {:04x} - {} vs {})\n", i - 1,
|
||||
code1[i - 1], code1[i], code2[i - 1], code2[i], line1, line2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (code2.size() != code1.size())
|
||||
{
|
||||
DEBUG_LOG_FMT(AUDIO, "Extra code words:\n");
|
||||
fmt::print("Extra code words:\n");
|
||||
const std::vector<u16>& longest = code1.size() > code2.size() ? code1 : code2;
|
||||
for (u16 i = min_size; i < longest.size(); i++)
|
||||
{
|
||||
u16 pc = i;
|
||||
std::string line;
|
||||
disassembler.DisassembleOpcode(&longest[0], &pc, line);
|
||||
DEBUG_LOG_FMT(AUDIO, "!! {}\n", line);
|
||||
disassembler.DisassembleOpcode(longest, &pc, line);
|
||||
fmt::print("!! {:04x} : {:04x} - {}\n", i, longest[i], line);
|
||||
}
|
||||
}
|
||||
DEBUG_LOG_FMT(AUDIO, "Equal instruction words: {} / {}\n", count_equal, min_size);
|
||||
fmt::print("Equal instruction words: {} / {}\n", count_equal, min_size);
|
||||
return code1.size() == code2.size() && code1.size() == count_equal;
|
||||
}
|
||||
|
||||
|
@ -33,9 +33,10 @@ bool DSPDisassembler::Disassemble(const std::vector<u16>& code, std::string& tex
|
||||
|
||||
for (u16 pc = 0; pc < code.size();)
|
||||
{
|
||||
if (!DisassembleOpcode(code.data(), &pc, text))
|
||||
return false;
|
||||
bool failed = !DisassembleOpcode(code, &pc, text);
|
||||
text.append("\n");
|
||||
if (failed)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -107,7 +108,7 @@ std::string DSPDisassembler::DisassembleParameters(const DSPOPCTemplate& opc, u1
|
||||
{
|
||||
// Left and right shifts function essentially as a single shift by a 7-bit signed value,
|
||||
// but are split into two intructions for clarity.
|
||||
buf += fmt::format("#{}", (val & 0x20) != 0 ? (64 - val) : val);
|
||||
buf += fmt::format("#{}", (val & 0x20) != 0 ? (int(val) - 64) : int(val));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -139,16 +140,23 @@ std::string DSPDisassembler::DisassembleParameters(const DSPOPCTemplate& opc, u1
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool DSPDisassembler::DisassembleOpcode(const u16* binbuf, u16* pc, std::string& dest)
|
||||
bool DSPDisassembler::DisassembleOpcode(const std::vector<u16>& code, u16* pc, std::string& dest)
|
||||
{
|
||||
if ((*pc & 0x7fff) >= 0x1000)
|
||||
return DisassembleOpcode(code.data(), code.size(), pc, dest);
|
||||
}
|
||||
|
||||
bool DSPDisassembler::DisassembleOpcode(const u16* binbuf, size_t binbuf_size, u16* pc,
|
||||
std::string& dest)
|
||||
{
|
||||
const u16 wrapped_pc = (*pc & 0x7fff);
|
||||
if (wrapped_pc >= binbuf_size)
|
||||
{
|
||||
++pc;
|
||||
dest.append("; outside memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
const u16 op1 = binbuf[*pc & 0x0fff];
|
||||
const u16 op1 = binbuf[wrapped_pc];
|
||||
|
||||
// Find main opcode
|
||||
const DSPOPCTemplate* opc = FindOpInfoByOpcode(op1);
|
||||
@ -179,14 +187,23 @@ bool DSPDisassembler::DisassembleOpcode(const u16* binbuf, u16* pc, std::string&
|
||||
// printing
|
||||
|
||||
if (settings_.show_pc)
|
||||
dest += fmt::format("{:04x} ", *pc);
|
||||
dest += fmt::format("{:04x} ", wrapped_pc);
|
||||
|
||||
u16 op2;
|
||||
|
||||
// Size 2 - the op has a large immediate.
|
||||
if (opc->size == 2)
|
||||
{
|
||||
op2 = binbuf[(*pc + 1) & 0x0fff];
|
||||
if (wrapped_pc + 1 >= binbuf_size)
|
||||
{
|
||||
if (settings_.show_hex)
|
||||
dest += fmt::format("{:04x} ???? ", op1);
|
||||
dest += fmt::format("; Insufficient data for large immediate");
|
||||
*pc += opc->size;
|
||||
return false;
|
||||
}
|
||||
|
||||
op2 = binbuf[wrapped_pc + 1];
|
||||
if (settings_.show_hex)
|
||||
dest += fmt::format("{:04x} {:04x} ", op1, op2);
|
||||
}
|
||||
|
@ -34,8 +34,10 @@ public:
|
||||
|
||||
bool Disassemble(const std::vector<u16>& code, std::string& text);
|
||||
|
||||
// Warning - this one is trickier to use right.
|
||||
bool DisassembleOpcode(const u16* binbuf, u16* pc, std::string& dest);
|
||||
// Disassembles the given opcode at pc and increases pc by the opcode's size.
|
||||
// The PC is wrapped such that 0x0000 and 0x8000 both point to the start of the buffer.
|
||||
bool DisassembleOpcode(const std::vector<u16>& code, u16* pc, std::string& dest);
|
||||
bool DisassembleOpcode(const u16* binbuf, size_t binbuf_size, u16* pc, std::string& dest);
|
||||
|
||||
private:
|
||||
std::string DisassembleParameters(const DSPOPCTemplate& opc, u16 op1, u16 op2);
|
||||
|
@ -77,13 +77,15 @@ void AutoDisassembly(const SDSP& dsp, u16 start_addr, u16 end_addr)
|
||||
|
||||
u16 addr = start_addr;
|
||||
const u16* ptr = (start_addr >> 15) != 0 ? dsp.irom : dsp.iram;
|
||||
constexpr size_t size = DSP_IROM_SIZE;
|
||||
static_assert(size == DSP_IRAM_SIZE);
|
||||
while (addr < end_addr)
|
||||
{
|
||||
line_to_addr[line_counter] = addr;
|
||||
addr_to_line[addr] = line_counter;
|
||||
|
||||
std::string buf;
|
||||
if (!disasm.DisassembleOpcode(ptr, &addr, buf))
|
||||
if (!disasm.DisassembleOpcode(ptr, size, &addr, buf))
|
||||
{
|
||||
ERROR_LOG_FMT(DSPLLE, "disasm failed at {:04x}", addr);
|
||||
break;
|
||||
|
Reference in New Issue
Block a user