Files
archived-dolphin/Source/Core/Core/DSP/DSPDisassembler.cpp
Martino Fontana a14c88ba67 Remove unused imports
Yellow squiggly lines begone!
Done automatically on .cpp files through `run-clang-tidy`, with manual corrections to the mistakes.
If an import is directly used, but is technically unnecessary since it's recursively imported by something else, it is *not* removed.
The tool doesn't touch .h files, so I did some of them by hand while fixing errors due to old recursive imports.
Not everything is removed, but the cleanup should be substantial enough.
Because this done on Linux, code that isn't used on it is mostly untouched.
(Hopefully no open PR is depending on these imports...)
2026-01-25 16:12:15 +01:00

254 lines
5.7 KiB
C++

// Copyright 2008 Dolphin Emulator Project
// Copyright 2005 Duddie
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Core/DSP/DSPDisassembler.h"
#include <limits>
#include <string>
#include <utility>
#include <vector>
#include <fmt/format.h>
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "Core/DSP/DSPTables.h"
namespace DSP
{
DSPDisassembler::DSPDisassembler(const AssemblerSettings& settings) : settings_(settings)
{
}
bool DSPDisassembler::Disassemble(const std::vector<u16>& code, std::string& text)
{
if (code.size() > std::numeric_limits<u16>::max())
{
text.append("; code too large for 16-bit addressing\n");
return false;
}
for (u16 pc = 0; pc < code.size();)
{
bool failed = !DisassembleOpcode(code, &pc, text);
text.append("\n");
if (failed)
return false;
}
return true;
}
std::string DSPDisassembler::DisassembleParameters(const DSPOPCTemplate& opc, u16 op1, u16 op2)
{
std::string buf;
for (int j = 0; j < opc.param_count; j++)
{
if (j > 0)
buf += ", ";
u32 val = (opc.params[j].loc >= 1) ? op2 : op1;
val &= opc.params[j].mask;
if (opc.params[j].lshift < 0)
val = val << (-opc.params[j].lshift);
else
val = val >> opc.params[j].lshift;
u32 type = opc.params[j].type;
if ((type & 0xff) == 0x10)
type &= 0xff00;
if (type & P_REG)
{
// Check for _D parameter - if so flip.
if ((type == P_ACC_D) || (type == P_ACCM_D)) // Used to be P_ACCM_D TODO verify
val = (~val & 0x1) | ((type & P_REGS_MASK) >> 8);
else
val |= (type & P_REGS_MASK) >> 8;
type &= ~P_REGS_MASK;
}
switch (type)
{
case P_REG:
if (settings_.decode_registers)
buf += fmt::format("${}", pdregname(val));
else
buf += fmt::format("${}", val);
break;
case P_PRG:
if (settings_.decode_registers)
buf += fmt::format("@${}", pdregname(val));
else
buf += fmt::format("@${}", val);
break;
case P_VAL:
case P_ADDR_I:
case P_ADDR_D:
if (settings_.decode_names)
{
buf += pdname(val);
}
else
{
buf += fmt::format("0x{:04x}", val);
}
break;
case P_IMM:
if (opc.params[j].size != 2)
{
// LSL, LSR, ASL, ASR
if (opc.params[j].mask == 0x003f)
{
// Left and right shifts function essentially as a single shift by a 7-bit signed value,
// but are split into two instructions for clarity.
buf += fmt::format("#{}", (val & 0x20) != 0 ? (int(val) - 64) : int(val));
}
else
{
buf += fmt::format("#0x{:02x}", val);
}
}
else
{
buf += fmt::format("#0x{:04x}", val);
}
break;
case P_MEM:
if (opc.params[j].size != 2)
val = (u16)(s16)(s8)val;
if (settings_.decode_names)
buf += fmt::format("@{}", pdname(val));
else
buf += fmt::format("@0x{:04x}", val);
break;
default:
ERROR_LOG_FMT(DSPLLE, "Unknown parameter type: {:x}", std::to_underlying(opc.params[j].type));
break;
}
}
return buf;
}
bool DSPDisassembler::DisassembleOpcode(const std::vector<u16>& code, u16* pc, std::string& dest)
{
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[wrapped_pc];
// Find main opcode
const DSPOPCTemplate* opc = FindOpInfoByOpcode(op1);
if (!opc)
opc = &cw;
bool is_extended = false;
bool is_only_7_bit_ext = false;
if (((opc->opcode >> 12) == 0x3) && (op1 & 0x007f))
{
is_extended = true;
is_only_7_bit_ext = true;
}
else if (((opc->opcode >> 12) > 0x3) && (op1 & 0x00ff))
{
is_extended = true;
}
const DSPOPCTemplate* opc_ext = nullptr;
if (is_extended)
{
// opcode has an extension
const u16 extended_opcode = is_only_7_bit_ext ? op1 & 0x7F : op1;
opc_ext = FindExtOpInfoByOpcode(extended_opcode);
}
// printing
if (settings_.show_pc)
dest += fmt::format("{:04x} ", wrapped_pc);
u16 op2;
// Size 2 - the op has a large immediate.
if (opc->size == 2)
{
if (wrapped_pc + 1u >= 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);
}
else
{
op2 = 0;
if (settings_.show_hex)
dest += fmt::format("{:04x} ", op1);
}
std::string opname = opc->name;
if (is_extended)
opname += fmt::format("{}{}", settings_.ext_separator, opc_ext->name);
if (settings_.lower_case_ops)
Common::ToLower(&opname);
if (settings_.print_tabs)
dest += fmt::format("{}\t", opname);
else
dest += fmt::format("{:<12}", opname);
if (opc->param_count > 0)
dest += DisassembleParameters(*opc, op1, op2);
// Handle opcode extension.
if (is_extended)
{
if (opc->param_count > 0)
dest += " ";
dest += ": ";
if (opc_ext->param_count > 0)
dest += DisassembleParameters(*opc_ext, op1, op2);
}
if (opc->opcode_mask == 0)
{
// unknown opcode
dest += "\t\t; *** UNKNOWN OPCODE ***";
}
*pc += is_extended ? opc_ext->size : opc->size;
return true;
}
} // namespace DSP