32x: drc: handlers wip
[picodrive.git] / cpu / drc / emit_x86.c
CommitLineData
679af8a3 1#include <stdarg.h>
2
f4bb5d6b 3enum { 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