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_
|