about summary refs log tree commit diff stats
path: root/src/rv64detect.c
blob: e1b3b40a8d5911b6abb68b6cb770226ae2855271 (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
#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);

    // THead vendor extensions

    // 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);
}