diff --git a/Common/CPUDetect.h b/Common/CPUDetect.h index cdf32bf1b8..36686f38f4 100644 --- a/Common/CPUDetect.h +++ b/Common/CPUDetect.h @@ -97,6 +97,14 @@ struct CPUInfo { bool bXBurst1; bool bXBurst2; + // RiscV specific extension flags. + bool RiscV_M; + bool RiscV_A; + bool RiscV_F; + bool RiscV_D; + bool RiscV_C; + bool RiscV_V; + // 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/RiscVCPUDetect.cpp b/Common/RiscVCPUDetect.cpp index 7a47bd1021..6aeed2e117 100644 --- a/Common/RiscVCPUDetect.cpp +++ b/Common/RiscVCPUDetect.cpp @@ -18,13 +18,16 @@ #include "ppsspp_config.h" #if PPSSPP_ARCH(RISCV64) +#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" -#include -#include // Only Linux platforms have /proc/cpuinfo #if defined(__linux__) @@ -32,30 +35,59 @@ 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 RiscVCPUInfoParser { +public: + RiscVCPUInfoParser(); + + int ProcessorCount(); + int TotalLogicalCount(); + + std::string ISAString(); + +private: + std::vector> cores_; +}; + +RiscVCPUInfoParser::RiscVCPUInfoParser() { + 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 RiscVCPUInfoParser::ProcessorCount() { + // Not using present as that counts the logical CPUs (aka harts.) + static const char *marker = "processor\t: "; + std::set processors; + for (auto core : cores_) { + for (auto line : core) { + if (line.find(marker) != line.npos) + processors.insert(line); + } + } + + return (int)processors.size(); } -int GetCoreCount() -{ - std::string line, marker = "processor\t: "; - int cores = 1; - - std::string presentData; +int RiscVCPUInfoParser::TotalLogicalCount() { + std::string presentData, line; bool presentSuccess = File::ReadFileToString(true, Path(syscpupresentfile), presentData); - std::istringstream presentFile(presentData); - if (presentSuccess) { + std::istringstream presentFile(presentData); + int low, high, found; std::getline(presentFile, line); found = sscanf(line.c_str(), "%d-%d", &low, &high); @@ -65,21 +97,36 @@ int GetCoreCount() return high - low + 1; } - std::string procdata; - if (!File::ReadFileToString(true, Path(procfile), procdata)) - return 1; - std::istringstream file(procdata); - - while (std::getline(file, line)) - { - if (line.find(marker) != std::string::npos) - ++cores; + static const char *marker = "hart\t\t: "; + std::set harts; + for (auto core : cores_) { + for (auto line : core) { + if (line.find(marker) != line.npos) + harts.insert(line); + } } - - return cores; + + return (int)harts.size(); +} + +std::string RiscVCPUInfoParser::ISAString() { + static const char *marker = "isa\t\t: "; + for (auto core : cores_) { + for (auto line : core) { + if (line.find(marker) != line.npos) + return line.substr(strlen(marker)); + } + } + + return "Unknown"; } #endif +static bool ExtensionSupported(unsigned long v, char c) { + unsigned long bit = (v >> (c - 'A')) & 1; + return bit == 1; +} + CPUInfo cpu_info; CPUInfo::CPUInfo() { @@ -101,16 +148,31 @@ void CPUInfo::Detect() Mode64bit = false; #endif vendor = VENDOR_OTHER; - logical_cpu_count = 1; + + // Not sure how to get anything great here. + truncate_cpy(brand_string, "Unknown"); - // Get the information about the CPU #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(); + RiscVCPUInfoParser parser; + num_cores = parser.ProcessorCount(); + logical_cpu_count = parser.TotalLogicalCount() / num_cores; + if (logical_cpu_count <= 0) + logical_cpu_count = 1; + + truncate_cpy(cpu_string, parser.ISAString().c_str()); #endif + + unsigned long hwcap = getauxval(AT_HWCAP); + RiscV_M = ExtensionSupported(hwcap, 'M'); + RiscV_A = ExtensionSupported(hwcap, 'A'); + RiscV_F = ExtensionSupported(hwcap, 'F'); + RiscV_D = ExtensionSupported(hwcap, 'D'); + RiscV_C = ExtensionSupported(hwcap, 'C'); + RiscV_V = ExtensionSupported(hwcap, 'V'); } // Turn the cpu info into a string we can show diff --git a/Common/RiscVEmitter.cpp b/Common/RiscVEmitter.cpp index 93ca51c682..0ec05c1c56 100644 --- a/Common/RiscVEmitter.cpp +++ b/Common/RiscVEmitter.cpp @@ -19,38 +19,38 @@ #include #include #include "Common/BitScan.h" +#include "Common/CPUDetect.h" #include "Common/RiscVEmitter.h" namespace RiscVGen { static inline bool SupportsCompressed() { - // TODO - return true; + return cpu_info.RiscV_C; } static inline uint8_t BitsSupported() { - // TODO - return 64; + return cpu_info.OS64bit ? 64 : 32; } static inline uint8_t FloatBitsSupported() { - // TODO: 0 if not. - return 64; + if (cpu_info.RiscV_D) + return 64; + if (cpu_info.RiscV_F) + return 32; + return 0; } static inline bool SupportsMulDiv() { - // TODO - return true; + return cpu_info.RiscV_M; } static inline bool SupportsAtomic() { - // TODO - return true; + return cpu_info.RiscV_A; } static inline bool SupportsZicsr() { // TODO - return true; + return false; } enum class Opcode32 {