From 161f56e27027de49c7e70c74beba1cf4b0fd46c8 Mon Sep 17 00:00:00 2001 From: KatyushaScarlet Date: Mon, 7 Aug 2023 00:14:56 +0800 Subject: [PATCH 1/4] Add basic support for loongarch64 --- CMakeLists.txt | 19 +++- Common/Common.vcxproj | 1 + Common/Common.vcxproj.filters | 1 + Common/FakeCPUDetect.cpp | 2 + Common/LoongArchCPUDetect.cpp | 121 ++++++++++++++++++++++++++ ext/cmake/cpu_features/CMakeLists.txt | 5 ++ ext/cpu_features | 2 +- ppsspp_config.h | 5 ++ 8 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 Common/LoongArchCPUDetect.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d6033eadafc..a8cd6ccd1d86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,8 @@ if(CMAKE_SYSTEM_PROCESSOR) set(MIPS_DEVICE ON) elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^riscv64") set(RISCV64_DEVICE ON) + elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^loongarch64") + set(LOONGARCH64_DEVICE ON) else() message("Unknown CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") endif() @@ -139,6 +141,7 @@ option(ARMV7 "Set to ON if targeting an ARMv7 processor" ${ARMV7_DEVICE}) option(ARM "Set to ON if targeting an ARM processor" ${ARM_DEVICE}) option(MIPS "Set to ON if targeting a MIPS processor" ${MIPS_DEVICE}) option(RISCV64 "Set to ON if targeting a RISCV64 processor" ${RISCV64_DEVICE}) +option(LOONGARCH64 "Set to ON if targeting a LOONGARCH64 processor" ${LOONGARCH64_DEVICE}) option(X86 "Set to ON if targeting an X86 processor" ${X86_DEVICE}) option(X86_64 "Set to ON if targeting an X86_64 processor" ${X86_64_DEVICE}) # :: Environments @@ -318,6 +321,9 @@ endif() if(RISCV64) message("Generating for RISCV64, ${CMAKE_BUILD_TYPE}") endif() +if(LOONGARCH64) + message("Generating for LOONGARCH64, ${CMAKE_BUILD_TYPE}") +endif() if(X86) message("Generating for x86, ${CMAKE_BUILD_TYPE}") endif() @@ -527,6 +533,14 @@ set(CommonRISCV64 ) source_group(RISCV64 FILES ${CommonRISCV64}) +set(CommonLOONGARCH64 + ${CommonJIT} + Common/LoongArchCPUDetect.cpp + Core/MIPS/fake/FakeJit.cpp + Core/MIPS/fake/FakeJit.h +) +source_group(LOONGARCH64 FILES ${CommonLOONGARCH64}) + if(WIN32) set(CommonD3D Common/GPU/D3D9/D3D9ShaderCompiler.cpp @@ -565,6 +579,7 @@ add_library(Common STATIC ${CommonARM64} ${CommonMIPS} ${CommonRISCV64} + ${CommonLOONGARCH64} ${CommonD3D} ${CommonVR} Common/Serialize/Serializer.cpp @@ -887,6 +902,8 @@ if(USE_FFMPEG) set(PLATFORM_ARCH "linux/mips32") elseif(RISCV64) set(PLATFORM_ARCH "linux/riscv64") + elseif(LOONGARCH64) + set(PLATFORM_ARCH "linux/loongarch64") elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) set(PLATFORM_ARCH "linux/x86_64") elseif(X86) @@ -1478,7 +1495,7 @@ if(LINUX AND NOT ANDROID) endif() set(ATOMIC_LIB) -if(ANDROID OR (LINUX AND ARM_DEVICE) OR (LINUX AND RISCV64)) +if(ANDROID OR (LINUX AND ARM_DEVICE) OR (LINUX AND RISCV64) OR (LINUX AND LOONGARCH64)) set(ATOMIC_LIB atomic) endif() diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index d6f8a1282ff0..e83ebfd5d315 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -941,6 +941,7 @@ + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index 92c8592484d4..288b7dc289e5 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -875,6 +875,7 @@ GPU\Vulkan + GPU\Vulkan diff --git a/Common/FakeCPUDetect.cpp b/Common/FakeCPUDetect.cpp index e57799950ab2..af0ecb9efccb 100644 --- a/Common/FakeCPUDetect.cpp +++ b/Common/FakeCPUDetect.cpp @@ -24,6 +24,8 @@ #define REAL_CPUDETECT_AVAIL 1 #elif PPSSPP_ARCH(RISCV64) #define REAL_CPUDETECT_AVAIL 1 +#elif PPSSPP_ARCH(LOONGARCH64) +#define REAL_CPUDETECT_AVAIL 1 #endif #ifndef REAL_CPUDETECT_AVAIL diff --git a/Common/LoongArchCPUDetect.cpp b/Common/LoongArchCPUDetect.cpp new file mode 100644 index 000000000000..4972d53e94e2 --- /dev/null +++ b/Common/LoongArchCPUDetect.cpp @@ -0,0 +1,121 @@ +// 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(LOONGARCH64) + +#include "ext/cpu_features/include/cpuinfo_loongarch.h" + +#if defined(CPU_FEATURES_OS_LINUX) +#define USE_CPU_FEATURES 1 +#endif + +#include +#include +#include +#include +#include +#include "Common/Common.h" +#include "Common/CPUDetect.h" +#include "Common/StringUtils.h" +#include "Common/File/FileUtil.h" +#include "Common/Data/Encoding/Utf8.h" + +// 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() { + //TODO + std::string cpu_string; + cpu_string = "Unknown"; + return cpu_string; +} + +std::string GetCPUBrandString() { + //TODO + std::string brand_string; + brand_string = "Unknown"; + return brand_string; +} + +int GetCoreCount() { + // TODO + return 4; +} + +#endif + +CPUInfo cpu_info; + +CPUInfo::CPUInfo() { + Detect(); +} + +// Detects the various cpu features +void CPUInfo::Detect() { + // Set some defaults here + HTT = false; +#if PPSSPP_ARCH(LOONGARCH64) + OS64bit = true; + CPU64bit = true; + Mode64bit = true; +#else + OS64bit = false; + CPU64bit = false; + Mode64bit = false; +#endif + vendor = VENDOR_OTHER; + + truncate_cpy(brand_string, "Unknown"); +#if !defined(__linux__) + num_cores = 1; + logical_cpu_count = 1; + truncate_cpy(cpu_string, "Unknown"); +#else // __linux__ + truncate_cpy(cpu_string, GetCPUString().c_str()); + truncate_cpy(brand_string, GetCPUBrandString().c_str()); + num_cores = GetCoreCount(); +#endif +} + +std::vector CPUInfo::Features() { + // TODO + std::vector features; + + + + 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); + + //TODO: parse /proc/cpuinfo + + return sum; +} + +#endif // PPSSPP_ARCH(LOONGARCH64) \ No newline at end of file diff --git a/ext/cmake/cpu_features/CMakeLists.txt b/ext/cmake/cpu_features/CMakeLists.txt index e8bfdc34cfc8..f43b9ac8c895 100644 --- a/ext/cmake/cpu_features/CMakeLists.txt +++ b/ext/cmake/cpu_features/CMakeLists.txt @@ -51,6 +51,7 @@ set(PROCESSOR_IS_X86 FALSE) set(PROCESSOR_IS_POWER FALSE) set(PROCESSOR_IS_S390X FALSE) set(PROCESSOR_IS_RISCV FALSE) +set(PROCESSOR_IS_LOONGARCH64 FALSE) if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips") set(PROCESSOR_IS_MIPS TRUE) @@ -66,6 +67,8 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(s390x)") set(PROCESSOR_IS_S390X TRUE) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^riscv") set(PROCESSOR_IS_RISCV TRUE) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^loongarch64") + set(PROCESSOR_IS_LOONGARCH64 TRUE) endif() macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) @@ -89,6 +92,8 @@ macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/../../cpu_features/include/cpuinfo_s390x.h) elseif(PROCESSOR_IS_RISCV) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/../../cpu_features/include/cpuinfo_riscv.h) + elseif(PROCESSOR_IS_LOONGARCH64) + # TODO else() message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}") endif() diff --git a/ext/cpu_features b/ext/cpu_features index 75ec988188f6..69c9bcd94297 160000 --- a/ext/cpu_features +++ b/ext/cpu_features @@ -1 +1 @@ -Subproject commit 75ec988188f62281efe7bf1d133338751369bb4c +Subproject commit 69c9bcd94297ae0468c34619b1cbb351e40b3e4c diff --git a/ppsspp_config.h b/ppsspp_config.h index e26b1220e1bb..6228d2b55600 100644 --- a/ppsspp_config.h +++ b/ppsspp_config.h @@ -75,6 +75,11 @@ #define PPSSPP_ARCH_64BIT 1 #endif +#if defined(__loongarch64) + //https://github.com/gcc-mirror/gcc/blob/master/gcc/config/loongarch/loongarch-c.cc + #define PPSSPP_ARCH_LOONGARCH64 1 + #define PPSSPP_ARCH_64BIT 1 +#endif // PLATFORM defines #if defined(_WIN32) From f94bbbd747d77382e9000b2d7ec17df0a6a29162 Mon Sep 17 00:00:00 2001 From: KatyushaScarlet Date: Mon, 7 Aug 2023 03:12:28 +0800 Subject: [PATCH 2/4] Fix the definition of logical_cpu_count --- Common/LoongArchCPUDetect.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Common/LoongArchCPUDetect.cpp b/Common/LoongArchCPUDetect.cpp index 4972d53e94e2..8d986a44de55 100644 --- a/Common/LoongArchCPUDetect.cpp +++ b/Common/LoongArchCPUDetect.cpp @@ -92,6 +92,7 @@ void CPUInfo::Detect() { truncate_cpy(cpu_string, GetCPUString().c_str()); truncate_cpy(brand_string, GetCPUBrandString().c_str()); num_cores = GetCoreCount(); + logical_cpu_count = 1; #endif } From f4d1a85af340931d1c1ceffa832d224f3572645a Mon Sep 17 00:00:00 2001 From: KatyushaScarlet Date: Sat, 2 Sep 2023 04:58:32 +0800 Subject: [PATCH 3/4] Detect the number of threads and supported features on LoongArch CPU --- Common/CPUDetect.h | 16 ++++ Common/LoongArchCPUDetect.cpp | 169 ++++++++++++++++++++++++++++------ ext/cpu_features | 2 +- ext/rcheevos | 2 +- 4 files changed, 159 insertions(+), 30 deletions(-) diff --git a/Common/CPUDetect.h b/Common/CPUDetect.h index d6ae56fe2e1c..db1ea377a570 100644 --- a/Common/CPUDetect.h +++ b/Common/CPUDetect.h @@ -115,6 +115,22 @@ struct CPUInfo { bool RiscV_Zbc; bool RiscV_Zbs; + // LoongArch specific extension flags. + bool LOONGARCH_CPUCFG; + bool LOONGARCH_LAM; + bool LOONGARCH_UAL; + bool LOONGARCH_FPU; + bool LOONGARCH_LSX; + bool LOONGARCH_LASX; + bool LOONGARCH_CRC32; + bool LOONGARCH_COMPLEX; + bool LOONGARCH_CRYPTO; + bool LOONGARCH_LVZ; + bool LOONGARCH_LBT_X86; + bool LOONGARCH_LBT_ARM; + bool LOONGARCH_LBT_MIPS; + bool LOONGARCH_PTW; + // Quirks struct { // Samsung Galaxy S7 devices (Exynos 8890) have a big.LITTLE configuration where the cacheline size differs between big and LITTLE. diff --git a/Common/LoongArchCPUDetect.cpp b/Common/LoongArchCPUDetect.cpp index 8d986a44de55..64f4acd9a0fd 100644 --- a/Common/LoongArchCPUDetect.cpp +++ b/Common/LoongArchCPUDetect.cpp @@ -41,27 +41,78 @@ 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() { - //TODO - std::string cpu_string; - cpu_string = "Unknown"; - return cpu_string; +class LoongArchCPUInfoParser { +public: + LoongArchCPUInfoParser(); + + int ProcessorCount(); + int TotalLogicalCount(); + +private: + std::vector> cores_; +}; + +LoongArchCPUInfoParser::LoongArchCPUInfoParser() { + std::string procdata, line; + if (!File::ReadFileToString(true, Path(procfile), procdata)) + return; + + std::istringstream file(procdata); + int index = -1; + while (std::getline(file, line)) { + if (line.length() == 0) { + index = -1; + } else { + if (index == -1) { + index = (int)cores_.size(); + cores_.push_back(std::vector()); + } + cores_[index].push_back(line); + } + } } -std::string GetCPUBrandString() { - //TODO - std::string brand_string; - brand_string = "Unknown"; - return brand_string; +int LoongArchCPUInfoParser::ProcessorCount() { + static const char *marker = "core"; + std::set coreIndex; + for (auto core : cores_) { + for (auto line : core) { + if (line.find(marker) != line.npos) + coreIndex.insert(line); + } + } + + return (int)coreIndex.size(); } -int GetCoreCount() { - // TODO - return 4; +int LoongArchCPUInfoParser::TotalLogicalCount() { + std::string presentData, line; + bool presentSuccess = File::ReadFileToString(true, Path(syscpupresentfile), presentData); + if (presentSuccess) { + std::istringstream presentFile(presentData); + + 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; + } + }else{ + return 1; + } } #endif +static bool ExtensionSupported(unsigned long v, unsigned int i) { + // https://github.com/torvalds/linux/blob/master/arch/loongarch/include/uapi/asm/hwcap.h + unsigned long mask = 1 << i; + return v & mask; +} + CPUInfo cpu_info; CPUInfo::CPUInfo() { @@ -69,7 +120,8 @@ CPUInfo::CPUInfo() { } // Detects the various cpu features -void CPUInfo::Detect() { +void CPUInfo::Detect() +{ // Set some defaults here HTT = false; #if PPSSPP_ARCH(LOONGARCH64) @@ -82,30 +134,89 @@ void CPUInfo::Detect() { Mode64bit = false; #endif vendor = VENDOR_OTHER; - - truncate_cpy(brand_string, "Unknown"); + truncate_cpy(brand_string, "Loongson"); + truncate_cpy(cpu_string, "Loongson"); #if !defined(__linux__) num_cores = 1; logical_cpu_count = 1; + truncate_cpy(brand_string, "Unknown"); truncate_cpy(cpu_string, "Unknown"); #else // __linux__ - truncate_cpy(cpu_string, GetCPUString().c_str()); - truncate_cpy(brand_string, GetCPUBrandString().c_str()); - num_cores = GetCoreCount(); - logical_cpu_count = 1; + LoongArchCPUInfoParser parser; + num_cores = parser.ProcessorCount(); + logical_cpu_count = parser.TotalLogicalCount() / num_cores; + if (logical_cpu_count <= 0) + logical_cpu_count = 1; +#endif + + unsigned long hwcap = getauxval(AT_HWCAP); + LOONGARCH_CPUCFG = true; + LOONGARCH_LAM = ExtensionSupported(hwcap, 1); + LOONGARCH_UAL = ExtensionSupported(hwcap, 2); + LOONGARCH_FPU = ExtensionSupported(hwcap, 3); + LOONGARCH_LSX = ExtensionSupported(hwcap, 4); + LOONGARCH_LASX = ExtensionSupported(hwcap, 5); + LOONGARCH_CRC32 = ExtensionSupported(hwcap, 6); + LOONGARCH_COMPLEX = ExtensionSupported(hwcap, 7); + LOONGARCH_CRYPTO = ExtensionSupported(hwcap, 8); + LOONGARCH_LVZ = ExtensionSupported(hwcap, 9); + LOONGARCH_LBT_X86 = ExtensionSupported(hwcap, 10); + LOONGARCH_LBT_ARM = ExtensionSupported(hwcap, 11); + LOONGARCH_LBT_MIPS = ExtensionSupported(hwcap, 12); + LOONGARCH_PTW = ExtensionSupported(hwcap, 13); + +#ifdef USE_CPU_FEATURES + cpu_features::LoongArchInfo info = cpu_features::GetLoongArchInfo(); + LOONGARCH_CPUCFG = true; + LOONGARCH_LAM = info.features.LAM; + LOONGARCH_UAL = info.features.UAL; + LOONGARCH_FPU = info.features.FPU; + LOONGARCH_LSX = info.features.LSX; + LOONGARCH_LASX = info.features.LASX; + LOONGARCH_CRC32 = info.features.CRC32; + LOONGARCH_COMPLEX = info.features.COMPLEX; + LOONGARCH_CRYPTO = info.features.CRYPTO; + LOONGARCH_LVZ = info.features.LVZ; + LOONGARCH_LBT_X86 = info.features.LBT_X86; + LOONGARCH_LBT_ARM = info.features.LBT_ARM; + LOONGARCH_LBT_MIPS = info.features.LBT_MIPS; + LOONGARCH_PTW = info.features.PTW; #endif } std::vector CPUInfo::Features() { - // TODO - std::vector features; - - +std::vector features; + + struct Flag { + bool &flag; + const char *str; + }; + const Flag list[] = { + { LOONGARCH_CPUCFG, "Identify CPU Features" }, + { LOONGARCH_LAM, "Atomic Memory Access Instructions" }, + { LOONGARCH_UAL, "Non-Aligned Memory Access" }, + { LOONGARCH_FPU, "Basic Floating-Point Instructions" }, + { LOONGARCH_LSX, "Loongson SIMD eXtension" }, + { LOONGARCH_LASX, "Loongson Advanced SIMD eXtension" }, + { LOONGARCH_CRC32, "Cyclic Redundancy Check Instructions" }, + { LOONGARCH_COMPLEX, "Complex Vector Operation Instructions" }, + { LOONGARCH_CRYPTO, "Encryption And Decryption Vector Instructions" }, + { LOONGARCH_LVZ, "Virtualization" }, + { LOONGARCH_LBT_X86, "X86 Binary Translation Extension" }, + { LOONGARCH_LBT_ARM, "ARM Binary Translation Extension" }, + { LOONGARCH_LBT_MIPS, "MIPS Binary Translation Extension" }, + { LOONGARCH_PTW, "Page Table Walker" }, + }; + + 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; @@ -114,9 +225,11 @@ std::string CPUInfo::Summarize() { else sum = StringFromFormat("%s, %i cores", cpu_string, num_cores); - //TODO: parse /proc/cpuinfo - + auto features = Features(); + for (std::string &feature : features) { + sum += ", " + feature; + } return sum; } -#endif // PPSSPP_ARCH(LOONGARCH64) \ No newline at end of file +#endif // PPSSPP_ARCH(LOONGARCH64) diff --git a/ext/cpu_features b/ext/cpu_features index 69c9bcd94297..fd4ffc1632db 160000 --- a/ext/cpu_features +++ b/ext/cpu_features @@ -1 +1 @@ -Subproject commit 69c9bcd94297ae0468c34619b1cbb351e40b3e4c +Subproject commit fd4ffc1632db7b4e763bd28ffa6fc9d761cf3587 diff --git a/ext/rcheevos b/ext/rcheevos index 813163c10c07..97db619aa4de 160000 --- a/ext/rcheevos +++ b/ext/rcheevos @@ -1 +1 @@ -Subproject commit 813163c10c0745322affb8342ca2ab3bb30bfcbf +Subproject commit 97db619aa4de15fe19887255e75899ae65d2e432 From 568b3eaff9125977a3f67adbc0b49fb5e5cc1311 Mon Sep 17 00:00:00 2001 From: KatyushaScarlet Date: Sat, 2 Sep 2023 14:04:38 +0800 Subject: [PATCH 4/4] Bump rcheevos --- ext/rcheevos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/rcheevos b/ext/rcheevos index 97db619aa4de..813163c10c07 160000 --- a/ext/rcheevos +++ b/ext/rcheevos @@ -1 +1 @@ -Subproject commit 97db619aa4de15fe19887255e75899ae65d2e432 +Subproject commit 813163c10c0745322affb8342ca2ab3bb30bfcbf