mirror of
https://github.com/stenzek/duckstation.git
synced 2026-04-05 21:50:48 +00:00
Common: Add LoongArch support
This commit is contained in:
committed by
Connor McLaughlin
parent
c41cd7937a
commit
f6d526712e
@@ -25,6 +25,8 @@ elseif(LINUX)
|
||||
set(DEPS_PATH "${CMAKE_SOURCE_DIR}/dep/prebuilt/linux${DEPS_CROSS_PREFIX}-armhf")
|
||||
elseif(CPU_ARCH_ARM64)
|
||||
set(DEPS_PATH "${CMAKE_SOURCE_DIR}/dep/prebuilt/linux${DEPS_CROSS_PREFIX}-arm64")
|
||||
elseif(CPU_ARCH_LOONGARCH64)
|
||||
set(DEPS_PATH "${CMAKE_SOURCE_DIR}/dep/prebuilt/linux${DEPS_CROSS_PREFIX}-loongarch64")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported architecture")
|
||||
endif()
|
||||
|
||||
@@ -110,6 +110,9 @@ function(detect_architecture)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}" PARENT_SCOPE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS}" PARENT_SCOPE)
|
||||
elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "loongarch64")
|
||||
message(STATUS "Building LoongArch 64 binaries.")
|
||||
set(CPU_ARCH_LOONGARCH64 TRUE PARENT_SCOPE)
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown system processor: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
|
||||
@@ -182,6 +182,63 @@ asm(
|
||||
jr ra
|
||||
)");
|
||||
|
||||
#elif defined(__loongarch64)
|
||||
|
||||
asm(
|
||||
"\t.global " PREFIX "fastjmp_set\n"
|
||||
"\t.global " PREFIX "fastjmp_jmp\n"
|
||||
"\t.text\n"
|
||||
"\t.align 16\n"
|
||||
"\t" PREFIX "fastjmp_set:" R"(
|
||||
st.d $sp, $a0, 0
|
||||
st.d $s0, $a0, 8
|
||||
st.d $s1, $a0, 16
|
||||
st.d $s2, $a0, 24
|
||||
st.d $s3, $a0, 32
|
||||
st.d $s4, $a0, 40
|
||||
st.d $s5, $a0, 48
|
||||
st.d $s6, $a0, 56
|
||||
st.d $s7, $a0, 64
|
||||
st.d $s8, $a0, 72
|
||||
st.d $s9, $a0, 80
|
||||
fst.d $fs0, $a0, 88
|
||||
fst.d $fs1, $a0, 96
|
||||
fst.d $fs2, $a0, 104
|
||||
fst.d $fs3, $a0, 112
|
||||
fst.d $fs4, $a0, 120
|
||||
fst.d $fs5, $a0, 128
|
||||
fst.d $fs6, $a0, 136
|
||||
fst.d $fs7, $a0, 144
|
||||
st.d $ra, $a0, 152
|
||||
addi.d $a0, $zero, 0
|
||||
jirl $zero, $ra, 0
|
||||
)"
|
||||
".align 16\n"
|
||||
"\t" PREFIX "fastjmp_jmp:" R"(
|
||||
ld.d $ra, $a0, 152
|
||||
fld.d $fs7, $a0, 144
|
||||
fld.d $fs6, $a0, 136
|
||||
fld.d $fs5, $a0, 128
|
||||
fld.d $fs4, $a0, 120
|
||||
fld.d $fs3, $a0, 112
|
||||
fld.d $fs2, $a0, 104
|
||||
fld.d $fs1, $a0, 96
|
||||
fld.d $fs0, $a0, 88
|
||||
ld.d $s9, $a0, 80
|
||||
ld.d $s8, $a0, 72
|
||||
ld.d $s7, $a0, 64
|
||||
ld.d $s6, $a0, 56
|
||||
ld.d $s5, $a0, 48
|
||||
ld.d $s4, $a0, 40
|
||||
ld.d $s3, $a0, 32
|
||||
ld.d $s2, $a0, 24
|
||||
ld.d $s1, $a0, 16
|
||||
ld.d $s0, $a0, 8
|
||||
ld.d $sp, $a0, 0
|
||||
move $a0, $a1
|
||||
jirl $zero, $ra, 0
|
||||
)");
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ struct fastjmp_buf
|
||||
static constexpr std::size_t BUF_SIZE = 24;
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
static constexpr std::size_t BUF_SIZE = 216;
|
||||
#elif defined(__loongarch64)
|
||||
static constexpr std::size_t BUF_SIZE = 160;
|
||||
#else
|
||||
#error Unknown architecture.
|
||||
#endif
|
||||
|
||||
@@ -140,6 +140,15 @@ ALWAYS_INLINE static void MultiPause()
|
||||
#elif defined(CPU_ARCH_RISCV64)
|
||||
// Probably wrong... pause is optional :/
|
||||
asm volatile("fence" ::: "memory");
|
||||
#elif defined(CPU_ARCH_LOONGARCH64)
|
||||
asm volatile("ibar 0" ::: "memory");
|
||||
asm volatile("ibar 0" ::: "memory");
|
||||
asm volatile("ibar 0" ::: "memory");
|
||||
asm volatile("ibar 0" ::: "memory");
|
||||
asm volatile("ibar 0" ::: "memory");
|
||||
asm volatile("ibar 0" ::: "memory");
|
||||
asm volatile("ibar 0" ::: "memory");
|
||||
asm volatile("ibar 0" ::: "memory");
|
||||
#else
|
||||
#pragma warning("Missing implementation")
|
||||
#endif
|
||||
|
||||
@@ -164,7 +164,7 @@ void MemMap::ReleaseJITMemory(void* ptr, size_t size)
|
||||
ERROR_LOG("Failed to free code pointer {}", static_cast<void*>(ptr));
|
||||
}
|
||||
|
||||
#if defined(CPU_ARCH_ARM32) || defined(CPU_ARCH_ARM64) || defined(CPU_ARCH_RISCV64)
|
||||
#if defined(CPU_ARCH_ARM32) || defined(CPU_ARCH_ARM64) || defined(CPU_ARCH_RISCV64) || defined(CPU_ARCH_LOONGARCH64)
|
||||
|
||||
void MemMap::FlushInstructionCache(void* address, size_t size)
|
||||
{
|
||||
@@ -532,7 +532,7 @@ void MemMap::ReleaseJITMemory(void* ptr, size_t size)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CPU_ARCH_ARM32) || defined(CPU_ARCH_ARM64) || defined(CPU_ARCH_RISCV64)
|
||||
#if defined(CPU_ARCH_ARM32) || defined(CPU_ARCH_ARM64) || defined(CPU_ARCH_RISCV64) || defined(CPU_ARCH_LOONGARCH64)
|
||||
|
||||
void MemMap::FlushInstructionCache(void* address, size_t size)
|
||||
{
|
||||
@@ -820,7 +820,7 @@ void MemMap::ReleaseJITMemory(void* ptr, size_t size)
|
||||
ERROR_LOG("Failed to free code pointer {}", static_cast<void*>(ptr));
|
||||
}
|
||||
|
||||
#if defined(CPU_ARCH_ARM32) || defined(CPU_ARCH_ARM64) || defined(CPU_ARCH_RISCV64)
|
||||
#if defined(CPU_ARCH_ARM32) || defined(CPU_ARCH_ARM64) || defined(CPU_ARCH_RISCV64) || defined(CPU_ARCH_LOONGARCH64)
|
||||
|
||||
void MemMap::FlushInstructionCache(void* address, size_t size)
|
||||
{
|
||||
@@ -905,7 +905,7 @@ void* MemMap::AllocateJITMemory(size_t size)
|
||||
static constexpr size_t assume_binary_size = 64 * 1024 * 1024;
|
||||
static constexpr size_t step = 64 * 1024 * 1024;
|
||||
static constexpr size_t max_displacement = 0x80000000u;
|
||||
#elif defined(CPU_ARCH_ARM64) || defined(CPU_ARCH_RISCV64)
|
||||
#elif defined(CPU_ARCH_ARM64) || defined(CPU_ARCH_RISCV64) || defined(CPU_ARCH_LOONGARCH64)
|
||||
static constexpr size_t assume_binary_size = 16 * 1024 * 1024;
|
||||
static constexpr size_t step = 8 * 1024 * 1024;
|
||||
static constexpr size_t max_displacement =
|
||||
|
||||
@@ -73,7 +73,7 @@ void ReleaseJITMemory(void* ptr, size_t size);
|
||||
|
||||
/// Flushes the instruction cache on the host for the specified range.
|
||||
/// Only needed outside of X86, X86 has coherent D/I cache.
|
||||
#if !defined(CPU_ARCH_ARM32) && !defined(CPU_ARCH_ARM64) && !defined(CPU_ARCH_RISCV64)
|
||||
#if !defined(CPU_ARCH_ARM32) && !defined(CPU_ARCH_ARM64) && !defined(CPU_ARCH_RISCV64) && !defined(CPU_ARCH_LOONGARCH64)
|
||||
// clang-format off
|
||||
ALWAYS_INLINE static void FlushInstructionCache(void* address, size_t size) { }
|
||||
// clang-format on
|
||||
|
||||
@@ -162,6 +162,8 @@ struct dependent_int_false : std::false_type
|
||||
#define CPU_ARCH_ARM32 1
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
#define CPU_ARCH_RISCV64 1
|
||||
#elif defined(__loongarch64)
|
||||
#define CPU_ARCH_LOONGARCH64 1
|
||||
#else
|
||||
#error Unknown architecture.
|
||||
#endif
|
||||
@@ -182,6 +184,8 @@ struct dependent_int_false : std::false_type
|
||||
#define CPU_ARCH_STR "arm64"
|
||||
#elif defined(CPU_ARCH_RISCV64)
|
||||
#define CPU_ARCH_STR "riscv64"
|
||||
#elif defined(CPU_ARCH_LOONGARCH64)
|
||||
#define CPU_ARCH_STR "loongarch64"
|
||||
#else
|
||||
#define CPU_ARCH_STR "Unknown"
|
||||
#endif
|
||||
|
||||
@@ -89,6 +89,8 @@ static constexpr u32 HTTP_POLL_INTERVAL = 10;
|
||||
#define UPDATER_ASSET_FILENAME "DuckStation-armhf.AppImage"
|
||||
#elif defined(CPU_ARCH_RISCV64)
|
||||
#define UPDATER_ASSET_FILENAME "DuckStation-riscv64.AppImage"
|
||||
#elif defined(CPU_ARCH_LOONGARCH64)
|
||||
#define UPDATER_ASSET_FILENAME "DuckStation-loongarch64.AppImage"
|
||||
#endif
|
||||
#endif
|
||||
#ifndef UPDATER_ASSET_FILENAME
|
||||
|
||||
@@ -73,6 +73,109 @@
|
||||
|
||||
return ((bits & 0x7Fu) == 0b0100011u);
|
||||
}
|
||||
#elif defined(CPU_ARCH_LOONGARCH64)
|
||||
[[maybe_unused]] static bool IsStoreInstruction(const void* ptr)
|
||||
{
|
||||
u32 bits;
|
||||
std::memcpy(&bits, ptr, sizeof(bits));
|
||||
|
||||
u32 opcode = bits >> 24;
|
||||
u16 bits31_16 = bits >> 16;
|
||||
|
||||
// st.{b,h,w,d} and stptr.{b,h,w,d}
|
||||
if (opcode == 0x27 || opcode == 0x29 || opcode == 0x2D)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// stx.{b,h,w,d}
|
||||
if ((bits31_16 & 0xFFF0) == 0x3810)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// fst.{s,d}
|
||||
if (opcode == 0x2B && (bits & (1 << 22)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// fstx.{s,d} - bit 3 distinguishes from fldx
|
||||
if ((bits31_16 & 0xFFF8) == 0x3838)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// vst, vstx - vst has bit 22 set; vstx has bit 2 set
|
||||
if (opcode == 0x2C && (bits & (1 << 22)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ((bits31_16 & 0xFFFC) == 0x3844)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// xvst, xvstx - xvst has bits 23,22 set; xvstx has bit 2 set
|
||||
if (opcode == 0x2C && (bits & (1 << 23)) && (bits & (1 << 22)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ((bits31_16 & 0xFFFC) == 0x384C)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// stgt.{b,h,w,d}, stle.{b,h,w,d}
|
||||
if ((bits31_16 & 0xFFFC) >= 0x387C && (bits31_16 & 0xFFFC) <= 0x387F)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// fstgt.{s,d}, fstle.{s,d}
|
||||
if ((bits31_16 & 0xFFFC) >= 0x3874 && (bits31_16 & 0xFFFC) <= 0x3877)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// sc.w, sc.d
|
||||
if (opcode == 0x21 || opcode == 0x23)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// amswap, amadd, amand, amor, amxor, ammax, ammin, amcas, etc.
|
||||
if (bits31_16 >= 0x3858 && bits31_16 <= 0x3871)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// stl.w, str.w, stl.d, str.d
|
||||
if (opcode == 0x2F)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// sc.q, screl.w, screl.d
|
||||
if (bits31_16 == 0x3857)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// vstelm.*, xvstelm.*
|
||||
uint16_t bits31_24 = bits >> 24;
|
||||
if (bits31_24 == 0x31 || bits31_24 == 0x33)
|
||||
{
|
||||
uint32_t bits23_20 = (bits >> 20) & 0xF;
|
||||
// vstelm has sub-opcodes: .b=0x8, .h=0x4, .w=0x2, .d=0x1
|
||||
if (bits23_20 == 0x1 || bits23_20 == 0x2 || bits23_20 == 0x4 || bits23_20 == 0x8)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
@@ -161,6 +264,9 @@ void PageFaultHandler::SignalHandler(int sig, siginfo_t* info, void* ctx)
|
||||
#elif defined(CPU_ARCH_RISCV64)
|
||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext.__gregs[REG_PC]);
|
||||
const bool is_write = IsStoreInstruction(exception_pc);
|
||||
#elif defined(CPU_ARCH_LOONGARCH64)
|
||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext.__pc);
|
||||
const bool is_write = IsStoreInstruction(exception_pc);
|
||||
#else
|
||||
void* const exception_pc = nullptr;
|
||||
const bool is_write = false;
|
||||
|
||||
Reference in New Issue
Block a user