mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-12-23 06:57:08 +00:00
instruction tables Previously, all of the internals that handled how the instruction tables are initialized were exposed externally. However, this can all be made private to each CPU backend. If each backend has an Init() function, then this is where the instruction tables should be initialized, it shouldn't be the responsibility of external code to ensure internal validity. This allows for getting rid of all the table initialization shenanigans within JitInterface and PPCTables.
205 lines
5.2 KiB
C++
205 lines
5.2 KiB
C++
// Copyright 2008 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#include "Core/PowerPC/PPCTables.h"
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cinttypes>
|
|
#include <cstddef>
|
|
#include <vector>
|
|
|
|
#include "Common/CommonTypes.h"
|
|
#include "Common/FileUtil.h"
|
|
#include "Common/StringUtil.h"
|
|
|
|
#include "Core/PowerPC/Interpreter/Interpreter.h"
|
|
#include "Core/PowerPC/JitInterface.h"
|
|
#include "Core/PowerPC/PowerPC.h"
|
|
|
|
std::array<GekkoOPInfo*, 64> m_infoTable;
|
|
std::array<GekkoOPInfo*, 1024> m_infoTable4;
|
|
std::array<GekkoOPInfo*, 1024> m_infoTable19;
|
|
std::array<GekkoOPInfo*, 1024> m_infoTable31;
|
|
std::array<GekkoOPInfo*, 32> m_infoTable59;
|
|
std::array<GekkoOPInfo*, 1024> m_infoTable63;
|
|
|
|
std::array<GekkoOPInfo*, 512> m_allInstructions;
|
|
size_t m_numInstructions;
|
|
|
|
const std::array<u64, 16> m_crTable = {{
|
|
PPCCRToInternal(0x0), PPCCRToInternal(0x1), PPCCRToInternal(0x2), PPCCRToInternal(0x3),
|
|
PPCCRToInternal(0x4), PPCCRToInternal(0x5), PPCCRToInternal(0x6), PPCCRToInternal(0x7),
|
|
PPCCRToInternal(0x8), PPCCRToInternal(0x9), PPCCRToInternal(0xA), PPCCRToInternal(0xB),
|
|
PPCCRToInternal(0xC), PPCCRToInternal(0xD), PPCCRToInternal(0xE), PPCCRToInternal(0xF),
|
|
}};
|
|
|
|
GekkoOPInfo* GetOpInfo(UGeckoInstruction _inst)
|
|
{
|
|
GekkoOPInfo* info = m_infoTable[_inst.OPCD];
|
|
if (info->type == OPTYPE_SUBTABLE)
|
|
{
|
|
switch (_inst.OPCD)
|
|
{
|
|
case 4:
|
|
return m_infoTable4[_inst.SUBOP10];
|
|
case 19:
|
|
return m_infoTable19[_inst.SUBOP10];
|
|
case 31:
|
|
return m_infoTable31[_inst.SUBOP10];
|
|
case 59:
|
|
return m_infoTable59[_inst.SUBOP5];
|
|
case 63:
|
|
return m_infoTable63[_inst.SUBOP10];
|
|
default:
|
|
_assert_msg_(POWERPC, 0, "GetOpInfo - invalid subtable op %08x @ %08x", _inst.hex, PC);
|
|
return nullptr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (info->type == OPTYPE_INVALID)
|
|
{
|
|
_assert_msg_(POWERPC, 0, "GetOpInfo - invalid op %08x @ %08x", _inst.hex, PC);
|
|
return nullptr;
|
|
}
|
|
return m_infoTable[_inst.OPCD];
|
|
}
|
|
}
|
|
|
|
Interpreter::Instruction GetInterpreterOp(UGeckoInstruction _inst)
|
|
{
|
|
const GekkoOPInfo* info = m_infoTable[_inst.OPCD];
|
|
if (info->type == OPTYPE_SUBTABLE)
|
|
{
|
|
switch (_inst.OPCD)
|
|
{
|
|
case 4:
|
|
return Interpreter::m_op_table4[_inst.SUBOP10];
|
|
case 19:
|
|
return Interpreter::m_op_table19[_inst.SUBOP10];
|
|
case 31:
|
|
return Interpreter::m_op_table31[_inst.SUBOP10];
|
|
case 59:
|
|
return Interpreter::m_op_table59[_inst.SUBOP5];
|
|
case 63:
|
|
return Interpreter::m_op_table63[_inst.SUBOP10];
|
|
default:
|
|
_assert_msg_(POWERPC, 0, "GetInterpreterOp - invalid subtable op %08x @ %08x", _inst.hex, PC);
|
|
return nullptr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (info->type == OPTYPE_INVALID)
|
|
{
|
|
_assert_msg_(POWERPC, 0, "GetInterpreterOp - invalid op %08x @ %08x", _inst.hex, PC);
|
|
return nullptr;
|
|
}
|
|
return Interpreter::m_op_table[_inst.OPCD];
|
|
}
|
|
}
|
|
namespace PPCTables
|
|
{
|
|
bool UsesFPU(UGeckoInstruction inst)
|
|
{
|
|
GekkoOPInfo* const info = GetOpInfo(inst);
|
|
|
|
return (info->flags & FL_USE_FPU) != 0;
|
|
}
|
|
|
|
#define OPLOG
|
|
#define OP_TO_LOG "mtfsb0x"
|
|
|
|
#ifdef OPLOG
|
|
namespace
|
|
{
|
|
std::vector<u32> rsplocations;
|
|
}
|
|
#endif
|
|
|
|
const char* GetInstructionName(UGeckoInstruction _inst)
|
|
{
|
|
const GekkoOPInfo* info = GetOpInfo(_inst);
|
|
return info ? info->opname : nullptr;
|
|
}
|
|
|
|
bool IsValidInstruction(UGeckoInstruction _inst)
|
|
{
|
|
const GekkoOPInfo* info = GetOpInfo(_inst);
|
|
return info != nullptr;
|
|
}
|
|
|
|
void CountInstruction(UGeckoInstruction _inst)
|
|
{
|
|
GekkoOPInfo* info = GetOpInfo(_inst);
|
|
if (info)
|
|
{
|
|
info->runCount++;
|
|
}
|
|
}
|
|
|
|
void PrintInstructionRunCounts()
|
|
{
|
|
typedef std::pair<const char*, u64> OpInfo;
|
|
std::vector<OpInfo> temp;
|
|
temp.reserve(m_numInstructions);
|
|
for (size_t i = 0; i < m_numInstructions; ++i)
|
|
{
|
|
GekkoOPInfo* pInst = m_allInstructions[i];
|
|
temp.emplace_back(pInst->opname, pInst->runCount);
|
|
}
|
|
std::sort(temp.begin(), temp.end(),
|
|
[](const OpInfo& a, const OpInfo& b) { return a.second > b.second; });
|
|
|
|
for (auto& inst : temp)
|
|
{
|
|
if (inst.second == 0)
|
|
break;
|
|
|
|
DEBUG_LOG(POWERPC, "%s : %" PRIu64, inst.first, inst.second);
|
|
}
|
|
}
|
|
|
|
void LogCompiledInstructions()
|
|
{
|
|
static unsigned int time = 0;
|
|
|
|
File::IOFile f(StringFromFormat("%sinst_log%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time),
|
|
"w");
|
|
for (size_t i = 0; i < m_numInstructions; i++)
|
|
{
|
|
GekkoOPInfo* pInst = m_allInstructions[i];
|
|
if (pInst->compileCount > 0)
|
|
{
|
|
fprintf(f.GetHandle(), "%s\t%i\t%" PRId64 "\t%08x\n", pInst->opname, pInst->compileCount,
|
|
pInst->runCount, pInst->lastUse);
|
|
}
|
|
}
|
|
|
|
f.Open(StringFromFormat("%sinst_not%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time), "w");
|
|
for (size_t i = 0; i < m_numInstructions; i++)
|
|
{
|
|
GekkoOPInfo* pInst = m_allInstructions[i];
|
|
if (pInst->compileCount == 0)
|
|
{
|
|
fprintf(f.GetHandle(), "%s\t%i\t%" PRId64 "\n", pInst->opname, pInst->compileCount,
|
|
pInst->runCount);
|
|
}
|
|
}
|
|
|
|
#ifdef OPLOG
|
|
f.Open(StringFromFormat("%s" OP_TO_LOG "_at%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time),
|
|
"w");
|
|
for (auto& rsplocation : rsplocations)
|
|
{
|
|
fprintf(f.GetHandle(), OP_TO_LOG ": %08x\n", rsplocation);
|
|
}
|
|
#endif
|
|
|
|
++time;
|
|
}
|
|
|
|
} // namespace
|