32x: drc: new smc handling, write handlers adjusted.
[picodrive.git] / cpu / drc / emit_x86.c
1 #include <stdarg.h>
2
3 #if (DRC_DEBUG & 1)
4 #define COUNT_OP \
5         host_insn_count++
6 #else
7 #define COUNT_OP
8 #endif
9
10 enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
11
12 // TODO: move
13 static int reg_map_g2h[] = {
14         -1, -1, -1, -1,
15         -1, -1, -1, -1,
16         -1, -1, -1, -1,
17         -1, -1, -1, -1,
18         -1, -1, -1, -1,
19         -1, -1, -1, -1,
20 };
21
22 #define CONTEXT_REG xBP
23
24 #define EMIT_PTR(ptr, val, type) \
25         *(type *)(ptr) = val
26
27 #define EMIT(val, type) { \
28         EMIT_PTR(tcache_ptr, val, type); \
29         tcache_ptr += sizeof(type); \
30 }
31
32 #define EMIT_OP(op) { \
33         COUNT_OP; \
34         EMIT(op, u8); \
35 }
36
37 #define EMIT_MODRM(mod,r,rm) \
38         EMIT(((mod)<<6) | ((r)<<3) | (rm), u8)
39
40 #define EMIT_OP_MODRM(op,mod,r,rm) { \
41         EMIT_OP(op); \
42         EMIT_MODRM(mod, r, rm); \
43 }
44
45 #define emith_move_r_r(dst, src) \
46         EMIT_OP_MODRM(0x8b, 3, dst, src)
47
48 #define emith_move_r_imm(r, imm) { \
49         EMIT_OP(0xb8 + (r)); \
50         EMIT(imm, u32); \
51 }
52
53 #define emith_add_r_imm(r, imm) { \
54         EMIT_OP_MODRM(0x81, 3, 0, r); \
55         EMIT(imm, u32); \
56 }
57
58 #define emith_sub_r_imm(r, imm) { \
59         EMIT_OP_MODRM(0x81, 3, 5, r); \
60         EMIT(imm, u32); \
61 }
62
63 // XXX: offs is 8bit only
64 #define emith_ctx_read(r, offs) { \
65         EMIT_OP_MODRM(0x8b, 1, r, 5); \
66         EMIT(offs, u8);         /* mov tmp, [ebp+#offs] */ \
67 }
68
69 #define emith_ctx_write(r, offs) { \
70         EMIT_OP_MODRM(0x89, 1, r, 5); \
71         EMIT(offs, u8);         /* mov [ebp+#offs], tmp */ \
72 }
73
74 #define emith_ctx_sub(val, offs) { \
75         EMIT_OP_MODRM(0x81, 1, 5, 5); \
76         EMIT(offs, u8); \
77         EMIT(val, u32);         /* sub [ebp+#offs], dword val */ \
78 }
79
80 #define emith_test_t() { \
81         if (reg_map_g2h[SHR_SR] == -1) { \
82                 EMIT_OP_MODRM(0xf6, 1, 0, 5); \
83                 EMIT(SHR_SR * 4, u8); \
84                 EMIT(0x01, u8); /* test [ebp+SHR_SR], byte 1 */ \
85         } else { \
86                 EMIT_OP_MODRM(0xf7, 3, 0, reg_map_g2h[SHR_SR]); \
87                 EMIT(0x01, u16); /* test <reg>, word 1 */ \
88         } \
89 }
90
91 #define emith_jump(ptr) { \
92         u32 disp = (u32)ptr - ((u32)tcache_ptr + 5); \
93         EMIT_OP(0xe9); \
94         EMIT(disp, u32); \
95 }
96
97 #define emith_call(ptr) { \
98         u32 disp = (u32)ptr - ((u32)tcache_ptr + 5); \
99         EMIT_OP(0xe8); \
100         EMIT(disp, u32); \
101 }
102
103 #define EMIT_CONDITIONAL(code, is_nonzero) { \
104         u8 *ptr = tcache_ptr; \
105         tcache_ptr = tcache_ptr + 2; \
106         code; \
107         EMIT_PTR(ptr, ((is_nonzero) ? 0x75 : 0x74), u8); \
108         EMIT_PTR(ptr + 1, (tcache_ptr - (ptr + 2)), u8); \
109 }
110
111 #define arg2reg(rd, arg) \
112         switch (arg) { \
113         case 0: rd = xAX; break; \
114         case 1: rd = xDX; break; \
115         case 2: rd = xCX; break; \
116         }
117
118 #define emith_pass_arg_r(arg, reg) { \
119         int rd = 7; \
120         arg2reg(rd, arg); \
121         emith_move_r_r(rd, reg); \
122 }
123
124 #define emith_pass_arg_imm(arg, imm) { \
125         int rd = 7; \
126         arg2reg(rd, arg); \
127         emith_move_r_imm(rd, imm); \
128 }
129