679af8a3 |
1 | #include <stdarg.h> |
2 | |
f4bb5d6b |
3 | enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI }; |
4 | |
f4bb5d6b |
5 | #define CONTEXT_REG xBP |
679af8a3 |
6 | |
80599a42 |
7 | #define IOP_JE 0x74 |
8 | #define IOP_JNE 0x75 |
9 | #define IOP_JBE 0x76 |
10 | #define IOP_JA 0x77 |
11 | #define IOP_JS 0x78 |
12 | #define IOP_JNS 0x79 |
13 | #define IOP_JLE 0x7e |
14 | |
15 | // unified conditions (we just use rel8 jump instructions for x86) |
16 | #define DCOND_EQ IOP_JE |
17 | #define DCOND_NE IOP_JNE |
18 | #define DCOND_MI IOP_JS // MInus |
19 | #define DCOND_PL IOP_JNS // PLus or zero |
20 | |
679af8a3 |
21 | #define EMIT_PTR(ptr, val, type) \ |
22 | *(type *)(ptr) = val |
23 | |
24 | #define EMIT(val, type) { \ |
25 | EMIT_PTR(tcache_ptr, val, type); \ |
f4bb5d6b |
26 | tcache_ptr += sizeof(type); \ |
679af8a3 |
27 | } |
28 | |
e898de13 |
29 | #define EMIT_OP(op) { \ |
30 | COUNT_OP; \ |
31 | EMIT(op, u8); \ |
32 | } |
33 | |
679af8a3 |
34 | #define EMIT_MODRM(mod,r,rm) \ |
35 | EMIT(((mod)<<6) | ((r)<<3) | (rm), u8) |
36 | |
37 | #define EMIT_OP_MODRM(op,mod,r,rm) { \ |
e898de13 |
38 | EMIT_OP(op); \ |
679af8a3 |
39 | EMIT_MODRM(mod, r, rm); \ |
40 | } |
41 | |
80599a42 |
42 | #define JMP8_POS(ptr) \ |
43 | ptr = tcache_ptr; \ |
44 | tcache_ptr += 2 |
45 | |
46 | #define JMP8_EMIT(op, ptr) \ |
47 | EMIT_PTR(ptr, op, u8); \ |
48 | EMIT_PTR(ptr + 1, (tcache_ptr - (ptr+2)), u8) |
49 | |
679af8a3 |
50 | #define emith_move_r_r(dst, src) \ |
51 | EMIT_OP_MODRM(0x8b, 3, dst, src) |
52 | |
80599a42 |
53 | #define emith_add_r_r(d, s) \ |
54 | EMIT_OP_MODRM(0x01, 3, s, d) |
55 | |
56 | #define emith_sub_r_r(d, s) \ |
57 | EMIT_OP_MODRM(0x29, 3, s, d) |
58 | |
59 | #define emith_or_r_r(d, s) \ |
60 | EMIT_OP_MODRM(0x09, 3, s, d) |
61 | |
62 | #define emith_eor_r_r(d, s) \ |
63 | EMIT_OP_MODRM(0x31, 3, s, d) |
64 | |
65 | // fake teq - test equivalence - get_flags(d ^ s) |
66 | #define emith_teq_r_r(d, s) { \ |
67 | emith_push(d); \ |
68 | emith_eor_r_r(d, s); \ |
69 | emith_pop(d); \ |
70 | } |
71 | |
72 | // _r_imm |
679af8a3 |
73 | #define emith_move_r_imm(r, imm) { \ |
e898de13 |
74 | EMIT_OP(0xb8 + (r)); \ |
679af8a3 |
75 | EMIT(imm, u32); \ |
76 | } |
77 | |
80599a42 |
78 | #define emith_arith_r_imm(op, r, imm) { \ |
79 | EMIT_OP_MODRM(0x81, 3, op, r); \ |
679af8a3 |
80 | EMIT(imm, u32); \ |
81 | } |
82 | |
80599a42 |
83 | // 2 - adc, 3 - sbb, 6 - xor, 7 - cmp |
84 | #define emith_add_r_imm(r, imm) \ |
85 | emith_arith_r_imm(0, r, imm) |
86 | |
87 | #define emith_or_r_imm(r, imm) \ |
88 | emith_arith_r_imm(1, r, imm) |
89 | |
90 | #define emith_and_r_imm(r, imm) \ |
91 | emith_arith_r_imm(4, r, imm) |
92 | |
93 | #define emith_sub_r_imm(r, imm) \ |
94 | emith_arith_r_imm(5, r, imm) |
95 | |
96 | #define emith_tst_r_imm(r, imm) { \ |
97 | EMIT_OP_MODRM(0xf7, 3, 0, r); \ |
679af8a3 |
98 | EMIT(imm, u32); \ |
99 | } |
100 | |
80599a42 |
101 | // fake |
102 | #define emith_bic_r_imm(r, imm) \ |
103 | emith_arith_r_imm(4, r, ~(imm)) |
104 | |
105 | // fake conditionals (using SJMP instead) |
106 | #define emith_add_r_imm_c(cond, r, imm) { \ |
107 | (void)(cond); \ |
108 | emith_arith_r_imm(0, r, imm); \ |
109 | } |
110 | |
111 | #define emith_or_r_imm_c(cond, r, imm) { \ |
112 | (void)(cond); \ |
113 | emith_arith_r_imm(1, r, imm); \ |
114 | } |
115 | |
116 | #define emith_sub_r_imm_c(cond, r, imm) { \ |
117 | (void)(cond); \ |
118 | emith_arith_r_imm(5, r, imm); \ |
119 | } |
120 | |
121 | // shift |
122 | #define emith_shift(op, d, s, cnt) { \ |
123 | if (d != s) \ |
124 | emith_move_r_r(d, s); \ |
125 | EMIT_OP_MODRM(0xc1, 3, op, d); \ |
126 | EMIT(cnt, u8); \ |
127 | } |
128 | |
129 | #define emith_asr(d, s, cnt) \ |
130 | emith_shift(7, d, s, cnt) |
131 | |
132 | #define emith_lsl(d, s, cnt) \ |
133 | emith_shift(4, d, s, cnt) |
134 | |
135 | // misc |
136 | #define emith_push(r) \ |
137 | EMIT_OP(0x50 + (r)) |
138 | |
139 | #define emith_pop(r) \ |
140 | EMIT_OP(0x58 + (r)) |
141 | |
142 | #define emith_neg_r(r) \ |
143 | EMIT_OP_MODRM(0xf7, 3, 3, r) |
144 | |
145 | #define emith_clear_msb(d, s, count) { \ |
146 | u32 t = (u32)-1; \ |
147 | t >>= count; \ |
148 | if (d != s) \ |
149 | emith_move_r_r(d, s); \ |
150 | emith_and_r_imm(d, t); \ |
151 | } |
152 | |
153 | #define emith_sext(d, s, bits) { \ |
154 | emith_lsl(d, s, 32 - (bits)); \ |
155 | emith_asr(d, d, 32 - (bits)); \ |
156 | } |
157 | |
158 | // XXX: stupid mess |
159 | #define emith_mul(d, s1, s2) { \ |
160 | int rmr; \ |
161 | if (d != xAX) \ |
162 | emith_push(xAX); \ |
163 | if ((s1) == xAX) \ |
164 | rmr = s2; \ |
165 | else if ((s2) == xAX) \ |
166 | rmr = s1; \ |
167 | else { \ |
168 | emith_move_r_r(xAX, s1); \ |
169 | rmr = s2; \ |
170 | } \ |
171 | emith_push(xDX); \ |
172 | EMIT_OP_MODRM(0xf7, 3, 4, rmr); /* MUL rmr */ \ |
173 | emith_pop(xDX); \ |
174 | if (d != xAX) { \ |
175 | emith_move_r_r(d, xAX); \ |
176 | emith_pop(xAX); \ |
177 | } \ |
178 | } |
179 | |
180 | // "flag" instructions are the same |
181 | #define emith_subf_r_imm emith_sub_r_imm |
182 | #define emith_subf_r_r emith_sub_r_r |
183 | |
679af8a3 |
184 | // XXX: offs is 8bit only |
185 | #define emith_ctx_read(r, offs) { \ |
65c75cb0 |
186 | EMIT_OP_MODRM(0x8b, 1, r, xBP); \ |
679af8a3 |
187 | EMIT(offs, u8); /* mov tmp, [ebp+#offs] */ \ |
188 | } |
189 | |
190 | #define emith_ctx_write(r, offs) { \ |
65c75cb0 |
191 | EMIT_OP_MODRM(0x89, 1, r, xBP); \ |
679af8a3 |
192 | EMIT(offs, u8); /* mov [ebp+#offs], tmp */ \ |
193 | } |
194 | |
679af8a3 |
195 | #define emith_jump(ptr) { \ |
196 | u32 disp = (u32)ptr - ((u32)tcache_ptr + 5); \ |
e898de13 |
197 | EMIT_OP(0xe9); \ |
679af8a3 |
198 | EMIT(disp, u32); \ |
199 | } |
200 | |
201 | #define emith_call(ptr) { \ |
202 | u32 disp = (u32)ptr - ((u32)tcache_ptr + 5); \ |
e898de13 |
203 | EMIT_OP(0xe8); \ |
679af8a3 |
204 | EMIT(disp, u32); \ |
205 | } |
206 | |
80599a42 |
207 | // "simple" or "short" jump |
208 | #define EMITH_SJMP_START(cond) { \ |
209 | u8 *cond_ptr; \ |
210 | JMP8_POS(cond_ptr) |
211 | |
212 | #define EMITH_SJMP_END(cond) \ |
213 | JMP8_EMIT(cond, cond_ptr); \ |
679af8a3 |
214 | } |
215 | |
80599a42 |
216 | #define host_arg2reg(rd, arg) \ |
f4bb5d6b |
217 | switch (arg) { \ |
218 | case 0: rd = xAX; break; \ |
219 | case 1: rd = xDX; break; \ |
220 | case 2: rd = xCX; break; \ |
679af8a3 |
221 | } |
222 | |
f4bb5d6b |
223 | #define emith_pass_arg_r(arg, reg) { \ |
224 | int rd = 7; \ |
80599a42 |
225 | host_arg2reg(rd, arg); \ |
f4bb5d6b |
226 | emith_move_r_r(rd, reg); \ |
227 | } |
228 | |
229 | #define emith_pass_arg_imm(arg, imm) { \ |
230 | int rd = 7; \ |
80599a42 |
231 | host_arg2reg(rd, arg); \ |
f4bb5d6b |
232 | emith_move_r_imm(rd, imm); \ |
679af8a3 |
233 | } |
234 | |
65c75cb0 |
235 | /* SH2 drc specific */ |
80599a42 |
236 | #define emith_sh2_test_t() { \ |
237 | int t = rcache_get_reg(SHR_SR, RC_GR_READ); \ |
238 | EMIT_OP_MODRM(0xf6, 3, 0, t); \ |
239 | EMIT(0x01, u8); /* test <reg>, byte 1 */ \ |
240 | } |
241 | |
242 | #define emith_sh2_dtbf_loop() { \ |
243 | u8 *jmp0; /* negative cycles check */ \ |
244 | u8 *jmp1; /* unsinged overflow check */ \ |
245 | int cr, rn; \ |
246 | tmp = rcache_get_tmp(); \ |
247 | cr = rcache_get_reg(SHR_SR, RC_GR_RMW); \ |
248 | rn = rcache_get_reg((op >> 8) & 0x0f, RC_GR_RMW);\ |
249 | emith_sub_r_imm(rn, 1); \ |
250 | emith_sub_r_imm(cr, (cycles+1) << 12); \ |
251 | cycles = 0; \ |
252 | emith_asr(tmp, cr, 2+12); \ |
253 | JMP8_POS(jmp0); /* no negative cycles */ \ |
254 | emith_move_r_imm(tmp, 0); \ |
255 | JMP8_EMIT(IOP_JNS, jmp0); \ |
256 | emith_and_r_imm(cr, 0xffe); \ |
257 | emith_subf_r_r(rn, tmp); \ |
258 | JMP8_POS(jmp1); /* no overflow */ \ |
259 | emith_neg_r(rn); /* count left */ \ |
260 | emith_lsl(rn, rn, 2+12); \ |
261 | emith_or_r_r(cr, rn); \ |
262 | emith_or_r_imm(cr, 1); \ |
263 | emith_move_r_imm(rn, 0); \ |
264 | JMP8_EMIT(IOP_JA, jmp1); \ |
265 | rcache_free_tmp(tmp); \ |
65c75cb0 |
266 | } |
267 | |