Skip to content

Commit cf0c6b4

Browse files
authored
add riscv64 CPU compatibility (#257)
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.
1 parent 08af034 commit cf0c6b4

1 file changed

Lines changed: 47 additions & 0 deletions

File tree

include/tmc/detail/compat.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,53 @@ static inline size_t TMC_LOONGARCH_CPU_FREQ() noexcept {
133133
}
134134

135135
static inline const size_t TMC_CPU_FREQ = TMC_LOONGARCH_CPU_FREQ();
136+
#elif defined(__riscv)
137+
#if defined(__linux__)
138+
#include <cstdio>
139+
#endif
140+
#define TMC_CPU_RISCV
141+
static inline void TMC_CPU_PAUSE() noexcept {
142+
#if defined(__riscv_zihintpause)
143+
asm volatile("pause" ::: "memory");
144+
#else
145+
asm volatile("nop" ::: "memory");
146+
#endif
147+
}
148+
static inline size_t TMC_RISCV_READ_TIMEBASE_FREQ() noexcept {
149+
#if defined(__linux__)
150+
const char* paths[] = {
151+
"/proc/device-tree/cpus/timebase-frequency",
152+
"/sys/firmware/devicetree/base/cpus/timebase-frequency",
153+
};
154+
for (const char* path : paths) {
155+
auto* file = std::fopen(path, "rb");
156+
if (file == nullptr) {
157+
continue;
158+
}
159+
unsigned char bytes[8] = {};
160+
const auto size = std::fread(bytes, 1, sizeof(bytes), file);
161+
std::fclose(file);
162+
if (size == 4 || size == 8) {
163+
size_t result = 0;
164+
for (size_t i = 0; i != size; ++i) {
165+
result = (result << 8) | bytes[i];
166+
}
167+
if (result != 0) {
168+
return result;
169+
}
170+
}
171+
}
172+
#endif
173+
// This is only used for heuristics if the real RISC-V timebase is unavailable.
174+
// Use the 2GHz clock frequency of SG2042-class server chips as a default.
175+
return 2000000000;
176+
}
177+
static inline size_t TMC_CPU_TIMESTAMP() noexcept {
178+
size_t count;
179+
asm volatile("rdtime %0" : "=r"(count));
180+
return count;
181+
}
182+
static inline const size_t TMC_CPU_FREQ = TMC_RISCV_READ_TIMEBASE_FREQ();
136183
#endif
137184

138185
// clang-format tries to collapse the pragmas into one line...

0 commit comments

Comments
 (0)