drc: revive x86 dynarec, support x86-64
[picodrive.git] / cpu / drc / emit_x86.c
1 /*
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  *
8  * note:
9  *  temp registers must be eax-edx due to use of SETcc and r/w 8/16.
10  * note about silly things like emith_eor_r_r_r:
11  *  these are here because the compiler was designed
12  *  for ARM as it's primary target.
13  */
14 #include <stdarg.h>
15
16 enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
17
18 #define CONTEXT_REG xBP
19 #define RET_REG     xAX
20
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
37
38 // unified conditions (we just use rel8 jump instructions for x86)
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
53
54 #define EMIT_PTR(ptr, val, type) \
55         *(type *)(ptr) = val
56
57 #define EMIT(val, type) do { \
58         EMIT_PTR(tcache_ptr, val, type); \
59         tcache_ptr += sizeof(type); \
60 } while (0)
61
62 #define EMIT_OP(op) do { \
63         COUNT_OP; \
64         EMIT(op, u8); \
65 } while (0)
66
67 #define EMIT_MODRM(mod,r,rm) \
68         EMIT(((mod)<<6) | ((r)<<3) | (rm), u8)
69
70 #define EMIT_SIB(scale,index,base) \
71         EMIT(((scale)<<6) | ((index)<<3) | (base), u8)
72
73 #define EMIT_REX(w,r,x,b) \
74         EMIT(0x40 | ((w)<<3) | ((r)<<2) | ((x)<<1) | (b), u8)
75
76 #define EMIT_OP_MODRM(op,mod,r,rm) do { \
77         EMIT_OP(op); \
78         EMIT_MODRM(mod, r, rm); \
79 } while (0)
80
81 #define JMP8_POS(ptr) \
82         ptr = tcache_ptr; \
83         tcache_ptr += 2
84
85 #define JMP8_EMIT(op, ptr) \
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); \
91         EMIT_PTR(ptr + 1, (tcache_ptr - (ptr+2)), u8)
92
93 // _r_r
94 #define emith_move_r_r(dst, src) \
95         EMIT_OP_MODRM(0x8b, 3, dst, src)
96
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
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
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
114 #define emith_or_r_r(d, s) \
115         EMIT_OP_MODRM(0x09, 3, s, d)
116
117 #define emith_and_r_r(d, s) \
118         EMIT_OP_MODRM(0x21, 3, s, d)
119
120 #define emith_eor_r_r(d, s) \
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)
128
129 // fake teq - test equivalence - get_flags(d ^ s)
130 #define emith_teq_r_r(d, s) do { \
131         emith_push(d); \
132         emith_eor_r_r(d, s); \
133         emith_pop(d); \
134 } while (0)
135
136 #define emith_mvn_r_r(d, s) do { \
137         if (d != s) \
138                 emith_move_r_r(d, s); \
139         EMIT_OP_MODRM(0xf7, 3, 2, d); /* NOT d */ \
140 } while (0)
141
142 #define emith_negc_r_r(d, s) do { \
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_); \
148 } while (0)
149
150 #define emith_neg_r_r(d, s) do { \
151         if (d != s) \
152                 emith_move_r_r(d, s); \
153         EMIT_OP_MODRM(0xf7, 3, 3, d); /* NEG d */ \
154 } while (0)
155
156 // _r_r_r
157 #define emith_add_r_r_r(d, s1, s2) do { \
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         } \
166 } while (0)
167
168 #define emith_eor_r_r_r(d, s1, s2) do { \
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 { \
174                 emith_move_r_r(d, s1); \
175                 emith_eor_r_r(d, s2); \
176         } \
177 } while (0)
178
179 // _r_r_shift
180 #define emith_or_r_r_lsl(d, s, lslimm) do { \
181         int tmp_ = rcache_get_tmp(); \
182         emith_lsl(tmp_, s, lslimm); \
183         emith_or_r_r(d, tmp_); \
184         rcache_free_tmp(tmp_); \
185 } while (0)
186
187 // d != s
188 #define emith_eor_r_r_lsr(d, s, lsrimm) do { \
189         emith_push(s); \
190         emith_lsr(s, s, lsrimm); \
191         emith_eor_r_r(d, s); \
192         emith_pop(s); \
193 } while (0)
194
195 // _r_imm
196 #define emith_move_r_imm(r, imm) do { \
197         EMIT_OP(0xb8 + (r)); \
198         EMIT(imm, u32); \
199 } while (0)
200
201 #define emith_move_r_imm_s8(r, imm) \
202         emith_move_r_imm(r, (u32)(signed int)(signed char)(imm))
203
204 #define emith_arith_r_imm(op, r, imm) do { \
205         EMIT_OP_MODRM(0x81, 3, op, r); \
206         EMIT(imm, u32); \
207 } while (0)
208
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
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
221 #define emith_and_r_imm(r, imm) \
222         emith_arith_r_imm(4, r, imm)
223
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) \
232         emith_arith_r_imm(5, r, imm)
233
234 #define emith_eor_r_imm(r, imm) \
235         emith_arith_r_imm(6, r, imm)
236
237 #define emith_cmp_r_imm(r, imm) \
238         emith_arith_r_imm(7, r, imm)
239
240 #define emith_tst_r_imm(r, imm) do { \
241         EMIT_OP_MODRM(0xf7, 3, 0, r); \
242         EMIT(imm, u32); \
243 } while (0)
244
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)
250 #define emith_move_r_imm_c(cond, r, imm) do { \
251         (void)(cond); \
252         emith_move_r_imm(r, imm); \
253 } while (0)
254
255 #define emith_add_r_imm_c(cond, r, imm) do { \
256         (void)(cond); \
257         emith_add_r_imm(r, imm); \
258 } while (0)
259
260 #define emith_sub_r_imm_c(cond, r, imm) do { \
261         (void)(cond); \
262         emith_sub_r_imm(r, imm); \
263 } while (0)
264
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()
292
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)
313
314 #define emith_and_r_r_imm(d, s, imm) do { \
315         if (d != s) \
316                 emith_move_r_r(d, s); \
317         emith_and_r_imm(d, imm); \
318 } while (0)
319
320 // shift
321 #define emith_shift(op, d, s, cnt) do { \
322         if (d != s) \
323                 emith_move_r_r(d, s); \
324         EMIT_OP_MODRM(0xc1, 3, op, d); \
325         EMIT(cnt, u8); \
326 } while (0)
327
328 #define emith_lsl(d, s, cnt) \
329         emith_shift(4, d, s, cnt)
330
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
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
349 // misc
350 #define emith_push(r) \
351         EMIT_OP(0x50 + (r))
352
353 #define emith_push_imm(imm) do { \
354         EMIT_OP(0x68); \
355         EMIT(imm, u32); \
356 } while (0)
357
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
372 #define emith_clear_msb_c(cond, d, s, count) { \
373         (void)(cond); \
374         emith_clear_msb(d, s, count); \
375 }
376
377 #define emith_sext(d, s, bits) { \
378         emith_lsl(d, s, 32 - (bits)); \
379         emith_asr(d, d, 32 - (bits)); \
380 }
381
382 #define emith_setc(r) do { \
383         assert(is_abcdx(r)); \
384         EMIT_OP(0x0f); \
385         EMIT_OP_MODRM(0x92, 3, 0, r); /* SETC r */ \
386 } while (0)
387
388 // XXX: stupid mess
389 #define emith_mul_(op, dlo, dhi, s1, s2) do { \
390         int rmr; \
391         if (dlo != xAX && dhi != xAX) \
392                 emith_push(xAX); \
393         if (dlo != xDX && dhi != xDX) \
394                 emith_push(xDX); \
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         } \
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) \
414                 emith_pop(xAX); \
415 } while (0)
416
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
426 // (dlo,dhi) += signed(s1) * signed(s2)
427 #define emith_mula_s64(dlo, dhi, s1, s2) do { \
428         emith_push(dhi); \
429         emith_push(dlo); \
430         emith_mul_(5, dlo, dhi, s1, s2); \
431         EMIT_OP_MODRM(0x03, 0, dlo, 4); \
432         EMIT_SIB(0, 4, 4); /* add dlo, [xsp] */ \
433         EMIT_OP_MODRM(0x13, 1, dhi, 4); \
434         EMIT_SIB(0, 4, 4); \
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)
438
439 // "flag" instructions are the same
440 #define emith_addf_r_r   emith_add_r_r
441 #define emith_subf_r_r   emith_sub_r_r
442 #define emith_adcf_r_r   emith_adc_r_r
443 #define emith_sbcf_r_r   emith_sbc_r_r
444 #define emith_eorf_r_r   emith_eor_r_r
445 #define emith_negcf_r_r  emith_negc_r_r
446
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
454
455 #define emith_deref_op(op, r, rs, offs) do { \
456         /* mov r <-> [ebp+#offs] */ \
457         if ((offs) >= 0x80) { \
458                 EMIT_OP_MODRM(op, 2, r, rs); \
459                 EMIT(offs, u32); \
460         } else { \
461                 EMIT_OP_MODRM(op, 1, r, rs); \
462                 EMIT(offs, u8); \
463         } \
464 } while (0)
465
466 #define is_abcdx(r) (xAX <= (r) && (r) <= xDX)
467
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 { \
476         int r_ = r; \
477         if (!is_abcdx(r)) \
478                 r_ = rcache_get_tmp(); \
479         emith_deref_op(0x8a, r_, rs, offs); \
480         if ((r) != r_) { \
481                 emith_move_r_r(r, r_); \
482                 rcache_free_tmp(r_); \
483         } \
484 } while (0)
485
486 #define emith_write8_r_r_offs(r, rs, offs) do {\
487         int r_ = r; \
488         if (!is_abcdx(r)) { \
489                 r_ = rcache_get_tmp(); \
490                 emith_move_r_r(r_, r); \
491         } \
492         emith_deref_op(0x88, r_, rs, offs); \
493         if ((r) != r_) \
494                 rcache_free_tmp(r_); \
495 } while (0)
496
497 #define emith_read16_r_r_offs(r, rs, offs) do { \
498         EMIT(0x66, u8); /* operand override */ \
499         emith_read_r_r_offs(r, rs, offs); \
500 } while (0)
501
502 #define emith_write16_r_r_offs(r, rs, offs) do { \
503         EMIT(0x66, u8); \
504         emith_write_r_r_offs(r, rs, offs); \
505 } while (0)
506
507 #define emith_ctx_read(r, offs) \
508         emith_read_r_r_offs(r, CONTEXT_REG, offs)
509
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
515 #define emith_ctx_write(r, offs) \
516         emith_write_r_r_offs(r, CONTEXT_REG, offs)
517
518 #define emith_ctx_read_multiple(r, offs, cnt, tmpr) do { \
519         int r_ = r, offs_ = offs, cnt_ = cnt;     \
520         for (; cnt_ > 0; r_++, offs_ += 4, cnt_--) \
521                 emith_ctx_read(r_, offs_);        \
522 } while (0)
523
524 #define emith_ctx_write_multiple(r, offs, cnt, tmpr) do { \
525         int r_ = r, offs_ = offs, cnt_ = cnt;     \
526         for (; cnt_ > 0; r_++, offs_ += 4, cnt_--) \
527                 emith_ctx_write(r_, offs_);       \
528 } while (0)
529
530 // assumes EBX is free
531 #define emith_ret_to_ctx(offs) { \
532         emith_pop(xBX); \
533         emith_ctx_write(xBX, offs); \
534 }
535
536 #define emith_jump(ptr) { \
537         u32 disp = (u8 *)(ptr) - ((u8 *)tcache_ptr + 5); \
538         EMIT_OP(0xe9); \
539         EMIT(disp, u32); \
540 }
541
542 #define emith_jump_patchable(target) \
543         emith_jump(target)
544
545 #define emith_jump_cond(cond, ptr) do { \
546         u32 disp = (u8 *)(ptr) - ((u8 *)tcache_ptr + 6); \
547         EMIT(0x0f, u8); \
548         EMIT_OP(0x80 | (cond)); \
549         EMIT(disp, u32); \
550 } while (0)
551
552 #define emith_jump_cond_patchable(cond, target) \
553         emith_jump_cond(cond, target)
554
555 #define emith_jump_patch(ptr, target) do { \
556         u32 disp_ = (u8 *)(target) - ((u8 *)(ptr) + 4); \
557         u32 offs_ = (*(u8 *)(ptr) == 0x0f) ? 2 : 1; \
558         EMIT_PTR((u8 *)(ptr) + offs_, disp_ - offs_, u32); \
559 } while (0)
560
561 #define emith_jump_at(ptr, target) { \
562         u32 disp_ = (u8 *)(target) - ((u8 *)(ptr) + 5); \
563         EMIT_PTR(ptr, 0xe9, u8); \
564         EMIT_PTR((u8 *)(ptr) + 1, disp_, u32); \
565 }
566
567 #define emith_call(ptr) { \
568         u32 disp = (u8 *)(ptr) - ((u8 *)tcache_ptr + 5); \
569         EMIT_OP(0xe8); \
570         EMIT(disp, u32); \
571 }
572
573 #define emith_call_cond(cond, ptr) \
574         emith_call(ptr)
575
576 #define emith_call_reg(r) \
577         EMIT_OP_MODRM(0xff, 3, 2, r)
578
579 #define emith_call_ctx(offs) do { \
580         EMIT_OP_MODRM(0xff, 2, 2, CONTEXT_REG); \
581         EMIT(offs, u32); \
582 } while (0)
583
584 #define emith_ret() \
585         EMIT_OP(0xc3)
586
587 #define emith_jump_reg(r) \
588         EMIT_OP_MODRM(0xff, 3, 4, r)
589
590 #define emith_jump_ctx(offs) do { \
591         EMIT_OP_MODRM(0xff, 2, 4, CONTEXT_REG); \
592         EMIT(offs, u32); \
593 } while (0)
594
595 #define emith_push_ret()
596
597 #define emith_pop_and_ret() \
598         emith_ret()
599
600 #define EMITH_JMP_START(cond) { \
601         u8 *cond_ptr; \
602         JMP8_POS(cond_ptr)
603
604 #define EMITH_JMP_END(cond) \
605         JMP8_EMIT(cond, cond_ptr); \
606 }
607
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
620 // "simple" jump (no more then a few insns)
621 // ARM will use conditional instructions here
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
631 #define EMITH_SJMP_START EMITH_JMP_START
632 #define EMITH_SJMP_END EMITH_JMP_END
633
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
638 #define emith_pass_arg_r(arg, reg) do { \
639         int rd = 7; \
640         host_arg2reg(rd, arg); \
641         emith_move_r_r_ptr(rd, reg); \
642 } while (0)
643
644 #define emith_pass_arg_imm(arg, imm) do { \
645         int rd = 7; \
646         host_arg2reg(rd, arg); \
647         emith_move_r_imm(rd, imm); \
648 } while (0)
649
650 #define host_instructions_updated(base, end)
651
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
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
694 #define emith_sh2_drc_entry() { \
695         emith_push(xBX);        \
696         emith_push(xBP);        \
697         emith_push(xSI);        \
698         emith_push(xDI);        \
699 }
700
701 #define emith_sh2_drc_exit() {  \
702         emith_pop(xDI);         \
703         emith_pop(xSI);         \
704         emith_pop(xBP);         \
705         emith_pop(xBX);         \
706         emith_ret();            \
707 }
708
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
727 #define emith_sh2_wcall(a, tab) { \
728         int arg2_; \
729         host_arg2reg(arg2_, 2); \
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); \
736 }
737
738 #define emith_sh2_dtbf_loop() { \
739         u8 *jmp0; /* negative cycles check */            \
740         u8 *jmp1; /* unsinged overflow check */          \
741         int cr, rn;                                      \
742         int tmp_ = rcache_get_tmp();                     \
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;                                      \
748         emith_asr(tmp_, cr, 2+12);                       \
749         JMP8_POS(jmp0); /* no negative cycles */         \
750         emith_move_r_imm(tmp_, 0);                       \
751         JMP8_EMIT(ICOND_JNS, jmp0);                      \
752         emith_and_r_imm(cr, 0xffe);                      \
753         emith_subf_r_r(rn, tmp_);                        \
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);                         \
760         JMP8_EMIT(ICOND_JA, jmp1);                       \
761         rcache_free_tmp(tmp_);                           \
762 }
763
764 #define emith_write_sr(sr, srcr) { \
765         int tmp_ = rcache_get_tmp(); \
766         emith_clear_msb(tmp_, srcr, 22); \
767         emith_bic_r_imm(sr, 0x3ff); \
768         emith_or_r_r(sr, tmp_); \
769         rcache_free_tmp(tmp_); \
770 }
771
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)
777
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();              \
788         emith_eor_r_r(tmp_, tmp_);                \
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 */   \
793         JMP8_EMIT(ICOND_JE, jmp0); /* do_sub: */  \
794         emith_sub_r_r(rn, rm);                    \
795         JMP8_EMIT_NC(jmp1);      /* done: */      \
796         emith_adc_r_r(tmp_, tmp_);                \
797         emith_eor_r_r(sr, tmp_);                  \
798         rcache_free_tmp(tmp_);                    \
799 }
800