From cb2c7aa278ba3d7b46484cb67122da2a06815245 Mon Sep 17 00:00:00 2001 From: DaniAffCH Date: Sun, 7 Aug 2022 22:42:47 +0200 Subject: [PATCH 1/9] Add RISC-V support --- CMakeLists.txt | 5 ++ README.md | 38 ++++++----- include/cpuinfo_riscv.h | 72 ++++++++++++++++++++ include/internal/hwcaps.h | 3 + scripts/generate_badges.d | 3 +- src/impl_riscv_linux.c | 101 +++++++++++++++++++++++++++ src/utils/list_cpu_features.c | 11 +++ test/CMakeLists.txt | 7 ++ test/cpuinfo_riscv_test.cc | 125 ++++++++++++++++++++++++++++++++++ 9 files changed, 346 insertions(+), 19 deletions(-) create mode 100644 include/cpuinfo_riscv.h create mode 100644 src/impl_riscv_linux.c create mode 100644 test/cpuinfo_riscv_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index e2ffbe2f..b1677c27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ set(PROCESSOR_IS_AARCH64 FALSE) set(PROCESSOR_IS_X86 FALSE) set(PROCESSOR_IS_POWER FALSE) set(PROCESSOR_IS_S390X FALSE) +set(PROCESSOR_IS_RISCV FALSE) if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips") set(PROCESSOR_IS_MIPS TRUE) @@ -63,6 +64,8 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)") set(PROCESSOR_IS_POWER TRUE) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(s390x)") set(PROCESSOR_IS_S390X TRUE) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^riscv") + set(PROCESSOR_IS_RISCV TRUE) endif() macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) @@ -84,6 +87,8 @@ macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_ppc.h) elseif(PROCESSOR_IS_S390X) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_s390x.h) + elseif(PROCESSOR_IS_RISCV) + list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_riscv.h) else() message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}") endif() diff --git a/README.md b/README.md index f37d29b2..94751239 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,12 @@ instructions) at runtime. [comment]: <> (The following lines are generated by "scripts/generate_badges.d" that you can run online https://run.dlang.io/) -| Os | amd64 | AArch64 | ARM | MIPS | s390x | POWER | -| :-- | --: | --: | --: | --: | --: | --: | -| Linux | [![][i1a0]][l1a0]
[![][i1a1]][l1a1] | [![][i1b0]][l1b0]
![][d1] | [![][i1c0]][l1c0]
![][d1] | [![][i1d0]][l1d0]
![][d1] | [![][i1e0]][l1e0]
![][d1] | [![][i1f0]][l1f0]
![][d1] | -| FreeBSD | [![][i2a0]][l2a0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | -| MacOS | [![][i3a0]][l3a0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | -| Windows | [![][i4a0]][l4a0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | +| Os | amd64 | AArch64 | ARM | MIPS | POWER | RISCV | s390x | +| :-- | --: | --: | --: | --: | --: | --: | --: | +| Linux | [![][i1a0]][l1a0]
[![][i1a1]][l1a1] | [![][i1b0]][l1b0]
![][d1] | [![][i1c0]][l1c0]
![][d1] | [![][i1d0]][l1d0]
![][d1] | [![][i1e0]][l1e0]
![][d1] | [![][i1f0]][l1f0]
![][d1] | [![][i1g0]][l1g0]
![][d1] | +| FreeBSD | [![][i2a0]][l2a0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | +| MacOS | [![][i3a0]][l3a0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | +| Windows | [![][i4a0]][l4a0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | ![][d0]
![][d1] | [d0]: https://img.shields.io/badge/CMake-N%2FA-lightgrey [d1]: https://img.shields.io/badge/Bazel-N%2FA-lightgrey @@ -21,8 +21,9 @@ instructions) at runtime. [i1b0]: https://img.shields.io/github/workflow/status/google/cpu_features/AArch64%20Linux%20CMake/main?label=CMake [i1c0]: https://img.shields.io/github/workflow/status/google/cpu_features/ARM%20Linux%20CMake/main?label=CMake [i1d0]: https://img.shields.io/github/workflow/status/google/cpu_features/MIPS%20Linux%20CMake/main?label=CMake -[i1e0]: https://img.shields.io/github/workflow/status/google/cpu_features/s390x%20Linux%20CMake/main?label=CMake -[i1f0]: https://img.shields.io/github/workflow/status/google/cpu_features/POWER%20Linux%20CMake/main?label=CMake +[i1e0]: https://img.shields.io/github/workflow/status/google/cpu_features/POWER%20Linux%20CMake/main?label=CMake +[i1f0]: https://img.shields.io/github/workflow/status/google/cpu_features/RISCV%20Linux%20CMake/main?label=CMake +[i1g0]: https://img.shields.io/github/workflow/status/google/cpu_features/s390x%20Linux%20CMake/main?label=CMake [i2a0]: https://img.shields.io/github/workflow/status/google/cpu_features/amd64%20FreeBSD%20CMake/main?label=CMake [i3a0]: https://img.shields.io/github/workflow/status/google/cpu_features/amd64%20MacOS%20CMake/main?label=CMake [i4a0]: https://img.shields.io/github/workflow/status/google/cpu_features/amd64%20Windows%20CMake/main?label=CMake @@ -31,8 +32,9 @@ instructions) at runtime. [l1b0]: https://github.com/google/cpu_features/actions/workflows/aarch64_linux_cmake.yml [l1c0]: https://github.com/google/cpu_features/actions/workflows/arm_linux_cmake.yml [l1d0]: https://github.com/google/cpu_features/actions/workflows/mips_linux_cmake.yml -[l1e0]: https://github.com/google/cpu_features/actions/workflows/s390x_linux_cmake.yml -[l1f0]: https://github.com/google/cpu_features/actions/workflows/power_linux_cmake.yml +[l1e0]: https://github.com/google/cpu_features/actions/workflows/power_linux_cmake.yml +[l1f0]: https://github.com/google/cpu_features/actions/workflows/riscv_linux_cmake.yml +[l1g0]: https://github.com/google/cpu_features/actions/workflows/s390x_linux_cmake.yml [l2a0]: https://github.com/google/cpu_features/actions/workflows/amd64_freebsd_cmake.yml [l3a0]: https://github.com/google/cpu_features/actions/workflows/amd64_macos_cmake.yml [l4a0]: https://github.com/google/cpu_features/actions/workflows/amd64_windows_cmake.yml @@ -176,14 +178,14 @@ flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3 ## What's supported -| | x86³ | AArch64 | ARM | MIPS⁴ | s390x | POWER | -|---------|:----:|:-------:|:-------:|:-------:|:-------:|:-------:| -| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | -| FreeBSD | yes² | not yet | not yet | not yet | not yet | not yet | -| MacOs | yes² | not yet | N/A | N/A | no | no | -| Windows | yes² | not yet | not yet | N/A | N/A | N/A | -| Android | yes² | yes¹ | yes¹ | yes¹ | N/A | N/A | -| iOS | N/A | not yet | not yet | N/A | N/A | N/A | +| | x86³ | AArch64 | ARM | MIPS⁴ | s390x | POWER | RISC-V | +|---------|:----:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:| +| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | +| FreeBSD | yes² | not yet | not yet | not yet | not yet | not yet | N/A | +| MacOs | yes² | not yet | N/A | N/A | no | no | N/A | +| Windows | yes² | not yet | not yet | N/A | N/A | N/A | N/A | +| Android | yes² | yes¹ | yes¹ | yes¹ | N/A | N/A | N/A | +| iOS | N/A | not yet | not yet | N/A | N/A | N/A | N/A | 1. **Features revealed from Linux.** We gather data from several sources depending on availability: diff --git a/include/cpuinfo_riscv.h b/include/cpuinfo_riscv.h new file mode 100644 index 00000000..fba88048 --- /dev/null +++ b/include/cpuinfo_riscv.h @@ -0,0 +1,72 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ +#define CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ + +#include "cpu_features_cache_info.h" +#include "cpu_features_macros.h" + +#if !defined(CPU_FEATURES_ARCH_RISCV) +#error "Including cpuinfo_riscv.h from a non-riscv target." +#endif + +CPU_FEATURES_START_CPP_NAMESPACE + +typedef struct { + int riscv32 : 1; // Is a 32 bit architecture + int riscv64 : 1; // Is a 64 bit architecture + int riscv128 : 1; // Is a 128 bit architecture + int a : 1; // Atomic Instructions + int c : 1; // Compressed Instructions + int d : 1; // Double Precision Floating Point + int e : 1; // Base Integer Reduced + int f : 1; // Single Precision Floating Point + int i : 1; // Base Integer + int m : 1; // Integer Multiplication and Division + int v : 1; // Vector Operations + int q : 1; // Quad Precision Floating Point +} RiscvFeatures; + + +typedef struct { + RiscvFeatures features; + char uarch[64]; // 0 terminated string + char vendor[64]; // 0 terminated string +} RiscvInfo; + +typedef enum { + RISCV_32, + RISCV_64, + RISCV_128, + RISCV_A, + RISCV_C, + RISCV_D, + RISCV_E, + RISCV_F, + RISCV_I, + RISCV_M, + RISCV_V, + RISCV_Q, + RISCV_LAST_, +} RiscvFeaturesEnum; + +RiscvInfo GetRiscvInfo(void); +int GetRiscvFeaturesEnumValue(const RiscvFeatures* features, RiscvFeaturesEnum value); +const char* GetRiscvFeaturesEnumName(RiscvFeaturesEnum); + +CPU_FEATURES_END_CPP_NAMESPACE + +#endif // CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ + diff --git a/include/internal/hwcaps.h b/include/internal/hwcaps.h index 5030582f..adb61f88 100644 --- a/include/internal/hwcaps.h +++ b/include/internal/hwcaps.h @@ -205,6 +205,9 @@ CPU_FEATURES_START_CPP_NAMESPACE #define HWCAP_S390_SIE 4194304 // https://elixir.bootlin.com/linux/latest/source/arch/riscv/include/uapi/asm/hwcap.h +#define RISCV_HWCAP_32 0x32 +#define RISCV_HWCAP_64 0x64 +#define RISCV_HWCAP_128 0x128 #define RISCV_HWCAP_A (1UL << ('A' - 'A')) #define RISCV_HWCAP_C (1UL << ('C' - 'A')) #define RISCV_HWCAP_D (1UL << ('D' - 'A')) diff --git a/scripts/generate_badges.d b/scripts/generate_badges.d index 2e357a52..1cb81593 100644 --- a/scripts/generate_badges.d +++ b/scripts/generate_badges.d @@ -18,8 +18,9 @@ enum Cpu AArch64, ARM, MIPS, - s390x, POWER, + RISCV, + s390x, } enum Os diff --git a/src/impl_riscv_linux.c b/src/impl_riscv_linux.c new file mode 100644 index 00000000..8911a84d --- /dev/null +++ b/src/impl_riscv_linux.c @@ -0,0 +1,101 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cpu_features_macros.h" + +#ifdef CPU_FEATURES_ARCH_RISCV +#if defined(CPU_FEATURES_OS_LINUX) + +#include "cpuinfo_riscv.h" + +//////////////////////////////////////////////////////////////////////////////// +// Definitions for introspection. +//////////////////////////////////////////////////////////////////////////////// +#define INTROSPECTION_TABLE \ + LINE(RISCV_32, riscv32, "32", RISCV_HWCAP_32, 0) \ + LINE(RISCV_64, riscv64, "64", RISCV_HWCAP_64, 0) \ + LINE(RISCV_128, riscv128, "128", RISCV_HWCAP_128, 0) \ + LINE(RISCV_A, a, "a", RISCV_HWCAP_A, 0) \ + LINE(RISCV_C, c, "c", RISCV_HWCAP_C, 0) \ + LINE(RISCV_D, d, "d", RISCV_HWCAP_D, 0) \ + LINE(RISCV_E, e, "e", RISCV_HWCAP_E, 0) \ + LINE(RISCV_F, f, "f", RISCV_HWCAP_F, 0) \ + LINE(RISCV_I, i, "i", RISCV_HWCAP_I, 0) \ + LINE(RISCV_M, m, "m", RISCV_HWCAP_M, 0) \ + LINE(RISCV_V, v, "v", RISCV_HWCAP_V, 0) \ + LINE(RISCV_Q, q, "q", RISCV_HWCAP_Q, 0) +#define INTROSPECTION_PREFIX Riscv +#define INTROSPECTION_ENUM_PREFIX RISCV +#include "define_introspection_and_hwcaps.inl" + +//////////////////////////////////////////////////////////////////////////////// +// Implementation. +//////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "internal/filesystem.h" +#include "internal/stack_line_reader.h" + +static const RiscvInfo kEmptyRiscvInfo; + +static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) { + StringView line = result.line; + StringView key, value; + if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { + if (CpuFeatures_StringView_IsEquals(key, str("isa"))) { + // Strip "rv" prefix + if (!CpuFeatures_StringView_StartsWith(value, "rv")) continue; + value = CpuFeatures_StringView_PopFront(value, 2); + for (size_t i = 0; i < RISCV_LAST_; ++i) { + StringView flag = str(kCpuInfoFlags[i]); + bool is_set = CpuFeatures_StringView_IndexOf(value, flag) != -1; + kSetters[i](&info->features, is_set); + } + } + if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) { + int index = CpuFeatures_StringView_IndexOfChar(value, ','); + if (index == -1) continue; + StringView vendor = CpuFeatures_StringView_KeepFront(value, index); + StringView uarch = CpuFeatures_StringView_PopFront(value, index + 1); + CpuFeatures_StringView_CopyString(vendor, info->vendor, + sizeof(info->vendor)); + CpuFeatures_StringView_CopyString(uarch, info->uarch, + sizeof(info->uarch)); + } + } + return !result.eof; +} + +static void FillProcCpuInfoData(RiscvInfo* const info) { + const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); + if (fd >= 0) { + StackLineReader reader; + StackLineReader_Initialize(&reader, fd); + for (;;) { + if (!HandleRiscVLine(StackLineReader_NextLine(&reader), info)) break; + } + CpuFeatures_CloseFile(fd); + } +} + +RiscvInfo GetRiscvInfo(void) { + RiscvInfo info = kEmptyRiscvInfo; + FillProcCpuInfoData(&info); + return info; +} + +#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) +#endif // CPU_FEATURES_ARCH_RISCV diff --git a/src/utils/list_cpu_features.c b/src/utils/list_cpu_features.c index b280f69a..8226d852 100644 --- a/src/utils/list_cpu_features.c +++ b/src/utils/list_cpu_features.c @@ -37,6 +37,8 @@ #include "cpuinfo_ppc.h" #elif defined(CPU_FEATURES_ARCH_S390X) #include "cpuinfo_s390x.h" +#elif defined(CPU_FEATURES_ARCH_RISCV) +#include "cpuinfo_riscv.h" #endif // Design principles @@ -210,6 +212,9 @@ DEFINE_ADD_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures, #elif defined(CPU_FEATURES_ARCH_S390X) DEFINE_ADD_FLAGS(GetS390XFeaturesEnumValue, GetS390XFeaturesEnumName, S390XFeatures, S390X_LAST_) +#elif defined(CPU_FEATURES_ARCH_RISCV) +DEFINE_ADD_FLAGS(GetRiscvFeaturesEnumValue, GetRiscvFeaturesEnumName, RiscvFeatures, + RISCV_LAST_) #endif // Prints a json string with characters escaping. @@ -421,6 +426,12 @@ static Node* CreateTree(void) { AddMapEntry(root, "model", CreateString(strings.type.platform)); AddMapEntry(root, "# processors", CreateInt(strings.num_processors)); AddFlags(root, &info.features); +#elif defined(CPU_FEATURES_ARCH_RISCV) + const RiscvInfo info = GetRiscvInfo(); + AddMapEntry(root, "arch", CreateString("risc-v")); + AddMapEntry(root, "vendor", CreateString(info.vendor)); + AddMapEntry(root, "microarchitecture", CreateString(info.uarch)); + AddFlags(root, &info.features); #endif return root; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a87d18ae..82e129a9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -96,3 +96,10 @@ if(PROCESSOR_IS_S390X) target_link_libraries(cpuinfo_s390x_test all_libraries) add_test(NAME cpuinfo_s390x_test COMMAND cpuinfo_s390x_test) endif() +##------------------------------------------------------------------------------ +## cpuinfo_riscv_test +if(PROCESSOR_IS_RISCV) + add_executable(cpuinfo_riscv_test cpuinfo_riscv_test.cc ../src/impl_riscv_linux.c) + target_link_libraries(cpuinfo_riscv_test all_libraries) + add_test(NAME cpuinfo_riscv_test COMMAND cpuinfo_riscv_test) +endif() diff --git a/test/cpuinfo_riscv_test.cc b/test/cpuinfo_riscv_test.cc new file mode 100644 index 00000000..ff7d9790 --- /dev/null +++ b/test/cpuinfo_riscv_test.cc @@ -0,0 +1,125 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cpuinfo_riscv.h" + +#include "filesystem_for_testing.h" +#include "gtest/gtest.h" +#include "hwcaps_for_testing.h" + +namespace cpu_features { +namespace { + +TEST(CpuinfoRiscvTest, LicheeFromCpuInfo) { + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"(processor : 0 +hart : 0 +isa : rv64imafdc +mmu : sv39 +uarch : thead,c906)"); + const auto info = GetRiscvInfo(); + EXPECT_STREQ(info.uarch, "c906"); + EXPECT_STREQ(info.vendor, "thead"); + + EXPECT_FALSE(info.features.riscv32); + EXPECT_TRUE(info.features.riscv64); + EXPECT_FALSE(info.features.riscv128); + EXPECT_TRUE(info.features.a); + EXPECT_TRUE(info.features.c); + EXPECT_TRUE(info.features.d); + EXPECT_FALSE(info.features.e); + EXPECT_TRUE(info.features.f); + EXPECT_TRUE(info.features.i); + EXPECT_TRUE(info.features.m); + EXPECT_FALSE(info.features.q); + EXPECT_FALSE(info.features.v); +} + +TEST(CpuinfoRiscvTest, KendryteFromCpuInfo) { + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"( +hart : 0 +isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 +mmu : sv39 + +hart : 1 +isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 +mmu : sv39)"); + const auto info = GetRiscvInfo(); + EXPECT_STREQ(info.uarch, ""); + EXPECT_STREQ(info.vendor, ""); + + EXPECT_FALSE(info.features.riscv32); + EXPECT_TRUE(info.features.riscv64); + EXPECT_FALSE(info.features.riscv128); + EXPECT_TRUE(info.features.a); + EXPECT_TRUE(info.features.c); + EXPECT_TRUE(info.features.d); + EXPECT_FALSE(info.features.e); + EXPECT_TRUE(info.features.f); + EXPECT_TRUE(info.features.i); + EXPECT_TRUE(info.features.m); + EXPECT_FALSE(info.features.q); + EXPECT_TRUE(info.features.v); +} + +TEST(CpuinfoRiscvTest, UnknownFromCpuInfo) { + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"( +processor : 0 +hart : 2 +isa : rv64imafdc +mmu : sv39 +uarch : sifive,bullet0 + +processor : 1 +hart : 1 +isa : rv64imafdc +mmu : sv39 +uarch : sifive,bullet0 + +processor : 2 +hart : 3 +isa : rv64imafdc +mmu : sv39 +uarch : sifive,bullet0 + +processor : 3 +hart : 4 +isa : rv64imafdc +mmu : sv39 +uarch : sifive,bullet0)"); + const auto info = GetRiscvInfo(); + EXPECT_STREQ(info.uarch, "bullet0"); + EXPECT_STREQ(info.vendor, "sifive"); + + EXPECT_FALSE(info.features.riscv32); + EXPECT_TRUE(info.features.riscv64); + EXPECT_FALSE(info.features.riscv128); + EXPECT_TRUE(info.features.a); + EXPECT_TRUE(info.features.c); + EXPECT_TRUE(info.features.d); + EXPECT_FALSE(info.features.e); + EXPECT_TRUE(info.features.f); + EXPECT_TRUE(info.features.i); + EXPECT_TRUE(info.features.m); + EXPECT_FALSE(info.features.q); + EXPECT_FALSE(info.features.v); +} + +} // namespace +} // namespace cpu_features From 48be58cdfa1dd502089f14ea718cfdd820feec5a Mon Sep 17 00:00:00 2001 From: Corentin Le Molgat Date: Wed, 2 Nov 2022 17:55:25 +0100 Subject: [PATCH 2/9] Add RISC-V CI Support --- .github/workflows/riscv_linux_cmake.yml | 28 +++++++++++++++++++++++++ cmake/ci/Makefile | 3 +++ scripts/run_integration.sh | 15 +++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 .github/workflows/riscv_linux_cmake.yml diff --git a/.github/workflows/riscv_linux_cmake.yml b/.github/workflows/riscv_linux_cmake.yml new file mode 100644 index 00000000..ef7586ab --- /dev/null +++ b/.github/workflows/riscv_linux_cmake.yml @@ -0,0 +1,28 @@ +name: RISCV Linux CMake + +on: + push: + pull_request: + schedule: + # min hours day(month) month day(week) + - cron: '0 0 7,22 * *' + +jobs: + # Building using the github runner environement directly. + make: + runs-on: ubuntu-latest + strategy: + matrix: + targets: [ + [riscv32], + [riscv64], + ] + fail-fast: false + env: + TARGET: ${{ matrix.targets[0] }} + steps: + - uses: actions/checkout@v2 + - name: Build + run: make --directory=cmake/ci ${TARGET}_build + - name: Test + run: make --directory=cmake/ci ${TARGET}_test diff --git a/cmake/ci/Makefile b/cmake/ci/Makefile index 3ec93cd4..f655fc35 100644 --- a/cmake/ci/Makefile +++ b/cmake/ci/Makefile @@ -55,6 +55,8 @@ help: @echo -e "\t\t${BOLD}ppc${RESET} (bootlin toolchain)" @echo -e "\t\t${BOLD}ppc64${RESET} (bootlin toolchain)" @echo -e "\t\t${BOLD}ppc64le${RESET} (bootlin toolchain)" + @echo -e "\t\t${BOLD}riscv32${RESET} (bootlin toolchain)" + @echo -e "\t\t${BOLD}riscv64${RESET} (bootlin toolchain)" @echo -e "\t\t${BOLD}s390x${RESET} (bootlin toolchain)" @echo @echo -e "\tWith ${BOLD}${RESET}:" @@ -154,6 +156,7 @@ TOOLCHAIN_TARGETS = \ aarch64-linux-gnu aarch64_be-linux-gnu \ mips32 mips32el mips64 mips64el \ ppc ppc64 ppc64le \ + riscv32 riscv64 \ s390x TOOLCHAIN_STAGES = env devel build test define toolchain-stage-target = diff --git a/scripts/run_integration.sh b/scripts/run_integration.sh index 3f84e127..053ffa96 100755 --- a/scripts/run_integration.sh +++ b/scripts/run_integration.sh @@ -162,6 +162,14 @@ function expand_bootlin_config() { local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc-440fp/tarballs/powerpc-440fp--glibc--stable-2021.11-1.tar.bz2" local -r GCC_PREFIX="powerpc" ;; + "riscv32") + local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/riscv32-ilp32d/tarballs/riscv32-ilp32d--glibc--bleeding-edge-2022.08-1.tar.bz2" + local -r GCC_PREFIX="riscv32" + ;; + "riscv64") + local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/riscv64-lp64d/tarballs/riscv64-lp64d--glibc--stable-2022.08-1.tar.bz2" + local -r GCC_PREFIX="riscv64" + ;; "s390x") local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/s390x-z13/tarballs/s390x-z13--glibc--stable-2022.08-1.tar.bz2" local -r GCC_PREFIX="s390x" @@ -362,6 +370,7 @@ DESCRIPTION \t\tmips64 mips64el (codespace) \t\tppc (bootlin) \t\tppc64 ppc64le (bootlin) +\t\triscv32 riscv64 (bootlin) \t\ts390x (bootlin) OPTIONS @@ -448,6 +457,12 @@ function main() { ppc) expand_bootlin_config declare -r QEMU_ARCH=ppc ;; + riscv32) + expand_bootlin_config + declare -r QEMU_ARCH=riscv32 ;; + riscv64) + expand_bootlin_config + declare -r QEMU_ARCH=riscv64 ;; s390x) expand_bootlin_config declare -r QEMU_ARCH=s390x ;; From d096411e222a9b94d72dab66b3513506e27a6b7c Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Wed, 9 Nov 2022 15:53:40 +0000 Subject: [PATCH 3/9] Fix api call --- src/impl_riscv_linux.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/impl_riscv_linux.c b/src/impl_riscv_linux.c index 8911a84d..4f6ae903 100644 --- a/src/impl_riscv_linux.c +++ b/src/impl_riscv_linux.c @@ -56,9 +56,9 @@ static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) { StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { if (CpuFeatures_StringView_IsEquals(key, str("isa"))) { - // Strip "rv" prefix - if (!CpuFeatures_StringView_StartsWith(value, "rv")) continue; - value = CpuFeatures_StringView_PopFront(value, 2); + StringView prefix = str("rv"); + if (!CpuFeatures_StringView_StartsWith(value, prefix)) continue; + value = CpuFeatures_StringView_PopFront(value, prefix.size); for (size_t i = 0; i < RISCV_LAST_; ++i) { StringView flag = str(kCpuInfoFlags[i]); bool is_set = CpuFeatures_StringView_IndexOf(value, flag) != -1; From a0bc97e7af7a654ca137f441e573cebb263d43c2 Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Wed, 9 Nov 2022 16:01:16 +0000 Subject: [PATCH 4/9] Fix early return --- src/impl_riscv_linux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/impl_riscv_linux.c b/src/impl_riscv_linux.c index 4f6ae903..3686697a 100644 --- a/src/impl_riscv_linux.c +++ b/src/impl_riscv_linux.c @@ -57,7 +57,7 @@ static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) { if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { if (CpuFeatures_StringView_IsEquals(key, str("isa"))) { StringView prefix = str("rv"); - if (!CpuFeatures_StringView_StartsWith(value, prefix)) continue; + if (!CpuFeatures_StringView_StartsWith(value, prefix)) return true; value = CpuFeatures_StringView_PopFront(value, prefix.size); for (size_t i = 0; i < RISCV_LAST_; ++i) { StringView flag = str(kCpuInfoFlags[i]); @@ -67,7 +67,7 @@ static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) { } if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) { int index = CpuFeatures_StringView_IndexOfChar(value, ','); - if (index == -1) continue; + if (index == -1) return true; StringView vendor = CpuFeatures_StringView_KeepFront(value, index); StringView uarch = CpuFeatures_StringView_PopFront(value, index + 1); CpuFeatures_StringView_CopyString(vendor, info->vendor, From 9ebd6ce44cc2e314124a04155ddb502f43ac15ec Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Wed, 9 Nov 2022 16:09:41 +0000 Subject: [PATCH 5/9] Fix documentation --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 94751239..91ef3f01 100644 --- a/README.md +++ b/README.md @@ -178,11 +178,11 @@ flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3 ## What's supported -| | x86³ | AArch64 | ARM | MIPS⁴ | s390x | POWER | RISC-V | +| | x86³ | AArch64 | ARM | MIPS⁴ | POWER | RISCV | s390x | |---------|:----:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:| | Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | -| FreeBSD | yes² | not yet | not yet | not yet | not yet | not yet | N/A | -| MacOs | yes² | not yet | N/A | N/A | no | no | N/A | +| FreeBSD | yes² | not yet | not yet | not yet | not yet | N/A | not yet | +| MacOs | yes² | not yet | N/A | N/A | no | N/A | no | | Windows | yes² | not yet | not yet | N/A | N/A | N/A | N/A | | Android | yes² | yes¹ | yes¹ | yes¹ | N/A | N/A | N/A | | iOS | N/A | not yet | not yet | N/A | N/A | N/A | N/A | From f08d0e7ba973b0150fc3f92d1684f724319b9905 Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Mon, 9 Jan 2023 14:15:38 +0000 Subject: [PATCH 6/9] Keep only ratified cpu_features --- include/cpuinfo_riscv.h | 60 ++++++++++--------- include/internal/hwcaps.h | 9 +-- src/impl_riscv_linux.c | 53 ++++++++++------- test/cpuinfo_riscv_test.cc | 116 +++++++++++++++++-------------------- 4 files changed, 117 insertions(+), 121 deletions(-) diff --git a/include/cpuinfo_riscv.h b/include/cpuinfo_riscv.h index fba88048..a51477f4 100644 --- a/include/cpuinfo_riscv.h +++ b/include/cpuinfo_riscv.h @@ -25,48 +25,46 @@ CPU_FEATURES_START_CPP_NAMESPACE typedef struct { - int riscv32 : 1; // Is a 32 bit architecture - int riscv64 : 1; // Is a 64 bit architecture - int riscv128 : 1; // Is a 128 bit architecture - int a : 1; // Atomic Instructions - int c : 1; // Compressed Instructions - int d : 1; // Double Precision Floating Point - int e : 1; // Base Integer Reduced - int f : 1; // Single Precision Floating Point - int i : 1; // Base Integer - int m : 1; // Integer Multiplication and Division - int v : 1; // Vector Operations - int q : 1; // Quad Precision Floating Point -} RiscvFeatures; + // Base + int RV32I : 1; // Base Integer Instruction Set, 32-bit + int RV64I : 1; // Base Integer Instruction Set, 64-bit + // Extension + int M : 1; // Standard Extension for Integer Multiplication/Division + int A : 1; // Standard Extension for Atomic Instructions + int F : 1; // Standard Extension for Single-Precision Floating-Point + int D : 1; // Standard Extension for Double-Precision Floating-Point + int Q : 1; // Standard Extension for Quad-Precision Floating-Point + int C : 1; // Standard Extension for Compressed Instructions + int Zicsr : 1; // Control and Status Register (CSR) + int Zifencei : 1; // Instruction-Fetch Fence +} RiscvFeatures; typedef struct { - RiscvFeatures features; - char uarch[64]; // 0 terminated string - char vendor[64]; // 0 terminated string + RiscvFeatures features; + char uarch[64]; // 0 terminated string + char vendor[64]; // 0 terminated string } RiscvInfo; typedef enum { - RISCV_32, - RISCV_64, - RISCV_128, - RISCV_A, - RISCV_C, - RISCV_D, - RISCV_E, - RISCV_F, - RISCV_I, - RISCV_M, - RISCV_V, - RISCV_Q, - RISCV_LAST_, + RISCV_RV32I, + RISCV_RV64I, + RISCV_M, + RISCV_A, + RISCV_F, + RISCV_D, + RISCV_Q, + RISCV_C, + RISCV_Zicsr, + RISCV_Zifencei, + RISCV_LAST_, } RiscvFeaturesEnum; RiscvInfo GetRiscvInfo(void); -int GetRiscvFeaturesEnumValue(const RiscvFeatures* features, RiscvFeaturesEnum value); +int GetRiscvFeaturesEnumValue(const RiscvFeatures* features, + RiscvFeaturesEnum value); const char* GetRiscvFeaturesEnumName(RiscvFeaturesEnum); CPU_FEATURES_END_CPP_NAMESPACE #endif // CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ - diff --git a/include/internal/hwcaps.h b/include/internal/hwcaps.h index adb61f88..5ce349bd 100644 --- a/include/internal/hwcaps.h +++ b/include/internal/hwcaps.h @@ -208,15 +208,12 @@ CPU_FEATURES_START_CPP_NAMESPACE #define RISCV_HWCAP_32 0x32 #define RISCV_HWCAP_64 0x64 #define RISCV_HWCAP_128 0x128 +#define RISCV_HWCAP_M (1UL << ('M' - 'A')) #define RISCV_HWCAP_A (1UL << ('A' - 'A')) -#define RISCV_HWCAP_C (1UL << ('C' - 'A')) -#define RISCV_HWCAP_D (1UL << ('D' - 'A')) -#define RISCV_HWCAP_E (1UL << ('E' - 'A')) #define RISCV_HWCAP_F (1UL << ('F' - 'A')) -#define RISCV_HWCAP_I (1UL << ('I' - 'A')) -#define RISCV_HWCAP_M (1UL << ('M' - 'A')) -#define RISCV_HWCAP_V (1UL << ('V' - 'A')) +#define RISCV_HWCAP_D (1UL << ('D' - 'A')) #define RISCV_HWCAP_Q (1UL << ('Q' - 'A')) +#define RISCV_HWCAP_C (1UL << ('C' - 'A')) typedef struct { unsigned long hwcaps; diff --git a/src/impl_riscv_linux.c b/src/impl_riscv_linux.c index 3686697a..6f7c45c8 100644 --- a/src/impl_riscv_linux.c +++ b/src/impl_riscv_linux.c @@ -19,22 +19,28 @@ #include "cpuinfo_riscv.h" +// According to +// https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/riscv/cpus.yaml +// isa string should match the following regex +// ^rv(?:64|32)imaf?d?q?c?b?v?k?h?(?:_[hsxz](?:[a-z])+)*$ +// +// This means we can test for features in this exact order except for Z +// extensions. + //////////////////////////////////////////////////////////////////////////////// // Definitions for introspection. //////////////////////////////////////////////////////////////////////////////// #define INTROSPECTION_TABLE \ - LINE(RISCV_32, riscv32, "32", RISCV_HWCAP_32, 0) \ - LINE(RISCV_64, riscv64, "64", RISCV_HWCAP_64, 0) \ - LINE(RISCV_128, riscv128, "128", RISCV_HWCAP_128, 0) \ - LINE(RISCV_A, a, "a", RISCV_HWCAP_A, 0) \ - LINE(RISCV_C, c, "c", RISCV_HWCAP_C, 0) \ - LINE(RISCV_D, d, "d", RISCV_HWCAP_D, 0) \ - LINE(RISCV_E, e, "e", RISCV_HWCAP_E, 0) \ - LINE(RISCV_F, f, "f", RISCV_HWCAP_F, 0) \ - LINE(RISCV_I, i, "i", RISCV_HWCAP_I, 0) \ - LINE(RISCV_M, m, "m", RISCV_HWCAP_M, 0) \ - LINE(RISCV_V, v, "v", RISCV_HWCAP_V, 0) \ - LINE(RISCV_Q, q, "q", RISCV_HWCAP_Q, 0) + LINE(RISCV_RV32I, RV32I, "rv32i", RISCV_HWCAP_32, 0) \ + LINE(RISCV_RV64I, RV64I, "rv64i", RISCV_HWCAP_64, 0) \ + LINE(RISCV_M, M, "m", RISCV_HWCAP_M, 0) \ + LINE(RISCV_A, A, "a", RISCV_HWCAP_A, 0) \ + LINE(RISCV_F, F, "f", RISCV_HWCAP_F, 0) \ + LINE(RISCV_D, D, "d", RISCV_HWCAP_D, 0) \ + LINE(RISCV_Q, Q, "q", RISCV_HWCAP_Q, 0) \ + LINE(RISCV_C, C, "c", RISCV_HWCAP_C, 0) \ + LINE(RISCV_Zicsr, Zicsr, "_zicsr", 0, 0) \ + LINE(RISCV_Zifencei, Zifencei, "_zifencei", 0, 0) #define INTROSPECTION_PREFIX Riscv #define INTROSPECTION_ENUM_PREFIX RISCV #include "define_introspection_and_hwcaps.inl" @@ -51,21 +57,24 @@ static const RiscvInfo kEmptyRiscvInfo; +static void HandleRiscVIsaLine(StringView line, RiscvInfo* const info) { + for (size_t i = 0; i < RISCV_LAST_; ++i) { + StringView flag = str(kCpuInfoFlags[i]); + bool is_set = CpuFeatures_StringView_StartsWith(value, flag); + kSetters[i](&info->features, is_set); + if (is_set) { + line = CpuFeatures_StringView_PopFront(line, flag.size); + } + } +} + static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) { StringView line = result.line; StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { if (CpuFeatures_StringView_IsEquals(key, str("isa"))) { - StringView prefix = str("rv"); - if (!CpuFeatures_StringView_StartsWith(value, prefix)) return true; - value = CpuFeatures_StringView_PopFront(value, prefix.size); - for (size_t i = 0; i < RISCV_LAST_; ++i) { - StringView flag = str(kCpuInfoFlags[i]); - bool is_set = CpuFeatures_StringView_IndexOf(value, flag) != -1; - kSetters[i](&info->features, is_set); - } - } - if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) { + HandleRiscVIsaLine(); + } else if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) { int index = CpuFeatures_StringView_IndexOfChar(value, ','); if (index == -1) return true; StringView vendor = CpuFeatures_StringView_KeepFront(value, index); diff --git a/test/cpuinfo_riscv_test.cc b/test/cpuinfo_riscv_test.cc index ff7d9790..51324337 100644 --- a/test/cpuinfo_riscv_test.cc +++ b/test/cpuinfo_riscv_test.cc @@ -22,64 +22,60 @@ namespace cpu_features { namespace { TEST(CpuinfoRiscvTest, LicheeFromCpuInfo) { - ResetHwcaps(); - auto& fs = GetEmptyFilesystem(); - fs.CreateFile("/proc/cpuinfo", R"(processor : 0 + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"(processor : 0 hart : 0 isa : rv64imafdc mmu : sv39 uarch : thead,c906)"); - const auto info = GetRiscvInfo(); - EXPECT_STREQ(info.uarch, "c906"); - EXPECT_STREQ(info.vendor, "thead"); + const auto info = GetRiscvInfo(); + EXPECT_STREQ(info.uarch, "c906"); + EXPECT_STREQ(info.vendor, "thead"); - EXPECT_FALSE(info.features.riscv32); - EXPECT_TRUE(info.features.riscv64); - EXPECT_FALSE(info.features.riscv128); - EXPECT_TRUE(info.features.a); - EXPECT_TRUE(info.features.c); - EXPECT_TRUE(info.features.d); - EXPECT_FALSE(info.features.e); - EXPECT_TRUE(info.features.f); - EXPECT_TRUE(info.features.i); - EXPECT_TRUE(info.features.m); - EXPECT_FALSE(info.features.q); - EXPECT_FALSE(info.features.v); + EXPECT_FALSE(info.features.RV32I); + EXPECT_TRUE(info.features.RV64I); + EXPECT_TRUE(info.features.M); + EXPECT_TRUE(info.features.A); + EXPECT_TRUE(info.features.F); + EXPECT_TRUE(info.features.D); + EXPECT_FALSE(info.features.Q); + EXPECT_TRUE(info.features.C); } -TEST(CpuinfoRiscvTest, KendryteFromCpuInfo) { - ResetHwcaps(); - auto& fs = GetEmptyFilesystem(); - fs.CreateFile("/proc/cpuinfo", R"( -hart : 0 -isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 -mmu : sv39 +// TEST(CpuinfoRiscvTest, KendryteFromCpuInfo) { +// ResetHwcaps(); +// auto& fs = GetEmptyFilesystem(); +// fs.CreateFile("/proc/cpuinfo", R"( +// hart : 0 +// isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 +// mmu : sv39 -hart : 1 -isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 -mmu : sv39)"); - const auto info = GetRiscvInfo(); - EXPECT_STREQ(info.uarch, ""); - EXPECT_STREQ(info.vendor, ""); +// hart : 1 +// isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 +// mmu : sv39)"); +// const auto info = GetRiscvInfo(); +// EXPECT_STREQ(info.uarch, ""); +// EXPECT_STREQ(info.vendor, ""); - EXPECT_FALSE(info.features.riscv32); - EXPECT_TRUE(info.features.riscv64); - EXPECT_FALSE(info.features.riscv128); - EXPECT_TRUE(info.features.a); - EXPECT_TRUE(info.features.c); - EXPECT_TRUE(info.features.d); - EXPECT_FALSE(info.features.e); - EXPECT_TRUE(info.features.f); - EXPECT_TRUE(info.features.i); - EXPECT_TRUE(info.features.m); - EXPECT_FALSE(info.features.q); - EXPECT_TRUE(info.features.v); -} +// EXPECT_FALSE(info.features.riscv32); +// EXPECT_TRUE(info.features.riscv64); +// EXPECT_FALSE(info.features.riscv128); +// EXPECT_TRUE(info.features.a); +// EXPECT_TRUE(info.features.c); +// EXPECT_TRUE(info.features.d); +// EXPECT_FALSE(info.features.e); +// EXPECT_TRUE(info.features.f); +// EXPECT_TRUE(info.features.i); +// EXPECT_TRUE(info.features.m); +// EXPECT_FALSE(info.features.q); +// EXPECT_TRUE(info.features.v); +// } TEST(CpuinfoRiscvTest, UnknownFromCpuInfo) { - ResetHwcaps(); - auto& fs = GetEmptyFilesystem(); - fs.CreateFile("/proc/cpuinfo", R"( + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"( processor : 0 hart : 2 isa : rv64imafdc @@ -103,22 +99,18 @@ hart : 4 isa : rv64imafdc mmu : sv39 uarch : sifive,bullet0)"); - const auto info = GetRiscvInfo(); - EXPECT_STREQ(info.uarch, "bullet0"); - EXPECT_STREQ(info.vendor, "sifive"); + const auto info = GetRiscvInfo(); + EXPECT_STREQ(info.uarch, "bullet0"); + EXPECT_STREQ(info.vendor, "sifive"); - EXPECT_FALSE(info.features.riscv32); - EXPECT_TRUE(info.features.riscv64); - EXPECT_FALSE(info.features.riscv128); - EXPECT_TRUE(info.features.a); - EXPECT_TRUE(info.features.c); - EXPECT_TRUE(info.features.d); - EXPECT_FALSE(info.features.e); - EXPECT_TRUE(info.features.f); - EXPECT_TRUE(info.features.i); - EXPECT_TRUE(info.features.m); - EXPECT_FALSE(info.features.q); - EXPECT_FALSE(info.features.v); + EXPECT_FALSE(info.features.RV32I); + EXPECT_TRUE(info.features.RV64I); + EXPECT_TRUE(info.features.M); + EXPECT_TRUE(info.features.A); + EXPECT_TRUE(info.features.F); + EXPECT_TRUE(info.features.D); + EXPECT_FALSE(info.features.Q); + EXPECT_TRUE(info.features.C); } } // namespace From 68109ebeb5f7e741eb6156abdac2a3f00807f9fe Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Mon, 9 Jan 2023 14:23:05 +0000 Subject: [PATCH 7/9] Fix compilation --- src/impl_riscv_linux.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/impl_riscv_linux.c b/src/impl_riscv_linux.c index 6f7c45c8..afb16ff0 100644 --- a/src/impl_riscv_linux.c +++ b/src/impl_riscv_linux.c @@ -57,11 +57,11 @@ static const RiscvInfo kEmptyRiscvInfo; -static void HandleRiscVIsaLine(StringView line, RiscvInfo* const info) { +static void HandleRiscVIsaLine(StringView line, RiscvFeatures* const features) { for (size_t i = 0; i < RISCV_LAST_; ++i) { StringView flag = str(kCpuInfoFlags[i]); - bool is_set = CpuFeatures_StringView_StartsWith(value, flag); - kSetters[i](&info->features, is_set); + bool is_set = CpuFeatures_StringView_StartsWith(line, flag); + kSetters[i](features, is_set); if (is_set) { line = CpuFeatures_StringView_PopFront(line, flag.size); } @@ -73,7 +73,7 @@ static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) { StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { if (CpuFeatures_StringView_IsEquals(key, str("isa"))) { - HandleRiscVIsaLine(); + HandleRiscVIsaLine(value, &info->vendor); } else if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) { int index = CpuFeatures_StringView_IndexOfChar(value, ','); if (index == -1) return true; From 3bf84aafde71272f1c64ab9b35cbc2851f5ceb82 Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Thu, 12 Jan 2023 12:08:58 +0000 Subject: [PATCH 8/9] Fix wrong argument --- src/impl_riscv_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/impl_riscv_linux.c b/src/impl_riscv_linux.c index afb16ff0..00ffe54a 100644 --- a/src/impl_riscv_linux.c +++ b/src/impl_riscv_linux.c @@ -73,7 +73,7 @@ static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) { StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { if (CpuFeatures_StringView_IsEquals(key, str("isa"))) { - HandleRiscVIsaLine(value, &info->vendor); + HandleRiscVIsaLine(value, &info->features); } else if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) { int index = CpuFeatures_StringView_IndexOfChar(value, ','); if (index == -1) return true; From 8c919b40a4d4c5b0ea8b22860c5c21a129ee57c0 Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Thu, 12 Jan 2023 13:19:30 +0000 Subject: [PATCH 9/9] Add more tests and update parsing --- src/impl_riscv_linux.c | 8 ++-- test/cpuinfo_riscv_test.cc | 97 ++++++++++++++++++++++++++------------ 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/src/impl_riscv_linux.c b/src/impl_riscv_linux.c index 00ffe54a..1a7fceff 100644 --- a/src/impl_riscv_linux.c +++ b/src/impl_riscv_linux.c @@ -60,11 +60,11 @@ static const RiscvInfo kEmptyRiscvInfo; static void HandleRiscVIsaLine(StringView line, RiscvFeatures* const features) { for (size_t i = 0; i < RISCV_LAST_; ++i) { StringView flag = str(kCpuInfoFlags[i]); - bool is_set = CpuFeatures_StringView_StartsWith(line, flag); + int index_of_flag = CpuFeatures_StringView_IndexOf(line, flag); + bool is_set = index_of_flag != -1; kSetters[i](features, is_set); - if (is_set) { - line = CpuFeatures_StringView_PopFront(line, flag.size); - } + if (is_set) + line = CpuFeatures_StringView_PopFront(line, index_of_flag + flag.size); } } diff --git a/test/cpuinfo_riscv_test.cc b/test/cpuinfo_riscv_test.cc index 51324337..92f637e3 100644 --- a/test/cpuinfo_riscv_test.cc +++ b/test/cpuinfo_riscv_test.cc @@ -21,7 +21,7 @@ namespace cpu_features { namespace { -TEST(CpuinfoRiscvTest, LicheeFromCpuInfo) { +TEST(CpuinfoRiscvTest, Sipeed_Lichee_RV_FromCpuInfo) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(processor : 0 @@ -43,34 +43,73 @@ uarch : thead,c906)"); EXPECT_TRUE(info.features.C); } -// TEST(CpuinfoRiscvTest, KendryteFromCpuInfo) { -// ResetHwcaps(); -// auto& fs = GetEmptyFilesystem(); -// fs.CreateFile("/proc/cpuinfo", R"( -// hart : 0 -// isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 -// mmu : sv39 - -// hart : 1 -// isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 -// mmu : sv39)"); -// const auto info = GetRiscvInfo(); -// EXPECT_STREQ(info.uarch, ""); -// EXPECT_STREQ(info.vendor, ""); - -// EXPECT_FALSE(info.features.riscv32); -// EXPECT_TRUE(info.features.riscv64); -// EXPECT_FALSE(info.features.riscv128); -// EXPECT_TRUE(info.features.a); -// EXPECT_TRUE(info.features.c); -// EXPECT_TRUE(info.features.d); -// EXPECT_FALSE(info.features.e); -// EXPECT_TRUE(info.features.f); -// EXPECT_TRUE(info.features.i); -// EXPECT_TRUE(info.features.m); -// EXPECT_FALSE(info.features.q); -// EXPECT_TRUE(info.features.v); -// } +// https://github.com/ThomasKaiser/sbc-bench/blob/284e82b016ec1beeac42a5fcbe556b670f68441a/results/Kendryte-K510-4.17.0.cpuinfo +TEST(CpuinfoRiscvTest, Kendryte_K510_FromCpuInfo) { + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"( +hart : 0 +isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 +mmu : sv39 + +hart : 1 +isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 +mmu : sv39"); + const auto info = GetRiscvInfo(); + EXPECT_STREQ(info.uarch, ""); + EXPECT_STREQ(info.vendor, ""); + + EXPECT_FALSE(info.features.RV32I); + EXPECT_TRUE(info.features.RV64I); + EXPECT_TRUE(info.features.M); + EXPECT_TRUE(info.features.A); + EXPECT_TRUE(info.features.F); + EXPECT_TRUE(info.features.D); + EXPECT_FALSE(info.features.Q); + EXPECT_TRUE(info.features.C); +} + +// https://github.com/ThomasKaiser/sbc-bench/blob/284e82b016ec1beeac42a5fcbe556b670f68441a/results/T-Head-C910-5.10.4.cpuinfo +TEST(CpuinfoRiscvTest, T_Head_C910_FromCpuInfo) { + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"( +processor : 0 +hart : 0 +isa : rv64imafdcsu +mmu : sv39 +cpu-freq : 1.2Ghz +cpu-icache : 64KB +cpu-dcache : 64KB +cpu-l2cache : 2MB +cpu-tlb : 1024 4-ways +cpu-cacheline : 64Bytes +cpu-vector : 0.7.1 + +processor : 1 +hart : 1 +isa : rv64imafdcsu +mmu : sv39 +cpu-freq : 1.2Ghz +cpu-icache : 64KB +cpu-dcache : 64KB +cpu-l2cache : 2MB +cpu-tlb : 1024 4-ways +cpu-cacheline : 64Bytes +cpu-vector : 0.7.1"); + const auto info = GetRiscvInfo(); + EXPECT_STREQ(info.uarch, ""); + EXPECT_STREQ(info.vendor, ""); + + EXPECT_FALSE(info.features.RV32I); + EXPECT_TRUE(info.features.RV64I); + EXPECT_TRUE(info.features.M); + EXPECT_TRUE(info.features.A); + EXPECT_TRUE(info.features.F); + EXPECT_TRUE(info.features.D); + EXPECT_FALSE(info.features.Q); + EXPECT_TRUE(info.features.C); +} TEST(CpuinfoRiscvTest, UnknownFromCpuInfo) { ResetHwcaps();