comparison gen_x86.c @ 14:2bdad0f52f42

x86 code gen, initial work on translator
author Mike Pavone <pavone@retrodev.com>
date Tue, 27 Nov 2012 09:28:13 -0800
parents
children c0f339564819
comparison
equal deleted inserted replaced
13:168b1a873895 14:2bdad0f52f42
1 #include "gen_x86.h"
2 #include "68kinst.h"
3 #include <stddef.h>
4 #include <stdio.h>
5
6 #define REX_RM_FIELD 0x1
7 #define REX_SIB_FIELD 0x2
8 #define REX_REG_FIELD 0x4
9 #define REX_QUAD 0x8
10
11 #define OP_ADD 0x00
12 #define OP_OR 0x08
13 #define PRE_2BYTE 0x0F
14 #define OP_ADC 0x10
15 #define OP_SBB 0x18
16 #define OP_AND 0x20
17 #define OP_SUB 0x28
18 #define OP_XOR 0x30
19 #define OP_CMP 0x38
20 #define PRE_REX 0x40
21 #define OP_PUSH 0x50
22 #define OP_POP 0x58
23 #define PRE_SIZE 0x66
24 #define OP_JCC 0x70
25 #define OP_IMMED_ARITH 0x80
26 #define OP_MOV 0x88
27 #define OP_PUSHF 0x9C
28 #define OP_POPF 0x9D
29 #define OP_MOV_I8R 0xB0
30 #define OP_MOV_IR 0xB8
31 #define OP_RETN 0xC3
32 #define OP_CALL 0xE8
33 #define OP_CALL_EA 0xFF
34
35 #define OP2_JCC 0x80
36 #define OP2_SETCC 0x90
37
38 #define OP_EX_ADDI 0x0
39 #define OP_EX_ORI 0x1
40 #define OP_EX_ADCI 0x2
41 #define OP_EX_SBBI 0x3
42 #define OP_EX_ANDI 0x4
43 #define OP_EX_SUBI 0x5
44 #define OP_EX_XORI 0x6
45 #define OP_EX_CMPI 0x7
46
47 #define BIT_IMMED_RAX 0x4
48 #define BIT_DIR 0x2
49 #define BIT_SIZE 0x1
50
51 #define M68K_N_REG RBX
52 #define M68K_V_REG BH
53 #define M68K_Z_REG RDX
54 #define M68K_C_REG DH
55
56 #define M68K_SCRATCH RCX
57
58 enum {
59 X86_RAX = 0,
60 X86_RCX,
61 X86_RDX,
62 X86_RBX,
63 X86_RSP,
64 X86_RBP,
65 X86_RSI,
66 X86_RDI,
67 X86_AH=4,
68 X86_CH,
69 X86_DH,
70 X86_BH,
71 X86_R8=0,
72 X86_R9,
73 X86_R10,
74 X86_R11,
75 X86_R12,
76 X86_R13,
77 X86_R14,
78 X86_R15
79 } x86_regs_enc;
80
81 enum {
82 MODE_REG_INDIRECT = 0,
83 MODE_REG_DISPLACE8 = 0x40,
84 MODE_REG_DIPSLACE32 = 0x80,
85 MODE_REG_DIRECT = 0xC0
86 } x86_modes;
87
88 uint8_t * x86_rr_sizedir(uint8_t * out, uint8_t opcode, uint8_t src, uint8_t dst, uint8_t size)
89 {
90 //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
91 uint8_t tmp;
92 if (size == SZ_W) {
93 *(out++) = PRE_SIZE;
94 }
95 if (size == SZ_B && dst >= RSP && dst <= RDI) {
96 opcode |= BIT_DIR;
97 tmp = dst;
98 dst = src;
99 src = dst;
100 }
101 if (size == SZ_Q || src >= R8 || dst >= R8 || (size == SZ_B && src >= RSP && src <= RDI)) {
102 *out = PRE_REX;
103 if (size == SZ_Q) {
104 *out |= REX_QUAD;
105 }
106 if (src >= R8) {
107 *out |= REX_REG_FIELD;
108 src -= (R8 - X86_R8);
109 }
110 if (dst >= R8) {
111 *out |= REX_RM_FIELD;
112 dst -= (R8 - X86_R8);
113 }
114 out++;
115 }
116 if (size == SZ_B) {
117 if (src >= AH && src <= BH) {
118 src -= (AH-X86_AH);
119 }
120 if (dst >= AH && dst <= BH) {
121 dst -= (AH-X86_AH);
122 }
123 } else {
124 opcode |= BIT_SIZE;
125 }
126 *(out++) = opcode;
127 *(out++) = MODE_REG_DIRECT | dst | (src << 3);
128 return out;
129 }
130
131 uint8_t * x86_rrdisp8_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, int8_t disp, uint8_t size, uint8_t dir)
132 {
133 //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
134 uint8_t tmp;
135 if (size == SZ_W) {
136 *(out++) = PRE_SIZE;
137 }
138 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
139 *out = PRE_REX;
140 if (size == SZ_Q) {
141 *out |= REX_QUAD;
142 }
143 if (reg >= R8) {
144 *out |= REX_REG_FIELD;
145 reg -= (R8 - X86_R8);
146 }
147 if (base >= R8) {
148 *out |= REX_RM_FIELD;
149 base -= (R8 - X86_R8);
150 }
151 out++;
152 }
153 if (size == SZ_B) {
154 if (reg >= AH && reg <= BH) {
155 reg -= (AH-X86_AH);
156 }
157 } else {
158 opcode |= BIT_SIZE;
159 }
160 *(out++) = opcode | dir;
161 *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
162 *(out++) = disp;
163 return out;
164 }
165
166 uint8_t * x86_rrind_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir)
167 {
168 //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
169 uint8_t tmp;
170 if (size == SZ_W) {
171 *(out++) = PRE_SIZE;
172 }
173 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
174 *out = PRE_REX;
175 if (size == SZ_Q) {
176 *out |= REX_QUAD;
177 }
178 if (reg >= R8) {
179 *out |= REX_REG_FIELD;
180 reg -= (R8 - X86_R8);
181 }
182 if (base >= R8) {
183 *out |= REX_RM_FIELD;
184 base -= (R8 - X86_R8);
185 }
186 out++;
187 }
188 if (size == SZ_B) {
189 if (reg >= AH && reg <= BH) {
190 reg -= (AH-X86_AH);
191 }
192 } else {
193 opcode |= BIT_SIZE;
194 }
195 *(out++) = opcode | dir;
196 *(out++) = MODE_REG_INDIRECT | base | (reg << 3);
197 return out;
198 }
199
200 uint8_t * x86_i8r(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, uint8_t val, uint8_t dst)
201 {
202 if (dst == RAX) {
203 *(out++) = al_opcode | BIT_IMMED_RAX;
204 } else {
205 if (dst >= AH && dst <= BH) {
206 dst -= (AH-X86_AH);
207 } else if(dst >= R8) {
208 *(out++) = PRE_REX | REX_RM_FIELD;
209 }
210 *(out++) = opcode;
211 *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3);
212 }
213 *(out++) = val;
214 return out;
215 }
216
217 uint8_t * x86_i32r(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, int32_t val, uint8_t dst)
218 {
219 uint8_t sign_extend = 0;
220 if (val <= 0x7F && val >= -0x80) {
221 sign_extend = 1;
222 opcode |= BIT_DIR;
223 }
224 if (dst == RAX && !sign_extend) {
225 *(out++) = al_opcode | BIT_IMMED_RAX | BIT_SIZE;
226 } else {
227 if(dst >= R8) {
228 *(out++) = PRE_REX | REX_RM_FIELD;
229 }
230 *(out++) = opcode | BIT_SIZE;
231 *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3);
232 }
233 *(out++) = val;
234 if (!sign_extend) {
235 val >>= 8;
236 *(out++) = val;
237 val >>= 8;
238 *(out++) = val;
239 val >>= 8;
240 *(out++) = val;
241 }
242 return out;
243 }
244
245 uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
246 {
247 return x86_rr_sizedir(out, OP_ADD, src, dst, size);
248 }
249
250 uint8_t * add_i8r(uint8_t * out, uint8_t val, uint8_t dst)
251 {
252 return x86_i8r(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst);
253 }
254
255 uint8_t * add_i32r(uint8_t * out, int32_t val, uint8_t dst)
256 {
257 return x86_i32r(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst);
258 }
259
260 uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
261 {
262 return x86_rr_sizedir(out, OP_OR, src, dst, size);
263 }
264
265 uint8_t * or_i8r(uint8_t * out, uint8_t val, uint8_t dst)
266 {
267 return x86_i8r(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst);
268 }
269
270 uint8_t * or_i32r(uint8_t * out, int32_t val, uint8_t dst)
271 {
272 return x86_i32r(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst);
273 }
274
275 uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
276 {
277 return x86_rr_sizedir(out, OP_AND, src, dst, size);
278 }
279
280 uint8_t * and_i8r(uint8_t * out, uint8_t val, uint8_t dst)
281 {
282 return x86_i8r(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst);
283 }
284
285 uint8_t * and_i32r(uint8_t * out, int32_t val, uint8_t dst)
286 {
287 return x86_i32r(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst);
288 }
289
290 uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
291 {
292 return x86_rr_sizedir(out, OP_XOR, src, dst, size);
293 }
294
295 uint8_t * xor_i8r(uint8_t * out, uint8_t val, uint8_t dst)
296 {
297 return x86_i8r(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst);
298 }
299
300 uint8_t * xor_i32r(uint8_t * out, int32_t val, uint8_t dst)
301 {
302 return x86_i32r(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst);
303 }
304
305 uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
306 {
307 return x86_rr_sizedir(out, OP_SUB, src, dst, size);
308 }
309
310 uint8_t * sub_i8r(uint8_t * out, uint8_t val, uint8_t dst)
311 {
312 return x86_i8r(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst);
313 }
314
315 uint8_t * sub_i32r(uint8_t * out, int32_t val, uint8_t dst)
316 {
317 return x86_i32r(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst);
318 }
319
320
321 uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
322 {
323 return x86_rr_sizedir(out, OP_CMP, src, dst, size);
324 }
325
326 uint8_t * cmp_i8r(uint8_t * out, uint8_t val, uint8_t dst)
327 {
328 return x86_i8r(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst);
329 }
330
331 uint8_t * cmp_i32r(uint8_t * out, int32_t val, uint8_t dst)
332 {
333 return x86_i32r(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst);
334 }
335
336 uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
337 {
338 return x86_rr_sizedir(out, OP_MOV, src, dst, size);
339 }
340
341 uint8_t * mov_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
342 {
343 return x86_rrdisp8_sizedir(out, OP_MOV, src, dst_base, disp, size, 0);
344 }
345
346 uint8_t * mov_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
347 {
348 return x86_rrdisp8_sizedir(out, OP_MOV, dst, src_base, disp, size, BIT_DIR);
349 }
350
351 uint8_t * mov_rrind(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
352 {
353 return x86_rrind_sizedir(out, OP_MOV, src, dst, size, 0);
354 }
355
356 uint8_t * mov_rindr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
357 {
358 return x86_rrind_sizedir(out, OP_MOV, dst, src, size, BIT_DIR);
359 }
360
361 uint8_t * mov_i8r(uint8_t * out, uint8_t val, uint8_t dst)
362 {
363 if (dst >= AH && dst <= BH) {
364 dst -= AH - X86_AH;
365 } else if (dst >= RSP && dst <= RDI) {
366 *(out++) = PRE_REX;
367 } else if (dst >= R8) {
368 *(out++) = PRE_REX | REX_RM_FIELD;
369 dst -= R8 - X86_R8;
370 }
371 *(out++) = OP_MOV_I8R | dst;
372 *(out++) = val;
373 return out;
374 }
375
376 uint8_t * mov_i16r(uint8_t * out, uint16_t val, uint8_t dst)
377 {
378 *(out++) = PRE_SIZE;
379 if (dst >= R8) {
380 *(out++) = PRE_REX | REX_RM_FIELD;
381 dst -= R8 - X86_R8;
382 }
383 *(out++) = OP_MOV_IR | dst;
384 *(out++) = val;
385 val >>= 8;
386 *(out++) = val;
387 return out;
388 }
389
390 uint8_t * mov_i32r(uint8_t * out, uint32_t val, uint8_t dst)
391 {
392 if (dst >= R8) {
393 *(out++) = PRE_REX | REX_RM_FIELD;
394 dst -= R8 - X86_R8;
395 }
396 *(out++) = OP_MOV_IR | dst;
397 *(out++) = val;
398 val >>= 8;
399 *(out++) = val;
400 val >>= 8;
401 *(out++) = val;
402 val >>= 8;
403 *(out++) = val;
404 return out;
405 }
406
407 uint8_t * pushf(uint8_t * out)
408 {
409 *(out++) = OP_PUSHF;
410 return out;
411 }
412
413 uint8_t * popf(uint8_t * out)
414 {
415 *(out++) = OP_POPF;
416 return out;
417 }
418
419 uint8_t * push_r(uint8_t * out, uint8_t reg)
420 {
421 if (reg >= R8) {
422 *(out++) = PRE_REX | REX_RM_FIELD;
423 reg -= R8 - X86_R8;
424 }
425 *(out++) = OP_PUSH | reg;
426 return out;
427 }
428
429 uint8_t * pop_r(uint8_t * out, uint8_t reg)
430 {
431 if (reg >= R8) {
432 *(out++) = PRE_REX | REX_RM_FIELD;
433 reg -= R8 - X86_R8;
434 }
435 *(out++) = OP_POP | reg;
436 return out;
437 }
438
439 uint8_t * setcc_r(uint8_t * out, uint8_t cc, uint8_t dst)
440 {
441 if (dst >= R8) {
442 *(out++) = PRE_REX | REX_RM_FIELD;
443 dst -= R8 - X86_R8;
444 } else if (dst >= RSP && dst <= RDI) {
445 *(out++) = PRE_REX;
446 } else if (dst >= AH && dst <= BH) {
447 dst -= AH - X86_AH;
448 }
449 *(out++) = PRE_2BYTE;
450 *(out++) = OP2_SETCC | cc;
451 *(out++) = MODE_REG_DIRECT | dst;
452 return out;
453 }
454
455 uint8_t * setcc_rind(uint8_t * out, uint8_t cc, uint8_t dst)
456 {
457 if (dst >= R8) {
458 *(out++) = PRE_REX | REX_RM_FIELD;
459 dst -= R8 - X86_R8;
460 }
461 *(out++) = PRE_2BYTE;
462 *(out++) = OP2_SETCC | cc;
463 *(out++) = MODE_REG_INDIRECT | dst;
464 return out;
465 }
466
467 uint8_t * jcc(uint8_t * out, uint8_t cc, int32_t disp)
468 {
469 if (disp <= 0x7F && disp >= -0x80) {
470 *(out++) = OP_JCC | cc;
471 *(out++) = disp;
472 } else {
473 *(out++) = PRE_2BYTE;
474 *(out++) = OP2_JCC | cc;
475 *(out++) = disp;
476 disp >>= 8;
477 *(out++) = disp;
478 disp >>= 8;
479 *(out++) = disp;
480 disp >>= 8;
481 *(out++) = disp;
482 }
483 return out;
484 }
485
486 uint8_t * call(uint8_t * out, uint8_t * fun)
487 {
488 ptrdiff_t disp = fun-(out+5);
489 if (disp <= 0x7FFFFFFF && disp >= -2147483648) {
490 *(out++) = OP_CALL;
491 *(out++) = disp;
492 disp >>= 8;
493 *(out++) = disp;
494 disp >>= 8;
495 *(out++) = disp;
496 disp >>= 8;
497 *(out++) = disp;
498 } else {
499 //TODO: Implement far call
500 printf("%p - %p = %ld, %d, %d, %d\n", fun, out + 5, disp, disp <= 0x7FFFFFFF, disp >= (-2147483648), -2147483648);
501 return NULL;
502 }
503 return out;
504 }
505
506 uint8_t * retn(uint8_t * out)
507 {
508 *(out++) = OP_RETN;
509 return out;
510 }
511
512