mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Delete remains of support for the MIPS architecture as host
This commit is contained in:
@@ -594,13 +594,6 @@ set(CommonARM64
|
||||
)
|
||||
source_group(ARM64 FILES ${CommonARM64})
|
||||
|
||||
set(CommonMIPS
|
||||
Common/MipsCPUDetect.cpp
|
||||
Common/MipsEmitter.cpp
|
||||
Common/MipsEmitter.h
|
||||
)
|
||||
source_group(MIPS FILES ${CommonMIPS})
|
||||
|
||||
set(CommonRISCV64
|
||||
${CommonJIT}
|
||||
Common/RiscVCPUDetect.cpp
|
||||
@@ -654,7 +647,6 @@ add_library(Common STATIC
|
||||
${CommonX86}
|
||||
${CommonARM}
|
||||
${CommonARM64}
|
||||
${CommonMIPS}
|
||||
${CommonRISCV64}
|
||||
${CommonLOONGARCH64}
|
||||
${CommonD3D}
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "Common/StringUtils.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include "Common/CommonWindows.h"
|
||||
|
||||
#define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set
|
||||
@@ -64,9 +65,10 @@ void do_cpuid(u32 regs[4], u32 cpuid_leaf) {
|
||||
|
||||
#define do_xgetbv _xgetbv
|
||||
|
||||
#else // _WIN32
|
||||
#else // !_WIN32
|
||||
|
||||
#ifdef _M_SSE
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
static uint64_t do_xgetbv(unsigned int index) {
|
||||
@@ -76,8 +78,6 @@ static uint64_t do_xgetbv(unsigned int index) {
|
||||
}
|
||||
#endif // _M_SSE
|
||||
|
||||
#if !PPSSPP_ARCH(MIPS)
|
||||
|
||||
void do_cpuidex(u32 regs[4], u32 cpuid_leaf, u32 ecxval) {
|
||||
#if defined(__i386__) && defined(__PIC__)
|
||||
asm (
|
||||
@@ -98,8 +98,6 @@ void do_cpuid(u32 regs[4], u32 cpuid_leaf)
|
||||
do_cpuidex(regs, cpuid_leaf, 0);
|
||||
}
|
||||
|
||||
#endif // !PPSSPP_ARCH(MIPS)
|
||||
|
||||
#endif // !win32
|
||||
|
||||
#ifndef _XCR_XFEATURE_ENABLED_MASK
|
||||
|
||||
+1
-11
@@ -512,7 +512,6 @@
|
||||
<ClInclude Include="MachineContext.h" />
|
||||
<ClInclude Include="MemArena.h" />
|
||||
<ClInclude Include="MemoryUtil.h" />
|
||||
<ClInclude Include="MipsEmitter.h" />
|
||||
<ClInclude Include="OSVersion.h" />
|
||||
<ClInclude Include="Serialize\SerializeSet.h" />
|
||||
<ClInclude Include="StringUtils.h" />
|
||||
@@ -947,14 +946,6 @@
|
||||
<ClCompile Include="Data\Convert\ColorConv.cpp" />
|
||||
<ClCompile Include="Log\ConsoleListener.cpp" />
|
||||
<ClCompile Include="CPUDetect.cpp" />
|
||||
<ClCompile Include="MipsCPUDetect.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FakeCPUDetect.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@@ -973,7 +964,6 @@
|
||||
<ClCompile Include="MemArenaWin32.cpp" />
|
||||
<ClCompile Include="MemArenaDarwin.cpp" />
|
||||
<ClCompile Include="MemoryUtil.cpp" />
|
||||
<ClCompile Include="MipsEmitter.cpp" />
|
||||
<ClCompile Include="SysError.cpp" />
|
||||
<ClCompile Include="OSVersion.cpp" />
|
||||
<ClCompile Include="StringUtils.cpp" />
|
||||
@@ -1050,4 +1040,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -26,7 +26,6 @@
|
||||
<ClInclude Include="Crypto\sha256.h">
|
||||
<Filter>Crypto</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MipsEmitter.h" />
|
||||
<ClInclude Include="Arm64Emitter.h" />
|
||||
<ClInclude Include="ArmCommon.h" />
|
||||
<ClInclude Include="BitSet.h" />
|
||||
@@ -733,7 +732,6 @@
|
||||
<ClCompile Include="ABI.cpp" />
|
||||
<ClCompile Include="CPUDetect.cpp" />
|
||||
<ClCompile Include="FakeCPUDetect.cpp" />
|
||||
<ClCompile Include="MipsCPUDetect.cpp" />
|
||||
<ClCompile Include="MemoryUtil.cpp" />
|
||||
<ClCompile Include="StringUtils.cpp" />
|
||||
<ClCompile Include="Thunk.cpp" />
|
||||
@@ -750,7 +748,6 @@
|
||||
<ClCompile Include="Crypto\sha256.cpp">
|
||||
<Filter>Crypto</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MipsEmitter.cpp" />
|
||||
<ClCompile Include="Arm64Emitter.cpp" />
|
||||
<ClCompile Include="MemArenaPosix.cpp" />
|
||||
<ClCompile Include="MemArenaWin32.cpp" />
|
||||
@@ -1548,4 +1545,4 @@
|
||||
<Filter>Data\Collections</Filter>
|
||||
</Natvis>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -20,8 +20,6 @@
|
||||
#define REAL_CPUDETECT_AVAIL 1
|
||||
#elif (PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)) && !defined(__EMSCRIPTEN__)
|
||||
#define REAL_CPUDETECT_AVAIL 1
|
||||
#elif PPSSPP_ARCH(MIPS) || PPSSPP_ARCH(MIPS64)
|
||||
#define REAL_CPUDETECT_AVAIL 1
|
||||
#elif PPSSPP_ARCH(RISCV64)
|
||||
#define REAL_CPUDETECT_AVAIL 1
|
||||
#elif PPSSPP_ARCH(LOONGARCH64)
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
// Copyright (C) 2003 Dolphin 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.
|
||||
|
||||
// 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 SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
#if PPSSPP_ARCH(MIPS) || PPSSPP_ARCH(MIPS64)
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/File/FileUtil.h"
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
// Only Linux platforms have /proc/cpuinfo
|
||||
#if defined(__linux__)
|
||||
const char procfile[] = "/proc/cpuinfo";
|
||||
// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu
|
||||
const char syscpupresentfile[] = "/sys/devices/system/cpu/present";
|
||||
|
||||
std::string GetCPUString() {
|
||||
std::string line, marker = "Hardware\t: ";
|
||||
std::string cpu_string = "Unknown";
|
||||
|
||||
std::string procdata;
|
||||
if (!File::ReadSysTextFileToString(procfile, &procdata))
|
||||
return cpu_string;
|
||||
std::istringstream file(procdata);
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line.find(marker) != std::string::npos)
|
||||
{
|
||||
cpu_string = line.substr(marker.length());
|
||||
cpu_string.pop_back(); // Drop the new-line character
|
||||
}
|
||||
}
|
||||
|
||||
return cpu_string;
|
||||
}
|
||||
|
||||
unsigned char GetCPUImplementer()
|
||||
{
|
||||
std::string line, marker = "CPU implementer\t: ";
|
||||
unsigned char implementer = 0;
|
||||
|
||||
std::string procdata;
|
||||
if (!File::ReadSysTextFileToString(procfile, &procdata))
|
||||
return 0;
|
||||
std::istringstream file(procdata);
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line.find(marker) != std::string::npos)
|
||||
{
|
||||
line = line.substr(marker.length());
|
||||
sscanf(line.c_str(), "0x%02hhx", &implementer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return implementer;
|
||||
}
|
||||
|
||||
unsigned short GetCPUPart()
|
||||
{
|
||||
std::string line, marker = "CPU part\t: ";
|
||||
unsigned short part = 0;
|
||||
|
||||
std::string procdata;
|
||||
if (!File::ReadSysTextFileToString(procfile, &procdata))
|
||||
return 0;
|
||||
std::istringstream file(procdata);
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line.find(marker) != std::string::npos)
|
||||
{
|
||||
line = line.substr(marker.length());
|
||||
sscanf(line.c_str(), "0x%03hx", &part);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
bool CheckCPUASE(const std::string& ase)
|
||||
{
|
||||
std::string line, marker = "ASEs implemented\t: ";
|
||||
|
||||
std::string procdata;
|
||||
if (!File::ReadSysTextFileToString(procfile, &procdata))
|
||||
return false;
|
||||
std::istringstream file(procdata);
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line.find(marker) != std::string::npos)
|
||||
{
|
||||
std::stringstream line_stream(line);
|
||||
std::string token;
|
||||
while (std::getline(line_stream, token, ' '))
|
||||
{
|
||||
if (token == ase)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int GetCoreCount()
|
||||
{
|
||||
std::string line, marker = "processor\t: ";
|
||||
int cores = 1;
|
||||
|
||||
std::string presentData;
|
||||
bool presentSuccess = File::ReadSysTextFileToString(syscpupresentfile, &presentData);
|
||||
std::istringstream presentFile(presentData);
|
||||
|
||||
if (presentSuccess) {
|
||||
int low, high, found;
|
||||
std::getline(presentFile, line);
|
||||
found = sscanf(line.c_str(), "%d-%d", &low, &high);
|
||||
if (found == 1)
|
||||
return 1;
|
||||
if (found == 2)
|
||||
return high - low + 1;
|
||||
}
|
||||
|
||||
std::string procdata;
|
||||
if (!File::ReadSysTextFileToString(procfile, &procdata))
|
||||
return 1;
|
||||
std::istringstream file(procdata);
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line.find(marker) != std::string::npos)
|
||||
++cores;
|
||||
}
|
||||
|
||||
return cores;
|
||||
}
|
||||
#endif
|
||||
|
||||
CPUInfo cpu_info;
|
||||
|
||||
CPUInfo::CPUInfo() {
|
||||
Detect();
|
||||
}
|
||||
|
||||
// Detects the various cpu features
|
||||
void CPUInfo::Detect()
|
||||
{
|
||||
// Set some defaults here
|
||||
HTT = false;
|
||||
#if PPSSPP_ARCH(MIPS64)
|
||||
OS64bit = true;
|
||||
CPU64bit = true;
|
||||
Mode64bit = true;
|
||||
#else
|
||||
OS64bit = false;
|
||||
CPU64bit = false;
|
||||
Mode64bit = false;
|
||||
#endif
|
||||
vendor = VENDOR_OTHER;
|
||||
logical_cpu_count = 1;
|
||||
|
||||
// Get the information about the CPU
|
||||
#if !defined(__linux__)
|
||||
// Hardcode this for now
|
||||
bXBurst1 = false;
|
||||
bXBurst2 = false;
|
||||
num_cores = 1;
|
||||
#else // __linux__
|
||||
strncpy(cpu_string, GetCPUString().c_str(), sizeof(cpu_string));
|
||||
bXBurst1 = CheckCPUASE("mxu");
|
||||
bXBurst2 = CheckCPUASE("mxu2");
|
||||
unsigned short CPUPart = GetCPUPart();
|
||||
num_cores = GetCoreCount();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::string> CPUInfo::Features() {
|
||||
std::vector<std::string> features;
|
||||
|
||||
struct Flag {
|
||||
bool &flag;
|
||||
const char *str;
|
||||
};
|
||||
const Flag list[] = {
|
||||
{ bXBurst1, "XBurst1" },
|
||||
{ bXBurst2, "XBurst2" },
|
||||
{ CPU64bit, "64-bit" },
|
||||
};
|
||||
|
||||
for (auto &item : list) {
|
||||
if (item.flag) {
|
||||
features.push_back(item.str);
|
||||
}
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
// Turn the cpu info into a string we can show
|
||||
std::string CPUInfo::Summarize()
|
||||
{
|
||||
std::string sum;
|
||||
if (num_cores == 1)
|
||||
sum = StringFromFormat("%s, %i core", cpu_string, num_cores);
|
||||
else
|
||||
sum = StringFromFormat("%s, %i cores", cpu_string, num_cores);
|
||||
|
||||
auto features = Features();
|
||||
for (std::string &feature : features) {
|
||||
sum += ", " + feature;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
#endif // PPSSPP_ARCH(MIPS) || PPSSPP_ARCH(MIPS64)
|
||||
@@ -1,484 +0,0 @@
|
||||
// Copyright (c) 2014- 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/.
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "Common/MemoryUtil.h"
|
||||
#include "Common/MipsEmitter.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
|
||||
namespace MIPSGen {
|
||||
void MIPSEmitter::SetCodePointer(const u8 *ptr, u8 *writePtr) {
|
||||
code_ = writePtr;
|
||||
lastCacheFlushEnd_ = writePtr;
|
||||
}
|
||||
|
||||
const u8 *MIPSEmitter::GetCodePointer() const {
|
||||
return code_;
|
||||
}
|
||||
|
||||
void MIPSEmitter::ReserveCodeSpace(u32 bytes) {
|
||||
for (u32 i = 0; i < bytes / 4; ++i) {
|
||||
BREAK(0);
|
||||
}
|
||||
}
|
||||
|
||||
const u8 *MIPSEmitter::AlignCode16() {
|
||||
ReserveCodeSpace((-(intptr_t)code_) & 15);
|
||||
return code_;
|
||||
}
|
||||
|
||||
const u8 *MIPSEmitter::AlignCodePage() {
|
||||
// TODO: Assuming code pages ought to be 4K?
|
||||
ReserveCodeSpace((-(intptr_t)code_) & 4095);
|
||||
return code_;
|
||||
}
|
||||
|
||||
const u8 *MIPSEmitter::GetCodePtr() const {
|
||||
return code_;
|
||||
}
|
||||
|
||||
u8 *MIPSEmitter::GetWritableCodePtr() {
|
||||
return code_;
|
||||
}
|
||||
|
||||
void MIPSEmitter::FlushIcache() {
|
||||
FlushIcacheSection(lastCacheFlushEnd_, code_);
|
||||
lastCacheFlushEnd_ = code_;
|
||||
}
|
||||
|
||||
void MIPSEmitter::FlushIcacheSection(u8 *start, u8 *end) {
|
||||
#if PPSSPP_ARCH(MIPS)
|
||||
#ifdef __clang__
|
||||
__clear_cache(start, end);
|
||||
#else
|
||||
__builtin___clear_cache(start, end);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void MIPSEmitter::BREAK(u32 code) {
|
||||
// 000000 iiiiiiiiiiiiiiiiiiii 001101
|
||||
_dbg_assert_msg_(code <= 0xfffff, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 6, code & 0xfffff, 0, 0x0d);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::J(std::function<void ()> delaySlot) {
|
||||
// 000010 iiiiiiiiiiiiiiiiiiiiiiiiii (fix up)
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_26);
|
||||
Write32Fields(26, 0x02);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::J(const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(J(delaySlot), func);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::JAL(std::function<void ()> delaySlot) {
|
||||
// 000011 iiiiiiiiiiiiiiiiiiiiiiiiii (fix up)
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_26);
|
||||
Write32Fields(26, 0x03);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::JAL(const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(JAL(delaySlot), func);
|
||||
}
|
||||
|
||||
void MIPSEmitter::JR(MIPSReg rs, std::function<void ()> delaySlot) {
|
||||
// 000000 sssss xxxxxxxxxx hint- 001000 (hint must be 0.)
|
||||
_dbg_assert_msg_(rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 0, 0x08);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
}
|
||||
|
||||
void MIPSEmitter::JALR(MIPSReg rd, MIPSReg rs, std::function<void ()> delaySlot) {
|
||||
// 000000 sssss xxxxx ddddd hint- 001001 (hint must be 0.)
|
||||
_dbg_assert_msg_(rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 11, rd, 0, 0x09);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::BLTZ(MIPSReg rs, std::function<void ()> delaySlot) {
|
||||
// 000001 sssss xxxxx iiiiiiiiiiiiiii (fix up)
|
||||
_dbg_assert_msg_(rs < F_BASE, "Bad emitter arguments");
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_16);
|
||||
Write32Fields(26, 0x01, 21, rs);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::BLTZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(BLTZ(rs, delaySlot), func);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::BEQ(MIPSReg rs, MIPSReg rt, std::function<void ()> delaySlot) {
|
||||
// 000100 sssss ttttt iiiiiiiiiiiiiii (fix up)
|
||||
_dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments");
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_16);
|
||||
Write32Fields(26, 0x04, 21, rs, 16, rt);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::BEQ(MIPSReg rs, MIPSReg rt, const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(BEQ(rs, rt, delaySlot), func);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::BNE(MIPSReg rs, MIPSReg rt, std::function<void ()> delaySlot) {
|
||||
// 000101 sssss ttttt iiiiiiiiiiiiiii (fix up)
|
||||
_dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments");
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_16);
|
||||
Write32Fields(26, 0x05, 21, rs, 16, rt);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::BNE(MIPSReg rs, MIPSReg rt, const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(BNE(rs, rt, delaySlot), func);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::BLEZ(MIPSReg rs, std::function<void ()> delaySlot) {
|
||||
// 000110 sssss xxxxx iiiiiiiiiiiiiii (fix up)
|
||||
_dbg_assert_msg_(rs < F_BASE, "Bad emitter arguments");
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_16);
|
||||
Write32Fields(26, 0x06, 21, rs);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::BLEZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(BLEZ(rs, delaySlot), func);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::BGTZ(MIPSReg rs, std::function<void ()> delaySlot) {
|
||||
// 000111 sssss xxxxx iiiiiiiiiiiiiii (fix up)
|
||||
_dbg_assert_msg_(rs < F_BASE, "Bad emitter arguments");
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_16);
|
||||
Write32Fields(26, 0x07, 21, rs);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::BGTZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(BGTZ(rs, delaySlot), func);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SetJumpTarget(const FixupBranch &branch) {
|
||||
SetJumpTarget(branch, code_);
|
||||
}
|
||||
|
||||
bool MIPSEmitter::BInRange(const void *func) {
|
||||
return BInRange(code_, func);
|
||||
}
|
||||
|
||||
bool MIPSEmitter::JInRange(const void *func) {
|
||||
return JInRange(code_, func);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SetJumpTarget(const FixupBranch &branch, const void *dst) {
|
||||
const intptr_t srcp = (intptr_t)branch.ptr;
|
||||
const intptr_t dstp = (intptr_t)dst;
|
||||
u32 *fixup = (u32 *)branch.ptr;
|
||||
|
||||
_dbg_assert_msg_((dstp & 3) == 0, "Destination should be aligned");
|
||||
|
||||
if (branch.type == BRANCH_16) {
|
||||
// The distance is encoded as words from the delay slot.
|
||||
ptrdiff_t distance = (dstp - srcp - 4) >> 2;
|
||||
_dbg_assert_msg_(BInRange(branch.ptr, dst), "Destination is too far away (%p -> %p)", branch.ptr, dst);
|
||||
*fixup = (*fixup & 0xffff0000) | (distance & 0x0000ffff);
|
||||
} else {
|
||||
// Absolute, easy.
|
||||
_dbg_assert_msg_(JInRange(branch.ptr, dst), "Destination is too far away (%p -> %p)", branch.ptr, dst);
|
||||
*fixup = (*fixup & 0xfc000000) | ((dstp >> 2) & 0x03ffffff);
|
||||
}
|
||||
}
|
||||
|
||||
bool MIPSEmitter::BInRange(const void *src, const void *dst) {
|
||||
const intptr_t srcp = (intptr_t)src;
|
||||
const intptr_t dstp = (intptr_t)dst;
|
||||
|
||||
// The distance is encoded as words from the delay slot.
|
||||
ptrdiff_t distance = (dstp - srcp - 4) >> 2;
|
||||
return distance >= -0x8000 && distance < 0x8000;
|
||||
}
|
||||
|
||||
bool MIPSEmitter::JInRange(const void *src, const void *dst) {
|
||||
const intptr_t srcp = (intptr_t)src;
|
||||
const intptr_t dstp = (intptr_t)dst;
|
||||
|
||||
return (srcp - (srcp & 0x0fffffff)) == (dstp - (dstp & 0x0fffffff));
|
||||
}
|
||||
|
||||
void MIPSEmitter::ApplyDelaySlot(std::function<void ()> delaySlot) {
|
||||
if (delaySlot) {
|
||||
delaySlot();
|
||||
} else {
|
||||
// We just insert a NOP if there's no delay slot provided. Safer.
|
||||
NOP();
|
||||
}
|
||||
}
|
||||
|
||||
void MIPSEmitter::QuickCallFunction(MIPSReg scratchreg, const void *func) {
|
||||
_dbg_assert_msg_(scratchreg < F_BASE, "Bad emitter arguments");
|
||||
if (JInRange(func)) {
|
||||
JAL(func);
|
||||
} else {
|
||||
// This may never happen.
|
||||
MOVP2R(scratchreg, func);
|
||||
JALR(scratchreg);
|
||||
}
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::MakeFixupBranch(FixupBranchType type) const {
|
||||
FixupBranch b;
|
||||
b.ptr = code_;
|
||||
b.type = type;
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::LB(MIPSReg value, MIPSReg base, s16 offset) {
|
||||
// 100000 sssss ttttt iiiiiiiiiiiiiiii - rs = base, rt = value
|
||||
_dbg_assert_msg_(value < F_BASE && base < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x20, 21, base, 16, value, 0, (u16)offset);
|
||||
}
|
||||
|
||||
void MIPSEmitter::LH(MIPSReg value, MIPSReg base, s16 offset) {
|
||||
// 100001 sssss ttttt iiiiiiiiiiiiiiii - rs = base, rt = value
|
||||
_dbg_assert_msg_(value < F_BASE && base < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x21, 21, base, 16, value, 0, (u16)offset);
|
||||
}
|
||||
|
||||
void MIPSEmitter::LW(MIPSReg value, MIPSReg base, s16 offset) {
|
||||
// 100011 sssss ttttt iiiiiiiiiiiiiiii - rs = base, rt = value
|
||||
_dbg_assert_msg_(value < F_BASE && base < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x23, 21, base, 16, value, 0, (u16)offset);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SB(MIPSReg value, MIPSReg base, s16 offset) {
|
||||
// 101000 sssss ttttt iiiiiiiiiiiiiiii - rs = base, rt = value
|
||||
_dbg_assert_msg_(value < F_BASE && base < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x28, 21, base, 16, value, 0, (u16)offset);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SH(MIPSReg value, MIPSReg base, s16 offset) {
|
||||
// 101001 sssss ttttt iiiiiiiiiiiiiiii - rs = base, rt = value
|
||||
_dbg_assert_msg_(value < F_BASE && base < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x29, 21, base, 16, value, 0, (u16)offset);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SW(MIPSReg value, MIPSReg base, s16 offset) {
|
||||
// 101011 sssss ttttt iiiiiiiiiiiiiiii - rs = base, rt = value
|
||||
_dbg_assert_msg_(value < F_BASE && base < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x2b, 21, base, 16, value, 0, (u16)offset);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SLL(MIPSReg rd, MIPSReg rt, u8 sa) {
|
||||
// 000000 xxxxx ttttt ddddd aaaaa 000000
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && sa <= 0x1f, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 16, rt, 11, rd, 6, sa & 0x1f, 0, 0x00);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SRL(MIPSReg rd, MIPSReg rt, u8 sa) {
|
||||
// 000000 xxxxx ttttt ddddd aaaaa 000010
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && sa <= 0x1f, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 16, rt, 11, rd, 6, sa & 0x1f, 0, 0x02);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SRA(MIPSReg rd, MIPSReg rt, u8 sa) {
|
||||
// 000000 xxxxx ttttt ddddd aaaaa 000011
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && sa <= 0x1f, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 16, rt, 11, rd, 6, sa & 0x1f, 0, 0x03);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SLLV(MIPSReg rd, MIPSReg rt, MIPSReg rs) {
|
||||
// 000000 sssss ttttt ddddd xxxxx 000100
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x04);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SRLV(MIPSReg rd, MIPSReg rt, MIPSReg rs) {
|
||||
// 000000 sssss ttttt ddddd xxxxx 000110
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x06);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SRAV(MIPSReg rd, MIPSReg rt, MIPSReg rs) {
|
||||
// 000000 sssss ttttt ddddd xxxxx 000111
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x07);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SLT(MIPSReg rd, MIPSReg rs, MIPSReg rt) {
|
||||
// 000000 sssss ttttt ddddd xxxxx 101010
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x2a);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SLTU(MIPSReg rd, MIPSReg rs, MIPSReg rt) {
|
||||
// 000000 sssss ttttt ddddd xxxxx 101011
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x2b);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SLTI(MIPSReg rt, MIPSReg rs, s16 imm) {
|
||||
// 001010 sssss ttttt iiiiiiiiiiiiiiii
|
||||
_dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x0a, 21, rs, 16, rt, 0, (u16)imm);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SLTIU(MIPSReg rt, MIPSReg rs, s16 imm) {
|
||||
// 001011 sssss ttttt iiiiiiiiiiiiiiii
|
||||
_dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x0b, 21, rs, 16, rt, 0, (u16)imm);
|
||||
}
|
||||
|
||||
void MIPSEmitter::ADDU(MIPSReg rd, MIPSReg rs, MIPSReg rt) {
|
||||
// 000000 sssss ttttt ddddd 00000100001
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x21);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SUBU(MIPSReg rd, MIPSReg rs, MIPSReg rt) {
|
||||
// 000000 sssss ttttt ddddd 00000100011
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x23);
|
||||
}
|
||||
|
||||
void MIPSEmitter::ADDIU(MIPSReg rt, MIPSReg rs, s16 imm) {
|
||||
// 001001 sssss ttttt iiiiiiiiiiiiiiii
|
||||
_dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x09, 21, rs, 16, rt, 0, (u16)imm);
|
||||
}
|
||||
|
||||
void MIPSEmitter::AND(MIPSReg rd, MIPSReg rs, MIPSReg rt) {
|
||||
// 000000 sssss ttttt ddddd 00000100100
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x24);
|
||||
}
|
||||
|
||||
void MIPSEmitter::OR(MIPSReg rd, MIPSReg rs, MIPSReg rt) {
|
||||
// 000000 sssss ttttt ddddd 00000100101
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x25);
|
||||
}
|
||||
|
||||
void MIPSEmitter::XOR(MIPSReg rd, MIPSReg rs, MIPSReg rt) {
|
||||
// 000000 sssss ttttt ddddd 00000100110
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x26);
|
||||
}
|
||||
|
||||
void MIPSEmitter::ANDI(MIPSReg rt, MIPSReg rs, s16 imm) {
|
||||
// 001100 sssss ttttt iiiiiiiiiiiiiiii
|
||||
_dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x0c, 21, rs, 16, rt, 0, (u16)imm);
|
||||
}
|
||||
|
||||
void MIPSEmitter::ORI(MIPSReg rt, MIPSReg rs, s16 imm) {
|
||||
// 001101 sssss ttttt iiiiiiiiiiiiiiii
|
||||
_dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x0d, 21, rs, 16, rt, 0, (u16)imm);
|
||||
}
|
||||
|
||||
void MIPSEmitter::XORI(MIPSReg rt, MIPSReg rs, s16 imm) {
|
||||
// 001110 sssss ttttt iiiiiiiiiiiiiiii
|
||||
_dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x0e, 21, rs, 16, rt, 0, (u16)imm);
|
||||
}
|
||||
|
||||
void MIPSEmitter::LUI(MIPSReg rt, s16 imm) {
|
||||
// 001111 00000 ttttt iiiiiiiiiiiiiiii
|
||||
_dbg_assert_msg_(rt < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x0f, 16, rt, 0, (u16)imm);
|
||||
}
|
||||
|
||||
void MIPSEmitter::INS(MIPSReg rt, MIPSReg rs, s8 pos, s8 size) {
|
||||
// 011111 sssss ttttt xxxxx yyyyy 000100
|
||||
_dbg_assert_msg_(rt < F_BASE && rs < F_BASE && pos <= 0x1f && (size+pos+1) <= 0x1f, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x1f, 21, rt, 16, rs, 11, (size+pos+1) & 0x1f, 6, pos & 0x1f, 0, 0x04);
|
||||
}
|
||||
|
||||
void MIPSEmitter::EXT(MIPSReg rt, MIPSReg rs, s8 pos, s8 size) {
|
||||
// 111111 sssss ttttt xxxxx yyyyy 000000
|
||||
_dbg_assert_msg_(rt < F_BASE && rs < F_BASE && pos <= 0x1f && size >= 1, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x3f, 21, rt, 16, rs, 11, (size-1) & 0x1f, 6, pos & 0x1f, 0, 0x00);
|
||||
}
|
||||
|
||||
void MIPSEmitter::DSLL(MIPSReg rd, MIPSReg rt, u8 sa) {
|
||||
// 000000 xxxxx ttttt ddddd aaaaa 111000 DSLL
|
||||
// 000000 xxxxx ttttt ddddd aaaaa 111100 DSLL32
|
||||
_dbg_assert_msg_(rd < F_BASE && rt < F_BASE && sa <= 0x3f, "Bad emitter arguments");
|
||||
// TODO: Assert MIPS64.
|
||||
if (sa >= 32) {
|
||||
Write32Fields(26, 0x00, 16, rt, 11, rd, 6, (sa - 32) & 0x1f, 0, 0x3c);
|
||||
} else {
|
||||
Write32Fields(26, 0x00, 16, rt, 11, rd, 6, sa & 0x1f, 0, 0x38);
|
||||
}
|
||||
}
|
||||
|
||||
void MIPSEmitter::MOVI2R(MIPSReg reg, u64 imm) {
|
||||
_dbg_assert_msg_(reg < F_BASE, "Bad emitter arguments");
|
||||
// TODO: Assert MIPS64.
|
||||
|
||||
// Probably better to use a literal pool and load.
|
||||
LUI(reg, imm >> 48);
|
||||
ORI(reg, reg, (imm >> 32) & 0x0000ffff);
|
||||
DSLL(reg, reg, 16);
|
||||
ORI(reg, reg, (imm >> 16) & 0x0000ffff);
|
||||
DSLL(reg, reg, 16);
|
||||
ORI(reg, reg, (imm >> 0) & 0x0000ffff);
|
||||
}
|
||||
|
||||
void MIPSEmitter::MOVI2R(MIPSReg reg, u32 imm) {
|
||||
_dbg_assert_msg_(reg < F_BASE, "Bad emitter arguments");
|
||||
|
||||
if ((imm & 0xffff0000) != 0) {
|
||||
#if 0
|
||||
// TODO: CPUDetect MIPS64. Ideally allow emitter to emit MIPS32 on x64.
|
||||
ORI(reg, R_ZERO, imm >> 16);
|
||||
DSLL(reg, reg, 16);
|
||||
ORI(reg, reg, imm & 0x0000ffff);
|
||||
#else
|
||||
LUI(reg, imm >> 16);
|
||||
ORI(reg, reg, imm & 0x0000ffff);
|
||||
#endif
|
||||
} else {
|
||||
ORI(reg, R_ZERO, imm & 0x0000ffff);
|
||||
}
|
||||
}
|
||||
|
||||
void MIPSCodeBlock::PoisonMemory(int offset) {
|
||||
u32 *ptr = (u32 *)(region + offset);
|
||||
u32 *maxptr = (u32 *)(region + region_size - offset);
|
||||
// If our memory isn't a multiple of u32 then this won't write the last remaining bytes with anything
|
||||
// Less than optimal, but there would be nothing we could do but throw a runtime warning anyway.
|
||||
// AArch64: 0x0000000d = break 0
|
||||
while (ptr < maxptr)
|
||||
*ptr++ = 0x0000000d;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,284 +0,0 @@
|
||||
// Copyright (c) 2014- 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/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Common/CodeBlock.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace MIPSGen {
|
||||
|
||||
enum MIPSReg {
|
||||
R_ZERO = 0,
|
||||
R_AT,
|
||||
V0, V1,
|
||||
|
||||
A0 = 4, A1 = 5, A2 = 6, A3 = 7, A4 = 8, A5 = 9, A6 = 10, A7 = 11,
|
||||
// Alternate names depending on ABI.
|
||||
T0 = 8, T1 = 9, T2 = 10, T3 = 11,
|
||||
|
||||
T4, T5, T6, T7,
|
||||
S0, S1, S2, S3, S4, S5, S6, S7,
|
||||
T8, T9,
|
||||
K0, K1,
|
||||
R_GP, R_SP, R_FP,
|
||||
R_RA,
|
||||
|
||||
F_BASE = 32,
|
||||
F0 = 32, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,
|
||||
F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31,
|
||||
|
||||
INVALID_REG = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
enum {
|
||||
// All 32 except: ZERO, K0/K1 (kernel), RA. The rest are only convention.
|
||||
NUMGPRs = 32 - 1 - 2 - 1,
|
||||
NUMFPRs = 32,
|
||||
};
|
||||
|
||||
enum FixupBranchType {
|
||||
// 16-bit immediate jump/branch (to pc + (simm16 + 1 ops).)
|
||||
BRANCH_16,
|
||||
// 26-bit immediate jump/branch (to pc's 4 high bits + imm * 4.)
|
||||
BRANCH_26,
|
||||
};
|
||||
|
||||
// Beware of delay slots.
|
||||
struct FixupBranch {
|
||||
u8 *ptr;
|
||||
FixupBranchType type;
|
||||
};
|
||||
|
||||
class MIPSEmitter {
|
||||
public:
|
||||
MIPSEmitter() : code_(0), lastCacheFlushEnd_(0) {
|
||||
}
|
||||
MIPSEmitter(u8 *code_ptr) : code_(code_ptr), lastCacheFlushEnd_(code_ptr) {
|
||||
SetCodePointer(code_ptr, code_ptr);
|
||||
}
|
||||
virtual ~MIPSEmitter() {
|
||||
}
|
||||
|
||||
void SetCodePointer(const u8 *ptr, u8 *writePtr);
|
||||
const u8* GetCodePointer() const;
|
||||
|
||||
void ReserveCodeSpace(u32 bytes);
|
||||
const u8 *AlignCode16();
|
||||
const u8 *AlignCodePage();
|
||||
const u8 *GetCodePtr() const;
|
||||
u8 *GetWritableCodePtr();
|
||||
void FlushIcache();
|
||||
void FlushIcacheSection(u8 *start, u8 *end);
|
||||
|
||||
// 20 bits valid in code.
|
||||
void BREAK(u32 code);
|
||||
|
||||
void NOP() {
|
||||
SLL(R_ZERO, R_ZERO, 0);
|
||||
}
|
||||
|
||||
// Note for all branches and jumps:
|
||||
// MIPS has DELAY SLOTS. This emitter makes it so if you forget that, you'll be safe.
|
||||
// If you want to run something inside a delay slot, emit the instruction inside a closure.
|
||||
//
|
||||
// Example: Translates to:
|
||||
// J(&myFunc); J(&myFunc);
|
||||
// ADDU(V0, V0, V1); NOP();
|
||||
// ADDU(V0, V0, V1);
|
||||
//
|
||||
// J(&myFunc, [&] { J(&myFunc);
|
||||
// ADDU(V0, V0, V1); ADDU(V0, V0, V1);
|
||||
// });
|
||||
//
|
||||
// This applies to all J*() and B*() functions (except BREAK(), which is not a branch func.)
|
||||
|
||||
FixupBranch J(std::function<void ()> delaySlot = nullptr);
|
||||
void J(const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
FixupBranch JAL(std::function<void ()> delaySlot = nullptr);
|
||||
void JAL(const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
void JR(MIPSReg rs, std::function<void ()> delaySlot = nullptr);
|
||||
void JRRA(std::function<void ()> delaySlot = nullptr) {
|
||||
JR(R_RA, delaySlot);
|
||||
}
|
||||
void JALR(MIPSReg rd, MIPSReg rs, std::function<void ()> delaySlot = nullptr);
|
||||
void JALR(MIPSReg rs, std::function<void ()> delaySlot = nullptr) {
|
||||
JALR(R_RA, rs, delaySlot);
|
||||
}
|
||||
|
||||
inline FixupBranch B(std::function<void ()> delaySlot = nullptr) {
|
||||
return BEQ(R_ZERO, R_ZERO, delaySlot);
|
||||
}
|
||||
inline void B(const void *func, std::function<void ()> delaySlot = nullptr) {
|
||||
return BEQ(R_ZERO, R_ZERO, func, delaySlot);
|
||||
}
|
||||
FixupBranch BLTZ(MIPSReg rs, std::function<void ()> delaySlot = nullptr);
|
||||
void BLTZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
FixupBranch BEQ(MIPSReg rs, MIPSReg rt, std::function<void ()> delaySlot = nullptr);
|
||||
void BEQ(MIPSReg rs, MIPSReg rt, const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
FixupBranch BNE(MIPSReg rs, MIPSReg rt, std::function<void ()> delaySlot = nullptr);
|
||||
void BNE(MIPSReg rs, MIPSReg rt, const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
inline FixupBranch BEQZ(MIPSReg rs, std::function<void ()> delaySlot = nullptr) {
|
||||
return BEQ(rs, R_ZERO, delaySlot);
|
||||
}
|
||||
inline void BEQZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot = nullptr) {
|
||||
return BEQ(rs, R_ZERO, func, delaySlot);
|
||||
}
|
||||
inline FixupBranch BNEZ(MIPSReg rs, std::function<void ()> delaySlot = nullptr) {
|
||||
return BNE(rs, R_ZERO, delaySlot);
|
||||
}
|
||||
inline void BNEZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot = nullptr) {
|
||||
return BNE(rs, R_ZERO, func, delaySlot);
|
||||
}
|
||||
FixupBranch BLEZ(MIPSReg rs, std::function<void ()> delaySlot = nullptr);
|
||||
void BLEZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
FixupBranch BGTZ(MIPSReg rs, std::function<void ()> delaySlot = nullptr);
|
||||
void BGTZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
|
||||
void SetJumpTarget(const FixupBranch &branch);
|
||||
bool BInRange(const void *func);
|
||||
bool JInRange(const void *func);
|
||||
|
||||
// R_AT is the stereotypical scratch reg, but it is not likely to be used.
|
||||
void QuickCallFunction(MIPSReg scratchreg, const void *func);
|
||||
template <typename T> void QuickCallFunction(MIPSReg scratchreg, T func) {
|
||||
QuickCallFunction(scratchreg, (const void *)func);
|
||||
}
|
||||
|
||||
void LB(MIPSReg dest, MIPSReg base, s16 offset);
|
||||
void LH(MIPSReg dest, MIPSReg base, s16 offset);
|
||||
void LW(MIPSReg dest, MIPSReg base, s16 offset);
|
||||
void SB(MIPSReg value, MIPSReg base, s16 offset);
|
||||
void SH(MIPSReg dest, MIPSReg base, s16 offset);
|
||||
void SW(MIPSReg value, MIPSReg base, s16 offset);
|
||||
|
||||
// These exist for the sole purpose of making compilation fail if you try to load/store from R+R.
|
||||
void LB(MIPSReg dest, MIPSReg base, MIPSReg invalid);
|
||||
void LH(MIPSReg dest, MIPSReg base, MIPSReg invalid);
|
||||
void LW(MIPSReg dest, MIPSReg base, MIPSReg invalid);
|
||||
void SB(MIPSReg value, MIPSReg base, MIPSReg invalid);
|
||||
void SH(MIPSReg dest, MIPSReg base, MIPSReg invalid);
|
||||
void SW(MIPSReg value, MIPSReg base, MIPSReg invalid);
|
||||
|
||||
void SLL(MIPSReg rd, MIPSReg rt, u8 sa);
|
||||
void SRL(MIPSReg rd, MIPSReg rt, u8 sa);
|
||||
void SRA(MIPSReg rd, MIPSReg rt, u8 sa);
|
||||
void SLLV(MIPSReg rd, MIPSReg rt, MIPSReg rs);
|
||||
void SRLV(MIPSReg rd, MIPSReg rt, MIPSReg rs);
|
||||
void SRAV(MIPSReg rd, MIPSReg rt, MIPSReg rs);
|
||||
|
||||
void SLT(MIPSReg rd, MIPSReg rt, MIPSReg rs);
|
||||
void SLTU(MIPSReg rd, MIPSReg rt, MIPSReg rs);
|
||||
void SLTI(MIPSReg rd, MIPSReg rt, s16 imm);
|
||||
// Note: very importantly, *sign* extends imm before an unsigned compare.
|
||||
void SLTIU(MIPSReg rt, MIPSReg rs, s16 imm);
|
||||
|
||||
// ADD/SUB/ADDI intentionally omitted. They are just versions that trap.
|
||||
void ADDU(MIPSReg rd, MIPSReg rs, MIPSReg rt);
|
||||
void SUBU(MIPSReg rd, MIPSReg rs, MIPSReg rt);
|
||||
void ADDIU(MIPSReg rt, MIPSReg rs, s16 imm);
|
||||
void SUBIU(MIPSReg rt, MIPSReg rs, s16 imm) {
|
||||
ADDIU(rt, rs, -imm);
|
||||
}
|
||||
|
||||
void AND(MIPSReg rd, MIPSReg rs, MIPSReg rt);
|
||||
void OR(MIPSReg rd, MIPSReg rs, MIPSReg rt);
|
||||
void XOR(MIPSReg rd, MIPSReg rs, MIPSReg rt);
|
||||
void ANDI(MIPSReg rt, MIPSReg rs, s16 imm);
|
||||
void ORI(MIPSReg rt, MIPSReg rs, s16 imm);
|
||||
void XORI(MIPSReg rt, MIPSReg rs, s16 imm);
|
||||
|
||||
// Clears the lower bits. On MIPS64, the result is sign extended.
|
||||
void LUI(MIPSReg rt, s16 imm);
|
||||
|
||||
void INS(MIPSReg rt, MIPSReg rs, s8 pos, s8 size);
|
||||
void EXT(MIPSReg rt, MIPSReg rs, s8 pos, s8 size);
|
||||
|
||||
// MIPS64 only. Transparently uses DSLL32 to shift 32-63 bits.
|
||||
void DSLL(MIPSReg rd, MIPSReg rt, u8 sa);
|
||||
|
||||
void MOVI2R(MIPSReg reg, u64 val);
|
||||
void MOVI2R(MIPSReg reg, s64 val) {
|
||||
MOVI2R(reg, (u64)val);
|
||||
}
|
||||
void MOVI2R(MIPSReg reg, u32 val);
|
||||
void MOVI2R(MIPSReg reg, s32 val) {
|
||||
MOVI2R(reg, (u32)val);
|
||||
}
|
||||
template <class T> void MOVP2R(MIPSReg reg, T *val) {
|
||||
if (sizeof(uintptr_t) > sizeof(u32)) {
|
||||
MOVI2R(reg, (u64)(intptr_t)(const void *)val);
|
||||
} else {
|
||||
MOVI2R(reg, (u32)(intptr_t)(const void *)val);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
inline void Write32(u32 value) {
|
||||
*code32_++ = value;
|
||||
}
|
||||
|
||||
// Less parenthesis.
|
||||
inline void Write32Fields(u8 pos1, u32 v1) {
|
||||
*code32_++ = (v1 << pos1);
|
||||
}
|
||||
inline void Write32Fields(u8 pos1, u32 v1, u8 pos2, u32 v2) {
|
||||
*code32_++ = (v1 << pos1) | (v2 << pos2);
|
||||
}
|
||||
inline void Write32Fields(u8 pos1, u32 v1, u8 pos2, u32 v2, u8 pos3, u32 v3) {
|
||||
*code32_++ = (v1 << pos1) | (v2 << pos2) | (v3 << pos3);
|
||||
}
|
||||
inline void Write32Fields(u8 pos1, u32 v1, u8 pos2, u32 v2, u8 pos3, u32 v3, u8 pos4, u32 v4) {
|
||||
*code32_++ = (v1 << pos1) | (v2 << pos2) | (v3 << pos3) | (v4 << pos4);
|
||||
}
|
||||
inline void Write32Fields(u8 pos1, u32 v1, u8 pos2, u32 v2, u8 pos3, u32 v3, u8 pos4, u32 v4, u8 pos5, u32 v5) {
|
||||
*code32_++ = (v1 << pos1) | (v2 << pos2) | (v3 << pos3) | (v4 << pos5) | (v5 << pos5);
|
||||
}
|
||||
inline void Write32Fields(u8 pos1, u32 v1, u8 pos2, u32 v2, u8 pos3, u32 v3, u8 pos4, u32 v4, u8 pos5, u32 v5, u8 pos6, u32 v6) {
|
||||
*code32_++ = (v1 << pos1) | (v2 << pos2) | (v3 << pos3) | (v4 << pos5) | (v5 << pos5) | (v6 << pos6);
|
||||
}
|
||||
|
||||
static void SetJumpTarget(const FixupBranch &branch, const void *dst);
|
||||
static bool BInRange(const void *src, const void *dst);
|
||||
static bool JInRange(const void *src, const void *dst);
|
||||
FixupBranch MakeFixupBranch(FixupBranchType type) const;
|
||||
void ApplyDelaySlot(std::function<void ()> delaySlot);
|
||||
|
||||
private:
|
||||
union {
|
||||
u8 *code_;
|
||||
u32 *code32_;
|
||||
};
|
||||
u8 *lastCacheFlushEnd_;
|
||||
};
|
||||
|
||||
// Everything that needs to generate machine code should inherit from this.
|
||||
// You get memory management for free, plus, you can use all the LUI etc functions without
|
||||
// having to prefix them with gen-> or something similar.
|
||||
class MIPSCodeBlock : public CodeBlock<MIPSEmitter> {
|
||||
public:
|
||||
void PoisonMemory(int offset) override;
|
||||
|
||||
protected:
|
||||
u8 *region;
|
||||
size_t region_size;
|
||||
};
|
||||
|
||||
};
|
||||
@@ -41,8 +41,6 @@
|
||||
#include "Common/Arm64Emitter.h"
|
||||
#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
|
||||
#include "Common/x64Emitter.h"
|
||||
#elif PPSSPP_ARCH(MIPS)
|
||||
#include "Common/MipsEmitter.h"
|
||||
#elif PPSSPP_ARCH(RISCV64)
|
||||
#include "Common/RiscVEmitter.h"
|
||||
#elif PPSSPP_ARCH(LOONGARCH64)
|
||||
@@ -61,8 +59,6 @@ typedef ArmGen::ARMXCodeBlock BaseCodeBlock;
|
||||
typedef Arm64Gen::ARM64CodeBlock BaseCodeBlock;
|
||||
#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
|
||||
typedef Gen::XCodeBlock BaseCodeBlock;
|
||||
#elif PPSSPP_ARCH(MIPS)
|
||||
typedef MIPSGen::MIPSCodeBlock BaseCodeBlock;
|
||||
#elif PPSSPP_ARCH(RISCV64)
|
||||
typedef RiscVGen::RiscVCodeBlock BaseCodeBlock;
|
||||
#elif PPSSPP_ARCH(LOONGARCH64)
|
||||
|
||||
@@ -196,7 +196,6 @@
|
||||
<ClInclude Include="..\..\Common\LogReporting.h" />
|
||||
<ClInclude Include="..\..\Common\MemArena.h" />
|
||||
<ClInclude Include="..\..\Common\MemoryUtil.h" />
|
||||
<ClInclude Include="..\..\Common\MipsEmitter.h" />
|
||||
<ClInclude Include="..\..\Common\RiscVEmitter.h" />
|
||||
<ClInclude Include="..\..\Common\OSVersion.h" />
|
||||
<ClInclude Include="..\..\Common\StringUtils.h" />
|
||||
@@ -369,8 +368,6 @@
|
||||
<ClCompile Include="..\..\Common\MemArenaPosix.cpp" />
|
||||
<ClCompile Include="..\..\Common\MemArenaWin32.cpp" />
|
||||
<ClCompile Include="..\..\Common\MemoryUtil.cpp" />
|
||||
<ClCompile Include="..\..\Common\MipsCPUDetect.cpp" />
|
||||
<ClCompile Include="..\..\Common\MipsEmitter.cpp" />
|
||||
<ClCompile Include="..\..\Common\RiscVEmitter.cpp" />
|
||||
<ClCompile Include="..\..\Common\SysError.cpp" />
|
||||
<ClCompile Include="..\..\Common\OSVersion.cpp" />
|
||||
@@ -474,4 +471,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -130,8 +130,6 @@
|
||||
<ClCompile Include="..\..\Common\MemArenaPosix.cpp" />
|
||||
<ClCompile Include="..\..\Common\MemArenaWin32.cpp" />
|
||||
<ClCompile Include="..\..\Common\MemoryUtil.cpp" />
|
||||
<ClCompile Include="..\..\Common\MipsCPUDetect.cpp" />
|
||||
<ClCompile Include="..\..\Common\MipsEmitter.cpp" />
|
||||
<ClCompile Include="..\..\Common\RiscVEmitter.cpp" />
|
||||
<ClCompile Include="..\..\Common\SysError.cpp" />
|
||||
<ClCompile Include="..\..\Common\OSVersion.cpp" />
|
||||
@@ -538,15 +536,13 @@
|
||||
<ClCompile Include="..\..\ext\aemu_postoffice\client\postoffice.c">
|
||||
<Filter>ext\aemu_postoffice</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\ext\aemu_postoffice\client\postoffice_mem_psp.c">
|
||||
<Filter>ext\aemu_postoffice</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\ext\aemu_postoffice\client\sock_impl_windows.c">
|
||||
<Filter>ext\aemu_postoffice</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Common\UI\Notice.cpp">
|
||||
<Filter>UI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\ext\aemu_postoffice\client\postoffice_mem_stdc.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="targetver.h" />
|
||||
@@ -574,7 +570,6 @@
|
||||
<ClInclude Include="..\..\Common\LogReporting.h" />
|
||||
<ClInclude Include="..\..\Common\MemArena.h" />
|
||||
<ClInclude Include="..\..\Common\MemoryUtil.h" />
|
||||
<ClInclude Include="..\..\Common\MipsEmitter.h" />
|
||||
<ClInclude Include="..\..\Common\RiscVEmitter.h" />
|
||||
<ClInclude Include="..\..\Common\OSVersion.h" />
|
||||
<ClInclude Include="..\..\Common\StringUtils.h" />
|
||||
@@ -1047,6 +1042,7 @@
|
||||
<ClInclude Include="..\..\Common\UI\Notice.h">
|
||||
<Filter>UI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Common\Math\fast\fast_matrix.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\ext\libpng17\CMakeLists.txt" />
|
||||
@@ -1089,4 +1085,4 @@
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</Text>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -381,7 +381,6 @@ EXEC_AND_LIB_FILES := \
|
||||
$(SRC)/Common/MemArenaWin32.cpp \
|
||||
$(SRC)/Common/MemArenaPosix.cpp \
|
||||
$(SRC)/Common/MemoryUtil.cpp \
|
||||
$(SRC)/Common/MipsCPUDetect.cpp \
|
||||
$(SRC)/Common/StringUtils.cpp \
|
||||
$(SRC)/Common/SysError.cpp \
|
||||
$(SRC)/Common/TimeUtil.cpp
|
||||
|
||||
@@ -541,7 +541,6 @@ SOURCES_CXX += \
|
||||
$(COMMONDIR)/Log/LogManager.cpp \
|
||||
$(COMMONDIR)/OSVersion.cpp \
|
||||
$(COMMONDIR)/MemoryUtil.cpp \
|
||||
$(COMMONDIR)/MipsCPUDetect.cpp \
|
||||
$(COMMONDIR)/RiscVCPUDetect.cpp \
|
||||
$(COMMONDIR)/LogReporting.cpp \
|
||||
$(COMMONDIR)/SysError.cpp \
|
||||
|
||||
Reference in New Issue
Block a user