mirror of
https://github.com/libretro/ppsspp.git
synced 2025-03-06 15:37:22 +00:00
Add the beginnings of a rudimentary ARM64 disassembler
This commit is contained in:
parent
3aebc06329
commit
8945b2476d
@ -451,6 +451,7 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Util\BlockAllocator.cpp" />
|
||||
<ClCompile Include="Util\DisArm64.cpp" />
|
||||
<ClCompile Include="Util\GameManager.cpp" />
|
||||
<ClCompile Include="Util\PPGeDraw.cpp" />
|
||||
<ClCompile Include="Util\ppge_atlas.cpp" />
|
||||
@ -685,6 +686,7 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Util\BlockAllocator.h" />
|
||||
<ClInclude Include="Util\DisArm64.h" />
|
||||
<ClInclude Include="Util\GameManager.h" />
|
||||
<ClInclude Include="Util\PPGeDraw.h" />
|
||||
<ClInclude Include="Util\ppge_atlas.h" />
|
||||
|
@ -567,6 +567,7 @@
|
||||
<ClCompile Include="MIPS\ARM64\Arm64RegCacheFPU.cpp" />
|
||||
<ClCompile Include="MIPS\ARM64\Arm64Asm.cpp" />
|
||||
<ClCompile Include="MIPS\ARM64\Arm64CompALU.cpp" />
|
||||
<ClCompile Include="Core\Util\DisArm64.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ELF\ElfReader.h">
|
||||
@ -1078,6 +1079,7 @@
|
||||
<ClInclude Include="MIPS\ARM64\Arm64RegCache.h" />
|
||||
<ClInclude Include="MIPS\ARM64\Arm64RegCacheFPU.h" />
|
||||
<ClInclude Include="MIPS\ARM64\Arm64Asm.h" />
|
||||
<ClInclude Include="Core\Util\DisArm64.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
|
@ -73,7 +73,6 @@ using namespace Arm64JitConstants;
|
||||
|
||||
void Arm64Jit::GenerateFixedCode()
|
||||
{
|
||||
|
||||
// Uncomment if you want to see the output...
|
||||
// INFO_LOG(JIT, "THE DISASM ========================");
|
||||
// DisassembleArm(enterCode, GetCodePtr() - enterCode);
|
||||
|
133
Core/Util/DisArm64.cpp
Normal file
133
Core/Util/DisArm64.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
// Basic ARM64 disassembler.
|
||||
// No promises of accuracy, mostly just made to debug JIT code.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Common/StringUtils.h"
|
||||
|
||||
struct Instruction {
|
||||
char text[128];
|
||||
bool undefined;
|
||||
bool badbits;
|
||||
bool oddbits;
|
||||
};
|
||||
|
||||
int SignExtend26(int x) {
|
||||
return (x & 0x02000000) ? (0xFC000000 | x) : x;
|
||||
}
|
||||
|
||||
static void DataProcessingImmediate(uint32_t w, uint64_t addr, Instruction *instr) {
|
||||
snprintf(instr->text, sizeof(instr->text), "(DPI %08x)", w);
|
||||
}
|
||||
|
||||
static void BranchExceptionAndSystem(uint32_t w, uint64_t addr, Instruction *instr) {
|
||||
if (((w >> 26) & 0x1F) == 5) {
|
||||
// Unconditional branch / branch+link
|
||||
int offset = SignExtend26(w & 0x03FFFFFF) << 2;
|
||||
uint64_t target = addr + offset;
|
||||
snprintf(instr->text, sizeof(instr->text), "b%s %08x%08x", (w >> 31) ? "l" : "", (target >> 32), (target & 0xFFFFFFFF));
|
||||
} else {
|
||||
snprintf(instr->text, sizeof(instr->text), "(BRX %08x)", w);
|
||||
}
|
||||
}
|
||||
|
||||
static void LoadStore(uint32_t w, uint64_t addr, Instruction *instr) {
|
||||
snprintf(instr->text, sizeof(instr->text), "(LS %08x)", w);
|
||||
}
|
||||
|
||||
static void DataProcessingRegister(uint32_t w, uint64_t addr, Instruction *instr) {
|
||||
int rd = w & 0x1F;
|
||||
int rn = (w >> 5) & 0x1F;
|
||||
int rm = (w >> 16) & 0x1F;
|
||||
|
||||
if (((w >> 21) & 0xF) == 9) {
|
||||
bool S = (w >> 29) & 1;
|
||||
char r = ((w >> 31) & 1) ? 'x' : 'w';
|
||||
bool sub = (w >> 30) & 1;
|
||||
snprintf(instr->text, sizeof(instr->text), "%s%s %c%d, %c%d, %c%d", sub ? "sub" : "add", S ? "s" : "", r, rd, r, rn, r, rm);
|
||||
} else {
|
||||
snprintf(instr->text, sizeof(instr->text), "(DPR %08x)", w);
|
||||
}
|
||||
}
|
||||
|
||||
static void FPandASIMD1(uint32_t w, uint64_t addr, Instruction *instr) {
|
||||
snprintf(instr->text, sizeof(instr->text), "(FP1 %08x)", w);
|
||||
}
|
||||
|
||||
static void FPandASIMD2(uint32_t w, uint64_t addr, Instruction *instr) {
|
||||
snprintf(instr->text, sizeof(instr->text), "(FP2 %08x)", w);
|
||||
}
|
||||
|
||||
static void DisassembleInstruction(uint32_t w, uint64_t addr, Instruction *instr) {
|
||||
memset(instr, 0, sizeof(*instr));
|
||||
|
||||
// Identify the main encoding groups. See C3.1 A64 instruction index by encoding
|
||||
int id = (w >> 25) & 0xF;
|
||||
switch (id) {
|
||||
case 0: case 1: case 2: case 3: // 00xx
|
||||
instr->undefined = true;
|
||||
break;
|
||||
case 8: case 9:
|
||||
DataProcessingImmediate(w, addr, instr);
|
||||
break;
|
||||
case 0xA: case 0xB:
|
||||
BranchExceptionAndSystem(w, addr, instr);
|
||||
break;
|
||||
case 4: case 6: case 0xC: case 0xE:
|
||||
LoadStore(w, addr, instr);
|
||||
break;
|
||||
case 5: case 0xD:
|
||||
DataProcessingRegister(w, addr, instr);
|
||||
break;
|
||||
case 7:
|
||||
FPandASIMD1(w, addr, instr);
|
||||
break;
|
||||
case 0xF:
|
||||
FPandASIMD2(w, addr, instr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Arm64Dis(uint64_t addr, uint32_t w, char *output, int bufsize, bool includeWord) {
|
||||
Instruction instr;
|
||||
DisassembleInstruction(w, addr, &instr);
|
||||
char temp[256];
|
||||
if (includeWord) {
|
||||
snprintf(output, bufsize, "%08x\t%s", w, instr.text);
|
||||
} else {
|
||||
snprintf(output, bufsize, "%s", instr.text);
|
||||
}
|
||||
if (instr.undefined || instr.badbits || instr.oddbits) {
|
||||
if (instr.undefined) snprintf(output, bufsize, "%08x\t[undefined instr]", w);
|
||||
if (instr.badbits) snprintf(output, bufsize, "%08x\t[illegal bits]", w);
|
||||
|
||||
// strcat(output, " ? (extra bits)");
|
||||
if (instr.oddbits) {
|
||||
snprintf(temp, sizeof(temp), " [unexpected bits %08x]", w);
|
||||
strcat(output, temp);
|
||||
}
|
||||
}
|
||||
// zap tabs
|
||||
while (*output) {
|
||||
if (*output == '\t')
|
||||
*output = ' ';
|
||||
output++;
|
||||
}
|
||||
}
|
24
Core/Util/DisArm64.h
Normal file
24
Core/Util/DisArm64.h
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
// Basic ARM64 disassembler.
|
||||
// No promises of accuracy, mostly just made to debug JIT code.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void Arm64Dis(uint64_t addr, uint32_t w, char *output, int bufsize, bool includeWord);
|
||||
|
@ -614,6 +614,8 @@ void JitCompareScreen::UpdateDisasm() {
|
||||
|
||||
#if defined(ARM)
|
||||
std::vector<std::string> targetDis = DisassembleArm2(block->normalEntry, block->codeSize);
|
||||
#elif defined(ARM64)
|
||||
std::vector<std::string> targetDis = DisassembleArm64(block->normalEntry, block->codeSize);
|
||||
#else
|
||||
std::vector<std::string> targetDis = DisassembleX86(block->normalEntry, block->codeSize);
|
||||
#endif
|
||||
|
39
unittest/TestArm64Emitter.cpp
Normal file
39
unittest/TestArm64Emitter.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "Common/ARM64Emitter.h"
|
||||
#include "Core/MIPS/JitCommon/JitState.h"
|
||||
#include "Core/MIPS/JitCommon/JitCommon.h"
|
||||
#include "Core/MIPS/MIPSVFPUUtils.h"
|
||||
#include "Core/Util/DisArm64.h"
|
||||
|
||||
#include "UnitTest.h"
|
||||
|
||||
static bool CheckLast(Arm64Gen::ARM64XEmitter &emit, const char *comp) {
|
||||
u32 instr;
|
||||
memcpy(&instr, emit.GetCodePtr() - 4, 4);
|
||||
char disasm[512];
|
||||
Arm64Dis(0, instr, disasm, sizeof(disasm), true);
|
||||
EXPECT_EQ_STR(std::string(disasm), std::string(comp));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void DisassembleARMBetween(const u8 *start, const u8 *end) {
|
||||
while (start < end) {
|
||||
char disasm[512];
|
||||
uint32_t instr;
|
||||
memcpy(&instr, start, 4);
|
||||
Arm64Dis(0, instr, disasm, sizeof(disasm), true);
|
||||
printf("%s\n", disasm);
|
||||
start += 4;
|
||||
}
|
||||
}
|
||||
|
||||
bool TestArm64Emitter() {
|
||||
using namespace Arm64Gen;
|
||||
|
||||
u32 code[512];
|
||||
ARM64XEmitter emitter((u8 *)code);
|
||||
emitter.ADD(X1, X2, X30);
|
||||
RET(CheckLast(emitter, "8b3e6041 add x1, x2, x30"));
|
||||
emitter.SUB(W1, W2, W30);
|
||||
RET(CheckLast(emitter, "4b3e4041 sub w1, w2, w30"));
|
||||
return true;
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include "UnitTest.h"
|
||||
|
||||
bool CheckLast(ArmGen::ARMXEmitter &emit, const char *comp) {
|
||||
static bool CheckLast(ArmGen::ARMXEmitter &emit, const char *comp) {
|
||||
u32 instr;
|
||||
memcpy(&instr, emit.GetCodePtr() - 4, 4);
|
||||
char disasm[512];
|
||||
@ -16,7 +16,7 @@ bool CheckLast(ArmGen::ARMXEmitter &emit, const char *comp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DisassembleARMBetween(const u8 *start, const u8 *end) {
|
||||
static void DisassembleARMBetween(const u8 *start, const u8 *end) {
|
||||
while (start < end) {
|
||||
char disasm[512];
|
||||
uint32_t instr;
|
||||
|
@ -369,16 +369,21 @@ struct TestItem {
|
||||
#define TEST_ITEM(name) { #name, &Test ##name, }
|
||||
|
||||
bool TestArmEmitter();
|
||||
bool TestArm64Emitter();
|
||||
bool TestX64Emitter();
|
||||
|
||||
|
||||
TestItem availableTests[] = {
|
||||
TEST_ITEM(Asin),
|
||||
TEST_ITEM(SinCos),
|
||||
#if defined(ARM64) || defined(_M_X64) || defined(_M_IX86)
|
||||
TEST_ITEM(Arm64Emitter),
|
||||
#endif
|
||||
#if defined(ARM) || defined(_M_X64) || defined(_M_IX86)
|
||||
TEST_ITEM(ArmEmitter),
|
||||
#ifndef ARM
|
||||
#endif
|
||||
#if defined(_M_X64) || defined(_M_IX86)
|
||||
TEST_ITEM(X64Emitter),
|
||||
#endif
|
||||
TEST_ITEM(Asin),
|
||||
TEST_ITEM(SinCos),
|
||||
TEST_ITEM(VFPUSinCos),
|
||||
TEST_ITEM(MathUtil),
|
||||
TEST_ITEM(Parsers),
|
||||
|
@ -181,6 +181,7 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\native\ext\glew\glew.c" />
|
||||
<ClCompile Include="JitHarness.cpp" />
|
||||
<ClCompile Include="TestArm64Emitter.cpp" />
|
||||
<ClCompile Include="UnitTest.cpp" />
|
||||
<ClCompile Include="TestArmEmitter.cpp" />
|
||||
<ClCompile Include="TestX64Emitter.cpp" />
|
||||
|
@ -1,14 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="UnitTest.cpp" />
|
||||
<ClCompile Include="..\native\ext\glew\glew.c" />
|
||||
<ClCompile Include="JitHarness.cpp" />
|
||||
<ClCompile Include="TestArmEmitter.cpp" />
|
||||
<ClCompile Include="TestX64Emitter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="JitHarness.h" />
|
||||
<ClInclude Include="UnitTest.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="UnitTest.cpp" />
|
||||
<ClCompile Include="..\native\ext\glew\glew.c" />
|
||||
<ClCompile Include="JitHarness.cpp" />
|
||||
<ClCompile Include="TestArmEmitter.cpp" />
|
||||
<ClCompile Include="TestX64Emitter.cpp" />
|
||||
<ClCompile Include="TestArm64Emitter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="JitHarness.h" />
|
||||
<ClInclude Include="UnitTest.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
x
Reference in New Issue
Block a user