drc: revive x86 dynarec, support x86-64
[picodrive.git] / cpu / drc / emit_x86.c
CommitLineData
3863edbd 1/*
cff531af 2 * Basic macros to emit x86 instructions and some utils
3 * Copyright (C) 2008,2009,2010 notaz
4 *
5 * This work is licensed under the terms of MAME license.
6 * See COPYING file in the top-level directory.
7 *
8b4f38f4 8 * note:
a2b8c5a5 9 * temp registers must be eax-edx due to use of SETcc and r/w 8/16.
f0d7b1fa 10 * note about silly things like emith_eor_r_r_r:
8b4f38f4 11 * these are here because the compiler was designed
12 * for ARM as it's primary target.
3863edbd 13 */
679af8a3 14#include <stdarg.h>
15
f4bb5d6b 16enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
17
f4bb5d6b 18#define CONTEXT_REG xBP
898d51a7 19#define RET_REG xAX
679af8a3 20
18b94127 21#define ICOND_JO 0x00
22#define ICOND_JNO 0x01
23#define ICOND_JB 0x02
24#define ICOND_JAE 0x03
25#define ICOND_JE 0x04
26#define ICOND_JNE 0x05
27#define ICOND_JBE 0x06
28#define ICOND_JA 0x07
29#define ICOND_JS 0x08
30#define ICOND_JNS 0x09
31#define ICOND_JL 0x0c
32#define ICOND_JGE 0x0d
33#define ICOND_JLE 0x0e
34#define ICOND_JG 0x0f
35
36#define IOP_JMP 0xeb
80599a42 37
38// unified conditions (we just use rel8 jump instructions for x86)
18b94127 39#define DCOND_EQ ICOND_JE
40#define DCOND_NE ICOND_JNE
41#define DCOND_MI ICOND_JS // MInus
42#define DCOND_PL ICOND_JNS // PLus or zero
43#define DCOND_HI ICOND_JA // higher (unsigned)
44#define DCOND_HS ICOND_JAE // higher || same (unsigned)
45#define DCOND_LO ICOND_JB // lower (unsigned)
46#define DCOND_LS ICOND_JBE // lower || same (unsigned)
47#define DCOND_GE ICOND_JGE // greater || equal (signed)
48#define DCOND_GT ICOND_JG // greater (signed)
49#define DCOND_LE ICOND_JLE // less || equal (signed)
50#define DCOND_LT ICOND_JL // less (signed)
51#define DCOND_VS ICOND_JO // oVerflow Set
52#define DCOND_VC ICOND_JNO // oVerflow Clear
80599a42 53
679af8a3 54#define EMIT_PTR(ptr, val, type) \
55 *(type *)(ptr) = val
56
898d51a7 57#define EMIT(val, type) do { \
679af8a3 58 EMIT_PTR(tcache_ptr, val, type); \
f4bb5d6b 59 tcache_ptr += sizeof(type); \
898d51a7 60} while (0)
679af8a3 61
898d51a7 62#define EMIT_OP(op) do { \
e898de13 63 COUNT_OP; \
64 EMIT(op, u8); \
898d51a7 65} while (0)
e898de13 66
679af8a3 67#define EMIT_MODRM(mod,r,rm) \
68 EMIT(((mod)<<6) | ((r)<<3) | (rm), u8)
69
f0d7b1fa 70#define EMIT_SIB(scale,index,base) \
71 EMIT(((scale)<<6) | ((index)<<3) | (base), u8)
72
898d51a7 73#define EMIT_REX(w,r,x,b) \
74 EMIT(0x40 | ((w)<<3) | ((r)<<2) | ((x)<<1) | (b), u8)
75
04092e32 76#define EMIT_OP_MODRM(op,mod,r,rm) do { \
e898de13 77 EMIT_OP(op); \
679af8a3 78 EMIT_MODRM(mod, r, rm); \
04092e32 79} while (0)
679af8a3 80
80599a42 81#define JMP8_POS(ptr) \
82 ptr = tcache_ptr; \
83 tcache_ptr += 2
84
85#define JMP8_EMIT(op, ptr) \
18b94127 86 EMIT_PTR(ptr, 0x70|(op), u8); \
87 EMIT_PTR(ptr + 1, (tcache_ptr - (ptr+2)), u8)
88
89#define JMP8_EMIT_NC(ptr) \
90 EMIT_PTR(ptr, IOP_JMP, u8); \
80599a42 91 EMIT_PTR(ptr + 1, (tcache_ptr - (ptr+2)), u8)
92
3863edbd 93// _r_r
679af8a3 94#define emith_move_r_r(dst, src) \
95 EMIT_OP_MODRM(0x8b, 3, dst, src)
96
898d51a7 97#define emith_move_r_r_ptr(dst, src) do { \
98 EMIT_REX_FOR_PTR(); \
99 EMIT_OP_MODRM(0x8b, 3, dst, src); \
100} while (0)
101
80599a42 102#define emith_add_r_r(d, s) \
103 EMIT_OP_MODRM(0x01, 3, s, d)
104
105#define emith_sub_r_r(d, s) \
106 EMIT_OP_MODRM(0x29, 3, s, d)
107
3863edbd 108#define emith_adc_r_r(d, s) \
109 EMIT_OP_MODRM(0x11, 3, s, d)
110
111#define emith_sbc_r_r(d, s) \
112 EMIT_OP_MODRM(0x19, 3, s, d) /* SBB */
113
80599a42 114#define emith_or_r_r(d, s) \
115 EMIT_OP_MODRM(0x09, 3, s, d)
116
3863edbd 117#define emith_and_r_r(d, s) \
118 EMIT_OP_MODRM(0x21, 3, s, d)
119
80599a42 120#define emith_eor_r_r(d, s) \
3863edbd 121 EMIT_OP_MODRM(0x31, 3, s, d) /* XOR */
122
123#define emith_tst_r_r(d, s) \
124 EMIT_OP_MODRM(0x85, 3, s, d) /* TEST */
125
126#define emith_cmp_r_r(d, s) \
127 EMIT_OP_MODRM(0x39, 3, s, d)
80599a42 128
129// fake teq - test equivalence - get_flags(d ^ s)
898d51a7 130#define emith_teq_r_r(d, s) do { \
80599a42 131 emith_push(d); \
132 emith_eor_r_r(d, s); \
133 emith_pop(d); \
898d51a7 134} while (0)
80599a42 135
898d51a7 136#define emith_mvn_r_r(d, s) do { \
52d759c3 137 if (d != s) \
138 emith_move_r_r(d, s); \
139 EMIT_OP_MODRM(0xf7, 3, 2, d); /* NOT d */ \
898d51a7 140} while (0)
52d759c3 141
898d51a7 142#define emith_negc_r_r(d, s) do { \
52d759c3 143 int tmp_ = rcache_get_tmp(); \
144 emith_move_r_imm(tmp_, 0); \
145 emith_sbc_r_r(tmp_, s); \
146 emith_move_r_r(d, tmp_); \
147 rcache_free_tmp(tmp_); \
898d51a7 148} while (0)
52d759c3 149
898d51a7 150#define emith_neg_r_r(d, s) do { \
52d759c3 151 if (d != s) \
152 emith_move_r_r(d, s); \
153 EMIT_OP_MODRM(0xf7, 3, 3, d); /* NEG d */ \
898d51a7 154} while (0)
52d759c3 155
3863edbd 156// _r_r_r
898d51a7 157#define emith_add_r_r_r(d, s1, s2) do { \
bf092a36 158 if (d == s1) { \
159 emith_add_r_r(d, s2); \
160 } else if (d == s2) { \
161 emith_add_r_r(d, s1); \
162 } else { \
163 emith_move_r_r(d, s1); \
164 emith_add_r_r(d, s2); \
165 } \
898d51a7 166} while (0)
bf092a36 167
898d51a7 168#define emith_eor_r_r_r(d, s1, s2) do { \
52d759c3 169 if (d == s1) { \
170 emith_eor_r_r(d, s2); \
171 } else if (d == s2) { \
172 emith_eor_r_r(d, s1); \
173 } else { \
3863edbd 174 emith_move_r_r(d, s1); \
52d759c3 175 emith_eor_r_r(d, s2); \
176 } \
898d51a7 177} while (0)
3863edbd 178
f0d7b1fa 179// _r_r_shift
898d51a7 180#define emith_or_r_r_lsl(d, s, lslimm) do { \
52d759c3 181 int tmp_ = rcache_get_tmp(); \
f0d7b1fa 182 emith_lsl(tmp_, s, lslimm); \
183 emith_or_r_r(d, tmp_); \
52d759c3 184 rcache_free_tmp(tmp_); \
898d51a7 185} while (0)
3863edbd 186
f0d7b1fa 187// d != s
898d51a7 188#define emith_eor_r_r_lsr(d, s, lsrimm) do { \
f0d7b1fa 189 emith_push(s); \
190 emith_lsr(s, s, lsrimm); \
191 emith_eor_r_r(d, s); \
192 emith_pop(s); \
898d51a7 193} while (0)
f0d7b1fa 194
80599a42 195// _r_imm
898d51a7 196#define emith_move_r_imm(r, imm) do { \
e898de13 197 EMIT_OP(0xb8 + (r)); \
679af8a3 198 EMIT(imm, u32); \
898d51a7 199} while (0)
679af8a3 200
52d759c3 201#define emith_move_r_imm_s8(r, imm) \
202 emith_move_r_imm(r, (u32)(signed int)(signed char)(imm))
203
18b94127 204#define emith_arith_r_imm(op, r, imm) do { \
80599a42 205 EMIT_OP_MODRM(0x81, 3, op, r); \
679af8a3 206 EMIT(imm, u32); \
18b94127 207} while (0)
679af8a3 208
80599a42 209#define emith_add_r_imm(r, imm) \
210 emith_arith_r_imm(0, r, imm)
211
212#define emith_or_r_imm(r, imm) \
213 emith_arith_r_imm(1, r, imm)
214
5686d931 215#define emith_adc_r_imm(r, imm) \
216 emith_arith_r_imm(2, r, imm)
217
218#define emith_sbc_r_imm(r, imm) \
219 emith_arith_r_imm(3, r, imm) // sbb
220
80599a42 221#define emith_and_r_imm(r, imm) \
222 emith_arith_r_imm(4, r, imm)
223
898d51a7 224/* used for sub cycles after test, so retain flags with lea */
225#define emith_sub_r_imm(r, imm) do { \
226 assert(r != xSP); \
227 EMIT_OP_MODRM(0x8d, 2, r, r); \
228 EMIT(-(s32)(imm), s32); \
229} while (0)
230
231#define emith_subf_r_imm(r, imm) \
80599a42 232 emith_arith_r_imm(5, r, imm)
233
52d759c3 234#define emith_eor_r_imm(r, imm) \
235 emith_arith_r_imm(6, r, imm)
236
ed8cf79b 237#define emith_cmp_r_imm(r, imm) \
238 emith_arith_r_imm(7, r, imm)
239
18b94127 240#define emith_tst_r_imm(r, imm) do { \
80599a42 241 EMIT_OP_MODRM(0xf7, 3, 0, r); \
679af8a3 242 EMIT(imm, u32); \
18b94127 243} while (0)
679af8a3 244
80599a42 245// fake
246#define emith_bic_r_imm(r, imm) \
247 emith_arith_r_imm(4, r, ~(imm))
248
249// fake conditionals (using SJMP instead)
898d51a7 250#define emith_move_r_imm_c(cond, r, imm) do { \
8796b7ee 251 (void)(cond); \
252 emith_move_r_imm(r, imm); \
898d51a7 253} while (0)
8796b7ee 254
898d51a7 255#define emith_add_r_imm_c(cond, r, imm) do { \
80599a42 256 (void)(cond); \
3863edbd 257 emith_add_r_imm(r, imm); \
898d51a7 258} while (0)
80599a42 259
898d51a7 260#define emith_sub_r_imm_c(cond, r, imm) do { \
80599a42 261 (void)(cond); \
3863edbd 262 emith_sub_r_imm(r, imm); \
898d51a7 263} while (0)
3863edbd 264
b081408f 265#define emith_or_r_imm_c(cond, r, imm) \
266 emith_or_r_imm(r, imm)
267#define emith_eor_r_imm_c(cond, r, imm) \
268 emith_eor_r_imm(r, imm)
269#define emith_bic_r_imm_c(cond, r, imm) \
270 emith_bic_r_imm(r, imm)
271#define emith_ror_c(cond, d, s, cnt) \
272 emith_ror(d, s, cnt)
273
274#define emith_read_r_r_offs_c(cond, r, rs, offs) \
275 emith_read_r_r_offs(r, rs, offs)
276#define emith_write_r_r_offs_c(cond, r, rs, offs) \
277 emith_write_r_r_offs(r, rs, offs)
278#define emith_read8_r_r_offs_c(cond, r, rs, offs) \
279 emith_read8_r_r_offs(r, rs, offs)
280#define emith_write8_r_r_offs_c(cond, r, rs, offs) \
281 emith_write8_r_r_offs(r, rs, offs)
282#define emith_read16_r_r_offs_c(cond, r, rs, offs) \
283 emith_read16_r_r_offs(r, rs, offs)
284#define emith_write16_r_r_offs_c(cond, r, rs, offs) \
285 emith_write16_r_r_offs(r, rs, offs)
286#define emith_jump_reg_c(cond, r) \
287 emith_jump_reg(r)
288#define emith_jump_ctx_c(cond, offs) \
289 emith_jump_ctx(offs)
290#define emith_ret_c(cond) \
291 emith_ret()
e05b81fc 292
898d51a7 293// _r_r_imm - use lea
294#define emith_add_r_r_imm(d, s, imm) do { \
295 assert(s != xSP); \
296 EMIT_OP_MODRM(0x8d, 2, d, s); /* lea */ \
297 EMIT(imm, s32); \
298} while (0)
299
300#define emith_add_r_r_ptr_imm(d, s, imm) do { \
301 if (s != xSP) { \
302 EMIT_REX_FOR_PTR(); \
303 EMIT_OP_MODRM(0x8d, 2, d, s); /* lea */ \
304 } \
305 else { \
306 if (d != s) \
307 emith_move_r_r_ptr(d, s); \
308 EMIT_REX_FOR_PTR(); \
309 EMIT_OP_MODRM(0x81, 3, 0, d); /* add */ \
310 } \
311 EMIT(imm, s32); \
312} while (0)
e05b81fc 313
898d51a7 314#define emith_and_r_r_imm(d, s, imm) do { \
52d759c3 315 if (d != s) \
316 emith_move_r_r(d, s); \
18b94127 317 emith_and_r_imm(d, imm); \
898d51a7 318} while (0)
52d759c3 319
80599a42 320// shift
898d51a7 321#define emith_shift(op, d, s, cnt) do { \
80599a42 322 if (d != s) \
323 emith_move_r_r(d, s); \
324 EMIT_OP_MODRM(0xc1, 3, op, d); \
325 EMIT(cnt, u8); \
898d51a7 326} while (0)
80599a42 327
80599a42 328#define emith_lsl(d, s, cnt) \
329 emith_shift(4, d, s, cnt)
330
3863edbd 331#define emith_lsr(d, s, cnt) \
332 emith_shift(5, d, s, cnt)
333
334#define emith_asr(d, s, cnt) \
335 emith_shift(7, d, s, cnt)
336
ed8cf79b 337#define emith_rol(d, s, cnt) \
338 emith_shift(0, d, s, cnt)
339
340#define emith_ror(d, s, cnt) \
341 emith_shift(1, d, s, cnt)
342
343#define emith_rolc(r) \
344 EMIT_OP_MODRM(0xd1, 3, 2, r)
345
346#define emith_rorc(r) \
347 EMIT_OP_MODRM(0xd1, 3, 3, r)
348
80599a42 349// misc
350#define emith_push(r) \
351 EMIT_OP(0x50 + (r))
352
898d51a7 353#define emith_push_imm(imm) do { \
e05b81fc 354 EMIT_OP(0x68); \
355 EMIT(imm, u32); \
898d51a7 356} while (0)
e05b81fc 357
80599a42 358#define emith_pop(r) \
359 EMIT_OP(0x58 + (r))
360
361#define emith_neg_r(r) \
362 EMIT_OP_MODRM(0xf7, 3, 3, r)
363
364#define emith_clear_msb(d, s, count) { \
365 u32 t = (u32)-1; \
366 t >>= count; \
367 if (d != s) \
368 emith_move_r_r(d, s); \
369 emith_and_r_imm(d, t); \
370}
371
f0d7b1fa 372#define emith_clear_msb_c(cond, d, s, count) { \
373 (void)(cond); \
374 emith_clear_msb(d, s, count); \
375}
376
80599a42 377#define emith_sext(d, s, bits) { \
378 emith_lsl(d, s, 32 - (bits)); \
379 emith_asr(d, d, 32 - (bits)); \
380}
381
898d51a7 382#define emith_setc(r) do { \
383 assert(is_abcdx(r)); \
f0d7b1fa 384 EMIT_OP(0x0f); \
8b4f38f4 385 EMIT_OP_MODRM(0x92, 3, 0, r); /* SETC r */ \
898d51a7 386} while (0)
f0d7b1fa 387
80599a42 388// XXX: stupid mess
898d51a7 389#define emith_mul_(op, dlo, dhi, s1, s2) do { \
80599a42 390 int rmr; \
3863edbd 391 if (dlo != xAX && dhi != xAX) \
80599a42 392 emith_push(xAX); \
3863edbd 393 if (dlo != xDX && dhi != xDX) \
394 emith_push(xDX); \
80599a42 395 if ((s1) == xAX) \
396 rmr = s2; \
397 else if ((s2) == xAX) \
398 rmr = s1; \
399 else { \
400 emith_move_r_r(xAX, s1); \
401 rmr = s2; \
402 } \
3863edbd 403 EMIT_OP_MODRM(0xf7, 3, op, rmr); /* xMUL rmr */ \
404 /* XXX: using push/pop for the case of edx->eax; eax->edx */ \
405 if (dhi != xDX && dhi != -1) \
406 emith_push(xDX); \
407 if (dlo != xAX) \
408 emith_move_r_r(dlo, xAX); \
409 if (dhi != xDX && dhi != -1) \
410 emith_pop(dhi); \
411 if (dlo != xDX && dhi != xDX) \
412 emith_pop(xDX); \
413 if (dlo != xAX && dhi != xAX) \
80599a42 414 emith_pop(xAX); \
898d51a7 415} while (0)
80599a42 416
3863edbd 417#define emith_mul_u64(dlo, dhi, s1, s2) \
418 emith_mul_(4, dlo, dhi, s1, s2) /* MUL */
419
420#define emith_mul_s64(dlo, dhi, s1, s2) \
421 emith_mul_(5, dlo, dhi, s1, s2) /* IMUL */
422
423#define emith_mul(d, s1, s2) \
424 emith_mul_(4, d, -1, s1, s2)
425
f0d7b1fa 426// (dlo,dhi) += signed(s1) * signed(s2)
898d51a7 427#define emith_mula_s64(dlo, dhi, s1, s2) do { \
f0d7b1fa 428 emith_push(dhi); \
429 emith_push(dlo); \
430 emith_mul_(5, dlo, dhi, s1, s2); \
431 EMIT_OP_MODRM(0x03, 0, dlo, 4); \
898d51a7 432 EMIT_SIB(0, 4, 4); /* add dlo, [xsp] */ \
f0d7b1fa 433 EMIT_OP_MODRM(0x13, 1, dhi, 4); \
434 EMIT_SIB(0, 4, 4); \
898d51a7 435 EMIT(sizeof(void *), u8); /* adc dhi, [xsp+{4,8}] */ \
436 emith_add_r_r_ptr_imm(xSP, xSP, sizeof(void *) * 2); \
437} while (0)
f0d7b1fa 438
80599a42 439// "flag" instructions are the same
3863edbd 440#define emith_addf_r_r emith_add_r_r
80599a42 441#define emith_subf_r_r emith_sub_r_r
3863edbd 442#define emith_adcf_r_r emith_adc_r_r
443#define emith_sbcf_r_r emith_sbc_r_r
8796b7ee 444#define emith_eorf_r_r emith_eor_r_r
52d759c3 445#define emith_negcf_r_r emith_negc_r_r
3863edbd 446
ed8cf79b 447#define emith_lslf emith_lsl
448#define emith_lsrf emith_lsr
449#define emith_asrf emith_asr
450#define emith_rolf emith_rol
451#define emith_rorf emith_ror
452#define emith_rolcf emith_rolc
453#define emith_rorcf emith_rorc
80599a42 454
b081408f 455#define emith_deref_op(op, r, rs, offs) do { \
e05b81fc 456 /* mov r <-> [ebp+#offs] */ \
457 if ((offs) >= 0x80) { \
b081408f 458 EMIT_OP_MODRM(op, 2, r, rs); \
e05b81fc 459 EMIT(offs, u32); \
460 } else { \
b081408f 461 EMIT_OP_MODRM(op, 1, r, rs); \
e05b81fc 462 EMIT(offs, u8); \
463 } \
8796b7ee 464} while (0)
679af8a3 465
a2b8c5a5 466#define is_abcdx(r) (xAX <= (r) && (r) <= xDX)
467
04092e32 468#define emith_read_r_r_offs(r, rs, offs) \
469 emith_deref_op(0x8b, r, rs, offs)
470
471#define emith_write_r_r_offs(r, rs, offs) \
472 emith_deref_op(0x89, r, rs, offs)
473
474// note: don't use prefixes on this
475#define emith_read8_r_r_offs(r, rs, offs) do { \
a2b8c5a5 476 int r_ = r; \
477 if (!is_abcdx(r)) \
478 r_ = rcache_get_tmp(); \
04092e32 479 emith_deref_op(0x8a, r_, rs, offs); \
a2b8c5a5 480 if ((r) != r_) { \
481 emith_move_r_r(r, r_); \
482 rcache_free_tmp(r_); \
483 } \
484} while (0)
485
04092e32 486#define emith_write8_r_r_offs(r, rs, offs) do {\
a2b8c5a5 487 int r_ = r; \
488 if (!is_abcdx(r)) { \
489 r_ = rcache_get_tmp(); \
490 emith_move_r_r(r_, r); \
491 } \
04092e32 492 emith_deref_op(0x88, r_, rs, offs); \
a2b8c5a5 493 if ((r) != r_) \
494 rcache_free_tmp(r_); \
495} while (0)
496
898d51a7 497#define emith_read16_r_r_offs(r, rs, offs) do { \
b081408f 498 EMIT(0x66, u8); /* operand override */ \
04092e32 499 emith_read_r_r_offs(r, rs, offs); \
898d51a7 500} while (0)
b081408f 501
898d51a7 502#define emith_write16_r_r_offs(r, rs, offs) do { \
b081408f 503 EMIT(0x66, u8); \
04092e32 504 emith_write_r_r_offs(r, rs, offs); \
898d51a7 505} while (0)
b081408f 506
e05b81fc 507#define emith_ctx_read(r, offs) \
b081408f 508 emith_read_r_r_offs(r, CONTEXT_REG, offs)
e05b81fc 509
898d51a7 510#define emith_ctx_read_ptr(r, offs) do { \
511 EMIT_REX_FOR_PTR(); \
512 emith_deref_op(0x8b, r, CONTEXT_REG, offs); \
513} while (0)
514
e05b81fc 515#define emith_ctx_write(r, offs) \
b081408f 516 emith_write_r_r_offs(r, CONTEXT_REG, offs)
e05b81fc 517
8796b7ee 518#define emith_ctx_read_multiple(r, offs, cnt, tmpr) do { \
519 int r_ = r, offs_ = offs, cnt_ = cnt; \
8b4f38f4 520 for (; cnt_ > 0; r_++, offs_ += 4, cnt_--) \
8796b7ee 521 emith_ctx_read(r_, offs_); \
522} while (0)
523
8796b7ee 524#define emith_ctx_write_multiple(r, offs, cnt, tmpr) do { \
525 int r_ = r, offs_ = offs, cnt_ = cnt; \
8b4f38f4 526 for (; cnt_ > 0; r_++, offs_ += 4, cnt_--) \
8796b7ee 527 emith_ctx_write(r_, offs_); \
528} while (0)
679af8a3 529
e05b81fc 530// assumes EBX is free
531#define emith_ret_to_ctx(offs) { \
532 emith_pop(xBX); \
533 emith_ctx_write(xBX, offs); \
534}
535
679af8a3 536#define emith_jump(ptr) { \
898d51a7 537 u32 disp = (u8 *)(ptr) - ((u8 *)tcache_ptr + 5); \
e898de13 538 EMIT_OP(0xe9); \
679af8a3 539 EMIT(disp, u32); \
540}
541
44e6452e 542#define emith_jump_patchable(target) \
543 emith_jump(target)
544
898d51a7 545#define emith_jump_cond(cond, ptr) do { \
546 u32 disp = (u8 *)(ptr) - ((u8 *)tcache_ptr + 6); \
18b94127 547 EMIT(0x0f, u8); \
548 EMIT_OP(0x80 | (cond)); \
549 EMIT(disp, u32); \
898d51a7 550} while (0)
18b94127 551
44e6452e 552#define emith_jump_cond_patchable(cond, target) \
553 emith_jump_cond(cond, target)
18b94127 554
555#define emith_jump_patch(ptr, target) do { \
898d51a7 556 u32 disp_ = (u8 *)(target) - ((u8 *)(ptr) + 4); \
44e6452e 557 u32 offs_ = (*(u8 *)(ptr) == 0x0f) ? 2 : 1; \
558 EMIT_PTR((u8 *)(ptr) + offs_, disp_ - offs_, u32); \
18b94127 559} while (0)
560
a2b8c5a5 561#define emith_jump_at(ptr, target) { \
898d51a7 562 u32 disp_ = (u8 *)(target) - ((u8 *)(ptr) + 5); \
a2b8c5a5 563 EMIT_PTR(ptr, 0xe9, u8); \
564 EMIT_PTR((u8 *)(ptr) + 1, disp_, u32); \
565}
566
679af8a3 567#define emith_call(ptr) { \
898d51a7 568 u32 disp = (u8 *)(ptr) - ((u8 *)tcache_ptr + 5); \
e898de13 569 EMIT_OP(0xe8); \
679af8a3 570 EMIT(disp, u32); \
571}
572
f0d7b1fa 573#define emith_call_cond(cond, ptr) \
574 emith_call(ptr)
575
e05b81fc 576#define emith_call_reg(r) \
577 EMIT_OP_MODRM(0xff, 3, 2, r)
578
898d51a7 579#define emith_call_ctx(offs) do { \
b081408f 580 EMIT_OP_MODRM(0xff, 2, 2, CONTEXT_REG); \
e05b81fc 581 EMIT(offs, u32); \
898d51a7 582} while (0)
e05b81fc 583
584#define emith_ret() \
585 EMIT_OP(0xc3)
586
8796b7ee 587#define emith_jump_reg(r) \
588 EMIT_OP_MODRM(0xff, 3, 4, r)
589
898d51a7 590#define emith_jump_ctx(offs) do { \
b081408f 591 EMIT_OP_MODRM(0xff, 2, 4, CONTEXT_REG); \
e05b81fc 592 EMIT(offs, u32); \
898d51a7 593} while (0)
e05b81fc 594
a2b8c5a5 595#define emith_push_ret()
596
597#define emith_pop_and_ret() \
598 emith_ret()
599
8796b7ee 600#define EMITH_JMP_START(cond) { \
80599a42 601 u8 *cond_ptr; \
602 JMP8_POS(cond_ptr)
603
8796b7ee 604#define EMITH_JMP_END(cond) \
80599a42 605 JMP8_EMIT(cond, cond_ptr); \
679af8a3 606}
607
b081408f 608#define EMITH_JMP3_START(cond) { \
609 u8 *cond_ptr, *else_ptr; \
610 JMP8_POS(cond_ptr)
611
612#define EMITH_JMP3_MID(cond) \
613 JMP8_POS(else_ptr); \
614 JMP8_EMIT(cond, cond_ptr);
615
616#define EMITH_JMP3_END() \
617 JMP8_EMIT_NC(else_ptr); \
618}
619
8796b7ee 620// "simple" jump (no more then a few insns)
b081408f 621// ARM will use conditional instructions here
898d51a7 622#define EMITH_SJMP_DECL_() \
623 u8 *cond_ptr
624
625#define EMITH_SJMP_START_(cond) \
626 JMP8_POS(cond_ptr)
627
628#define EMITH_SJMP_END_(cond) \
629 JMP8_EMIT(cond, cond_ptr)
630
8796b7ee 631#define EMITH_SJMP_START EMITH_JMP_START
632#define EMITH_SJMP_END EMITH_JMP_END
633
b081408f 634#define EMITH_SJMP3_START EMITH_JMP3_START
635#define EMITH_SJMP3_MID EMITH_JMP3_MID
636#define EMITH_SJMP3_END EMITH_JMP3_END
637
898d51a7 638#define emith_pass_arg_r(arg, reg) do { \
f4bb5d6b 639 int rd = 7; \
80599a42 640 host_arg2reg(rd, arg); \
898d51a7 641 emith_move_r_r_ptr(rd, reg); \
642} while (0)
f4bb5d6b 643
898d51a7 644#define emith_pass_arg_imm(arg, imm) do { \
f4bb5d6b 645 int rd = 7; \
80599a42 646 host_arg2reg(rd, arg); \
f4bb5d6b 647 emith_move_r_imm(rd, imm); \
898d51a7 648} while (0)
679af8a3 649
a2b8c5a5 650#define host_instructions_updated(base, end)
651
898d51a7 652#ifdef __x86_64__
653
654#define PTR_SCALE 3
655#define NA_TMP_REG xCX // non-arg tmp from reg_temp[]
656
657#define EMIT_REX_FOR_PTR() \
658 EMIT_REX(1,0,0,0)
659
660#define host_arg2reg(rd, arg) \
661 switch (arg) { \
662 case 0: rd = xDI; break; \
663 case 1: rd = xSI; break; \
664 case 2: rd = xDX; break; \
665 }
666
667#define emith_sh2_drc_entry() { \
668 emith_push(xBX); \
669 emith_push(xBP); \
670 emith_push(xSI); /* to align */ \
671}
672
673#define emith_sh2_drc_exit() { \
674 emith_pop(xSI); \
675 emith_pop(xBP); \
676 emith_pop(xBX); \
677 emith_ret(); \
678}
679
680#else
681
682#define PTR_SCALE 2
683#define NA_TMP_REG xBX // non-arg tmp from reg_temp[]
684
685#define EMIT_REX_FOR_PTR()
686
a2b8c5a5 687#define host_arg2reg(rd, arg) \
688 switch (arg) { \
689 case 0: rd = xAX; break; \
690 case 1: rd = xDX; break; \
691 case 2: rd = xCX; break; \
692 }
693
8796b7ee 694#define emith_sh2_drc_entry() { \
695 emith_push(xBX); \
696 emith_push(xBP); \
8b4f38f4 697 emith_push(xSI); \
698 emith_push(xDI); \
8796b7ee 699}
700
701#define emith_sh2_drc_exit() { \
8b4f38f4 702 emith_pop(xDI); \
703 emith_pop(xSI); \
8796b7ee 704 emith_pop(xBP); \
705 emith_pop(xBX); \
e05b81fc 706 emith_ret(); \
707}
708
898d51a7 709#endif
710
711#define emith_save_caller_regs(mask) do { \
712 if ((mask) & (1 << xAX)) emith_push(xAX); \
713 if ((mask) & (1 << xCX)) emith_push(xCX); \
714 if ((mask) & (1 << xDX)) emith_push(xDX); \
715 if ((mask) & (1 << xSI)) emith_push(xSI); \
716 if ((mask) & (1 << xDI)) emith_push(xDI); \
717} while (0)
718
719#define emith_restore_caller_regs(mask) do { \
720 if ((mask) & (1 << xDI)) emith_pop(xDI); \
721 if ((mask) & (1 << xSI)) emith_pop(xSI); \
722 if ((mask) & (1 << xDX)) emith_pop(xDX); \
723 if ((mask) & (1 << xCX)) emith_pop(xCX); \
724 if ((mask) & (1 << xAX)) emith_pop(xAX); \
725} while (0)
726
bf092a36 727#define emith_sh2_wcall(a, tab) { \
e05b81fc 728 int arg2_; \
729 host_arg2reg(arg2_, 2); \
898d51a7 730 emith_lsr(NA_TMP_REG, a, SH2_WRITE_SHIFT); \
731 EMIT_REX_FOR_PTR(); \
732 EMIT_OP_MODRM(0x8b, 0, NA_TMP_REG, 4); \
733 EMIT_SIB(PTR_SCALE, NA_TMP_REG, tab); /* mov tmp, [tab + tmp * {4,8}] */ \
734 emith_move_r_r_ptr(arg2_, CONTEXT_REG); \
735 emith_jump_reg(NA_TMP_REG); \
8796b7ee 736}
737
80599a42 738#define emith_sh2_dtbf_loop() { \
739 u8 *jmp0; /* negative cycles check */ \
740 u8 *jmp1; /* unsinged overflow check */ \
741 int cr, rn; \
52d759c3 742 int tmp_ = rcache_get_tmp(); \
80599a42 743 cr = rcache_get_reg(SHR_SR, RC_GR_RMW); \
744 rn = rcache_get_reg((op >> 8) & 0x0f, RC_GR_RMW);\
745 emith_sub_r_imm(rn, 1); \
746 emith_sub_r_imm(cr, (cycles+1) << 12); \
747 cycles = 0; \
52d759c3 748 emith_asr(tmp_, cr, 2+12); \
80599a42 749 JMP8_POS(jmp0); /* no negative cycles */ \
52d759c3 750 emith_move_r_imm(tmp_, 0); \
18b94127 751 JMP8_EMIT(ICOND_JNS, jmp0); \
80599a42 752 emith_and_r_imm(cr, 0xffe); \
52d759c3 753 emith_subf_r_r(rn, tmp_); \
80599a42 754 JMP8_POS(jmp1); /* no overflow */ \
755 emith_neg_r(rn); /* count left */ \
756 emith_lsl(rn, rn, 2+12); \
757 emith_or_r_r(cr, rn); \
758 emith_or_r_imm(cr, 1); \
759 emith_move_r_imm(rn, 0); \
18b94127 760 JMP8_EMIT(ICOND_JA, jmp1); \
52d759c3 761 rcache_free_tmp(tmp_); \
65c75cb0 762}
763
18b94127 764#define emith_write_sr(sr, srcr) { \
52d759c3 765 int tmp_ = rcache_get_tmp(); \
18b94127 766 emith_clear_msb(tmp_, srcr, 22); \
767 emith_bic_r_imm(sr, 0x3ff); \
768 emith_or_r_r(sr, tmp_); \
52d759c3 769 rcache_free_tmp(tmp_); \
ed8cf79b 770}
771
8b4f38f4 772#define emith_tpop_carry(sr, is_sub) \
773 emith_lsr(sr, sr, 1)
774
775#define emith_tpush_carry(sr, is_sub) \
776 emith_adc_r_r(sr, sr)
ed8cf79b 777
f0d7b1fa 778/*
779 * if Q
780 * t = carry(Rn += Rm)
781 * else
782 * t = carry(Rn -= Rm)
783 * T ^= t
784 */
785#define emith_sh2_div1_step(rn, rm, sr) { \
786 u8 *jmp0, *jmp1; \
787 int tmp_ = rcache_get_tmp(); \
8b4f38f4 788 emith_eor_r_r(tmp_, tmp_); \
f0d7b1fa 789 emith_tst_r_imm(sr, Q); /* if (Q ^ M) */ \
790 JMP8_POS(jmp0); /* je do_sub */ \
791 emith_add_r_r(rn, rm); \
792 JMP8_POS(jmp1); /* jmp done */ \
18b94127 793 JMP8_EMIT(ICOND_JE, jmp0); /* do_sub: */ \
f0d7b1fa 794 emith_sub_r_r(rn, rm); \
18b94127 795 JMP8_EMIT_NC(jmp1); /* done: */ \
898d51a7 796 emith_adc_r_r(tmp_, tmp_); \
797 emith_eor_r_r(sr, tmp_); \
f0d7b1fa 798 rcache_free_tmp(tmp_); \
799}
800