about summary refs log tree commit diff stats
path: root/src/rv64detect.c
blob: b0664b05c951ef76c98552526c0b8c4d2c637139 (plain) (blame)
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <signal.h>
#include <sys/mman.h>
#include <setjmp.h>

#include "debug.h"
#include "dynarec/rv64/rv64_emitter.h"

// Detect RV64 extensions, by executing on of the opcode with a SIGILL signal handler

static sigjmp_buf sigbuf = {0};
typedef void(*vFiip_t)(int, int, void*);
static void detect_sigill(int sig)
{
    siglongjmp(sigbuf, 1);
}

static int Check(void* block)
{
    static uint64_t buf[2] = {0};
    // Clear instruction cache
    __clear_cache(block, block+box64_pagesize);
    // Setup SIGILL signal handler
    __sighandler_t old = signal(SIGILL, detect_sigill);
    if(sigsetjmp(sigbuf, 1)) {
        // didn't work, extension not present
        signal(SIGILL, old);
        return 0;
    }
    ((vFiip_t)block)(0, 1, buf);
    // done...
    signal(SIGILL, old);
    return 1;
}

void RV64_Detect_Function()
{
    // Alloc memory to execute stuffs
    void* my_block = mmap(NULL, box64_pagesize, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
    if(my_block==(void*)-1) {
        return;
    }
    uint32_t* block;
    #define EMIT(A) *block = (A); ++block

    // Official extensions

    // Test Zba with ADDUW
    block = (uint32_t*)my_block;
    ADDUW(A0, A0, A1);
    BR(xRA);
    rv64_zba = Check(my_block);
    // Test Zbb with ANDN
    block = (uint32_t*)my_block;
    ANDN(A0, A0, A1);
    BR(xRA);
    rv64_zbb = Check(my_block);
    // Test Zbc with CLMUL
    block = (uint32_t*)my_block;
    CLMUL(A0, A0, A1);
    BR(xRA);
    rv64_zbc = Check(my_block);
    // Test Zbs with BCLR
    block = (uint32_t*)my_block;
    BCLR(A0, A0, A1);
    BR(xRA);
    rv64_zbs = Check(my_block);

    block = (uint32_t*)my_block;
    CSRRS(xZR, xZR, 0xc22 /* vlenb */);
    BR(xRA);
    rv64_vector = Check(my_block);

    if (rv64_vector) {
        block = (uint32_t*)my_block;
        CSRRS(xZR, xZR, 0x00f /* vcsr */); // vcsr does not exists in xtheadvector
        BR(xRA);
        rv64_xtheadvector = !Check(my_block);
    }

    if (rv64_vector) {
        int vlenb = 0;
        asm volatile("csrr %0, 0xc22" : "=r"(vlenb));
        rv64_vlen = vlenb * 8;
        if (vlenb < 16) {
            // we need vlen >= 128
            rv64_vector = 0;
        }
    }

    // THead vendor extensions
    if (!rv64_zba) {
        // Test XTheadBa with TH_ADDSL
        block = (uint32_t*)my_block;
        TH_ADDSL(A0, A0, A1, 1);
        BR(xRA);
        rv64_xtheadba = Check(my_block);

        // Test XTheadBb with TH_SRRI
        block = (uint32_t*)my_block;
        TH_SRRI(A0, A1, 1);
        BR(xRA);
        rv64_xtheadbb = Check(my_block);

        // Test XTheadBs with TH_TST
        block = (uint32_t*)my_block;
        TH_TST(A0, A1, 1);
        BR(xRA);
        rv64_xtheadbs = Check(my_block);

        // Test XTheadCondMov with TH_MVEQZ
        block = (uint32_t*)my_block;
        TH_MVEQZ(A0, A0, A1);
        BR(xRA);
        rv64_xtheadcondmov = Check(my_block);

        // Test XTheadMemIdx with TH_LBIA
        block = (uint32_t*)my_block;
        TH_LBIA(A0, A2, 1, 1);
        BR(xRA);
        rv64_xtheadmemidx = Check(my_block);

        // Test XTheadMemPair with TH_LDD
        block = (uint32_t*)my_block;
        TH_LDD(A0, A1, A2, 0);
        BR(xRA);
        rv64_xtheadmempair = Check(my_block);

        // Test XTheadFMemIdx with TH_FLRD
        block = (uint32_t*)my_block;
        TH_FLRD(A0, A2, xZR, 0);
        BR(xRA);
        rv64_xtheadfmemidx = Check(my_block);

        // Test XTheadMac with TH_MULA
        block = (uint32_t*)my_block;
        TH_MULA(A0, A0, A1);
        BR(xRA);
        rv64_xtheadmac = Check(my_block);

        // Test XTheadFmv with TH_FMV_X_HW
        block = (uint32_t*)my_block;
        TH_FMV_X_HW(A0, A1);
        BR(xRA);
        rv64_xtheadfmv = Check(my_block);
    }

    // Finish
    // Free the memory my_block
    munmap(my_block, box64_pagesize);
}