1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
#+build riscv64
#+build linux
package sysinfo
import "base:intrinsics"
import "core:sys/linux"
@(init, private)
init_cpu_features :: proc "contextless" () {
_features: CPU_Features
defer cpu.features = _features
HWCAP_Bits :: enum u64 {
I = 'I' - 'A',
M = 'M' - 'A',
A = 'A' - 'A',
F = 'F' - 'A',
D = 'D' - 'A',
C = 'C' - 'A',
V = 'V' - 'A',
}
HWCAP :: bit_set[HWCAP_Bits; u64]
// Read HWCAP for base extensions, we can get this info through hwprobe too but that is Linux 6.4+ only.
{
fd, err := linux.open("/proc/self/auxv", {})
if err != .NONE { return }
defer linux.close(fd)
// This is probably enough right?
buf: [4096]byte
n, rerr := linux.read(fd, buf[:])
if rerr != .NONE || n == 0 { return }
ulong :: u64
AT_HWCAP :: 16
auxv := buf[:n]
for len(auxv) >= size_of(ulong)*2 {
key := intrinsics.unaligned_load((^ulong)(&auxv[0]))
val := intrinsics.unaligned_load((^ulong)(&auxv[size_of(ulong)]))
auxv = auxv[2*size_of(ulong):]
if key != AT_HWCAP {
continue
}
cap := transmute(HWCAP)(val)
if .I in cap {
_features += { .I }
}
if .M in cap {
_features += { .M }
}
if .A in cap {
_features += { .A }
}
if .F in cap {
_features += { .F }
}
if .D in cap {
_features += { .D }
}
if .C in cap {
_features += { .C }
}
if .V in cap {
_features += { .V }
}
break
}
}
// hwprobe for other features.
{
pairs := []linux.RISCV_HWProbe{
{ key = .IMA_EXT_0 },
{ key = .CPUPERF_0 },
{ key = .MISALIGNED_SCALAR_PERF },
}
err := linux.riscv_hwprobe(raw_data(pairs), len(pairs), 0, nil, {})
if err != nil {
assert_contextless(err == .ENOSYS, "unexpected error from riscv_hwprobe()")
return
}
assert_contextless(pairs[0].key == .IMA_EXT_0)
exts := pairs[0].value.ima_ext_0
exts -= { .FD, .C, .V }
_features += transmute(CPU_Features)exts
if pairs[2].key == .MISALIGNED_SCALAR_PERF {
if pairs[2].value.misaligned_scalar_perf == .FAST {
_features += { .Misaligned_Supported, .Misaligned_Fast }
} else if pairs[2].value.misaligned_scalar_perf != .UNSUPPORTED {
_features += { .Misaligned_Supported }
}
} else {
assert_contextless(pairs[1].key == .CPUPERF_0)
if .FAST in pairs[1].value.cpu_perf_0 {
_features += { .Misaligned_Supported, .Misaligned_Fast }
} else if .UNSUPPORTED not_in pairs[1].value.cpu_perf_0 {
_features += { .Misaligned_Supported }
}
}
}
}
@(init, private)
init_cpu_name :: proc "contextless" () {
cpu.name = "RISCV64"
}
|