From 8618846a6b49e348fd0ad6458e0614108f891f21 Mon Sep 17 00:00:00 2001 From: Xeonacid Date: Sat, 20 Jun 2026 10:02:51 +0200 Subject: [PATCH] add riscv64 CPU compatibility Add a riscv64 branch that uses the Zihintpause pause instruction when the target enables it, otherwise falls back to a nop that is valid for the baseline ISA. Read the Linux device-tree timebase-frequency value from procfs or sysfs as the counter frequency, and use rdtime for timestamps so both helpers use the RISC-V time counter units. Keep the stdio include inside the riscv64 Linux branch so the common compatibility header stays slim on other targets. If Linux device-tree data is unavailable, return a 2GHz heuristic fallback based on the SG2042 clock frequency. Validated by compiling and running a small riscv64 translation unit including tmc/ex_cpu.hpp and tmc/channel.hpp on real riscv64 hardware, where it reported the 50 MHz device-tree timebase. Also validated riscv64 header compilation in the Arch Linux riscv64 chroot and ran the non-Linux fallback preprocessor path, which reported 2GHz. --- include/tmc/detail/compat.hpp | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/include/tmc/detail/compat.hpp b/include/tmc/detail/compat.hpp index 0b5af122..4bc10d8a 100644 --- a/include/tmc/detail/compat.hpp +++ b/include/tmc/detail/compat.hpp @@ -133,6 +133,53 @@ static inline size_t TMC_LOONGARCH_CPU_FREQ() noexcept { } static inline const size_t TMC_CPU_FREQ = TMC_LOONGARCH_CPU_FREQ(); +#elif defined(__riscv) +#if defined(__linux__) +#include +#endif +#define TMC_CPU_RISCV +static inline void TMC_CPU_PAUSE() noexcept { +#if defined(__riscv_zihintpause) + asm volatile("pause" ::: "memory"); +#else + asm volatile("nop" ::: "memory"); +#endif +} +static inline size_t TMC_RISCV_READ_TIMEBASE_FREQ() noexcept { +#if defined(__linux__) + const char* paths[] = { + "/proc/device-tree/cpus/timebase-frequency", + "/sys/firmware/devicetree/base/cpus/timebase-frequency", + }; + for (const char* path : paths) { + auto* file = std::fopen(path, "rb"); + if (file == nullptr) { + continue; + } + unsigned char bytes[8] = {}; + const auto size = std::fread(bytes, 1, sizeof(bytes), file); + std::fclose(file); + if (size == 4 || size == 8) { + size_t result = 0; + for (size_t i = 0; i != size; ++i) { + result = (result << 8) | bytes[i]; + } + if (result != 0) { + return result; + } + } + } +#endif + // This is only used for heuristics if the real RISC-V timebase is unavailable. + // Use the 2GHz clock frequency of SG2042-class server chips as a default. + return 2000000000; +} +static inline size_t TMC_CPU_TIMESTAMP() noexcept { + size_t count; + asm volatile("rdtime %0" : "=r"(count)); + return count; +} +static inline const size_t TMC_CPU_FREQ = TMC_RISCV_READ_TIMEBASE_FREQ(); #endif // clang-format tries to collapse the pragmas into one line...