about summary refs log tree commit diff stats
path: root/src/dynarec/rv64/dynarec_rv64_private.h
blob: 70f58661615b3247dfd0ea9dac028375a7f5644e (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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#ifndef __DYNAREC_RV64_PRIVATE_H_
#define __DYNAREC_RV64_PRIVATE_H_
#include <stdint.h>

#include "../dynarec_private.h"

typedef struct x64emu_s x64emu_t;
typedef struct dynablock_s dynablock_t;
typedef struct instsize_s instsize_t;

#define BARRIER_MAYBE   8

#define EXT_CACHE_NONE   0
#define EXT_CACHE_ST_D   1
#define EXT_CACHE_ST_F   2
#define EXT_CACHE_ST_I64 3
#define EXT_CACHE_MM     4
#define EXT_CACHE_SS     5
#define EXT_CACHE_SD     6
#define EXT_CACHE_SCR    7
#define EXT_CACHE_XMMW   8
#define EXT_CACHE_XMMR   9

typedef union ext_cache_s {
    int8_t           v;
    struct {
        uint8_t t:4;   // reg type
        uint8_t n:4;   // reg number
    };
} ext_cache_t;

typedef union sse_cache_s {
    int16_t v;
    struct {
        uint16_t reg : 7;
        uint16_t vector : 1;
        uint16_t single : 1;
        uint16_t write : 1;
        uint16_t unused : 7;
    };
} sse_cache_t;

typedef union sse_old_s {
    int8_t      v;
    struct {
        uint8_t     changed:1;
        uint8_t     purged:1;
        uint8_t     reg:4;
        uint8_t     single:1;
    };
} sse_old_t;

typedef struct extcache_s {
    // ext cache
    ext_cache_t         extcache[24];
    int8_t              stack;
    int8_t              stack_next;
    int8_t              stack_pop;
    int8_t              stack_push;
    uint8_t             combined1;
    uint8_t             combined2;
    uint8_t             swapped;        // the combined reg were swapped
    uint8_t             barrier;        // is there a barrier at instruction epilog?
    uint8_t             pushed;         // positive pushed value (to check for overflow)
    uint8_t             poped;          // positive poped value (to check for underflow)
    uint32_t            news;           // bitmask, wich neoncache are new for this opcode
    sse_old_t           olds[16];       // SSE regs has changed or has been removed
    // fpu cache
    int8_t              x87cache[8];    // cache status for the 8 x87 register behind the fpu stack
    int8_t              x87reg[8];      // reg used for x87cache entry
    int16_t             tags;           // similar to fpu_tags
    int8_t              mmxcache[8];    // cache status for the 8 MMX registers
    sse_cache_t         ssecache[16];   // cache status for the 16 SSE(2) registers
    int8_t              fpuused[24];    // all 10..31 & 0..1 double reg from fpu, used by x87, sse and mmx
    int8_t              x87stack;       // cache stack counter
    int8_t              mmxcount;       // number of mmx register used (not both mmx and x87 at the same time)
    int8_t              fpu_scratch;    // scratch counter
    int8_t              fpu_extra_qscratch; // some opcode need an extra quad scratch register
    int8_t              fpu_reg;        // x87/sse/mmx reg counter
} extcache_t;

typedef struct flagcache_s {
    int                 pending;    // is there a pending flags here, or to check?
    uint8_t             dfnone;     // if deferred flags is already set to df_none
    uint8_t             dfnone_here;// defered flags is cleared in this opcode
} flagcache_t;

typedef struct instruction_rv64_s {
    instruction_x64_t   x64;
    uintptr_t           address;    // (start) address of the arm emitted instruction
    uintptr_t           epilog;     // epilog of current instruction (can be start of next, or barrier stuff)
    int                 size;       // size of the arm emitted instruction
    int                 size2;      // size of the arm emitted instrucion after pass2
    int                 pred_sz;    // size of predecessor list
    int                 *pred;      // predecessor array
    uintptr_t           mark[3];
    uintptr_t           markf[2];
    uintptr_t           markseg;
    uintptr_t           marklock;
    int                 pass2choice;// value for choices that are fixed on pass2 for pass3
    uintptr_t           natcall;
    uint16_t            retn;
    uint16_t            purge_ymm;  // need to purge some ymm
    uint16_t            ymm0_in;    // bitmap of ymm to zero at purge
    uint16_t            ymm0_add;   // the ymm0 added by the opcode
    uint16_t            ymm0_sub;   // the ymm0 removed by the opcode
    uint16_t            ymm0_out;   // the ymmm0 at th end of the opcode
    uint16_t            ymm0_pass2, ymm0_pass3;
    int                 barrier_maybe;
    flagcache_t         f_exit;     // flags status at end of intruction
    extcache_t          e;          // extcache at end of intruction (but before poping)
    flagcache_t         f_entry;    // flags status before the instruction begin
    uint8_t             vector_sew;
} instruction_rv64_t;

typedef struct dynarec_rv64_s {
    instruction_rv64_t* insts;
    int32_t             size;
    int32_t             cap;
    uintptr_t           start;      // start of the block
    uint32_t            isize;      // size in byte of x64 instructions included
    void*               block;      // memory pointer where next instruction is emitted
    uintptr_t           native_start;  // start of the arm code
    size_t              native_size;   // size of emitted arm code
    uintptr_t           last_ip;    // last set IP in RIP (or NULL if unclean state) TODO: move to a cache something
    uint64_t*           table64;   // table of 64bits value
    int                 table64size;// size of table (will be appended at end of executable code)
    int                 table64cap;
    uintptr_t           tablestart;
    uintptr_t           jmp_next;   // address of the jump_next address
    flagcache_t         f;
    extcache_t          e;          // cache for the 10..31 0..1 double reg from fpu, plus x87 stack delta
    uintptr_t*          next;       // variable array of "next" jump address
    int                 next_sz;
    int                 next_cap;
    int*                jmps;       // variable array of jump instructions
    int                 jmp_sz;
    int                 jmp_cap;
    int*                predecessor;// single array of all predecessor
    dynablock_t*        dynablock;
    instsize_t*         instsize;
    size_t              insts_size; // size of the instruction size array (calculated)
    uint8_t             smread;    // for strongmem model emulation
    uint8_t             smwrite;    // for strongmem model emulation
    uintptr_t           forward;    // address of the last end of code while testing forward
    uintptr_t           forward_to; // address of the next jump to (to check if everything is ok)
    int32_t             forward_size;   // size at the forward point
    int                 forward_ninst;  // ninst at the forward point
    uint16_t            ymm_zero;   // bitmap of ymm to zero at purge
    uint8_t             always_test;
    uint8_t             abort;
    uint8_t             vector_sew;
} dynarec_rv64_t;

// convert idx (0..24) to reg index (10..31 0..1)
#define EXTREG(A)   (((A)+10)&31)
// convert reg index (10..31 0..1) or idx (0..24)
#define EXTIDX(A)   (((A)-10)&31)

void add_next(dynarec_rv64_t *dyn, uintptr_t addr);
uintptr_t get_closest_next(dynarec_rv64_t *dyn, uintptr_t addr);
void add_jump(dynarec_rv64_t *dyn, int ninst);
int get_first_jump(dynarec_rv64_t *dyn, int next);
int get_first_jump_addr(dynarec_rv64_t *dyn, uintptr_t next);
int is_nops(dynarec_rv64_t *dyn, uintptr_t addr, int n);
int is_instructions(dynarec_rv64_t *dyn, uintptr_t addr, int n);

int Table64(dynarec_rv64_t *dyn, uint64_t val, int pass);  // add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal

void CreateJmpNext(void* addr, void* next);

#define GO_TRACE(A, B, s0)  \
    GETIP(addr);            \
    MV(A1, xRIP);           \
    STORE_XEMU_CALL(s0);    \
    MOV64x(A2, B);          \
    CALL(A, -1);            \
    LOAD_XEMU_CALL()

#endif //__DYNAREC_RV64_PRIVATE_H_