comparison gen_x86.c @ 343:467bfa17004a

Mostly working runtime generation of memory map read/write functions
author Mike Pavone <pavone@retrodev.com>
date Sat, 18 May 2013 11:44:42 -0700
parents 1788e3f29c28
children ad493d38964e
comparison
equal deleted inserted replaced
342:13f994c88c34 343:467bfa17004a
1 #include "gen_x86.h" 1 #include "gen_x86.h"
2 #include "68kinst.h" 2 #include "68kinst.h"
3 #include <stddef.h> 3 #include <stddef.h>
4 #include <stdio.h> 4 #include <stdio.h>
5 #include <stdlib.h>
5 6
6 #define REX_RM_FIELD 0x1 7 #define REX_RM_FIELD 0x1
7 #define REX_SIB_FIELD 0x2 8 #define REX_SIB_FIELD 0x2
8 #define REX_REG_FIELD 0x4 9 #define REX_REG_FIELD 0x4
9 #define REX_QUAD 0x8 10 #define REX_QUAD 0x8
218 } 219 }
219 *(out++) = disp; 220 *(out++) = disp;
220 return out; 221 return out;
221 } 222 }
222 223
224 uint8_t * x86_rrdisp32_sizedir(uint8_t * out, uint16_t opcode, uint8_t reg, uint8_t base, int32_t disp, uint8_t size, uint8_t dir)
225 {
226 //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
227 uint8_t tmp;
228 if (size == SZ_W) {
229 *(out++) = PRE_SIZE;
230 }
231 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
232 *out = PRE_REX;
233 if (reg >= AH && reg <= BH) {
234 fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
235 exit(1);
236 }
237 if (size == SZ_Q) {
238 *out |= REX_QUAD;
239 }
240 if (reg >= R8) {
241 *out |= REX_REG_FIELD;
242 reg -= (R8 - X86_R8);
243 }
244 if (base >= R8) {
245 *out |= REX_RM_FIELD;
246 base -= (R8 - X86_R8);
247 }
248 out++;
249 }
250 if (size == SZ_B) {
251 if (reg >= AH && reg <= BH) {
252 reg -= (AH-X86_AH);
253 }
254 } else {
255 opcode |= BIT_SIZE;
256 }
257 opcode |= dir;
258 if (opcode >= 0x100) {
259 *(out++) = opcode >> 8;
260 *(out++) = opcode;
261 } else {
262 *(out++) = opcode;
263 }
264 *(out++) = MODE_REG_DISPLACE32 | base | (reg << 3);
265 if (base == RSP) {
266 //add SIB byte, with no index and RSP as base
267 *(out++) = (RSP << 3) | RSP;
268 }
269 *(out++) = disp;
270 *(out++) = disp >> 8;
271 *(out++) = disp >> 16;
272 *(out++) = disp >> 24;
273 return out;
274 }
275
223 uint8_t * x86_rrind_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir) 276 uint8_t * x86_rrind_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir)
224 { 277 {
225 //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 278 //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
226 uint8_t tmp; 279 uint8_t tmp;
227 if (size == SZ_W) { 280 if (size == SZ_W) {
256 *(out++) = opcode | dir; 309 *(out++) = opcode | dir;
257 *(out++) = MODE_REG_INDIRECT | base | (reg << 3); 310 *(out++) = MODE_REG_INDIRECT | base | (reg << 3);
258 if (base == RSP) { 311 if (base == RSP) {
259 //add SIB byte, with no index and RSP as base 312 //add SIB byte, with no index and RSP as base
260 *(out++) = (RSP << 3) | RSP; 313 *(out++) = (RSP << 3) | RSP;
314 }
315 return out;
316 }
317
318 uint8_t * x86_rrindex_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t index, uint8_t scale, uint8_t size, uint8_t dir)
319 {
320 //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
321 uint8_t tmp;
322 if (size == SZ_W) {
323 *(out++) = PRE_SIZE;
324 }
325 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
326 *out = PRE_REX;
327 if (reg >= AH && reg <= BH) {
328 fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
329 exit(1);
330 }
331 if (size == SZ_Q) {
332 *out |= REX_QUAD;
333 }
334 if (reg >= R8) {
335 *out |= REX_REG_FIELD;
336 reg -= (R8 - X86_R8);
337 }
338 if (base >= R8) {
339 *out |= REX_RM_FIELD;
340 base -= (R8 - X86_R8);
341 }
342 if (index >= R8) {
343 *out |= REX_SIB_FIELD;
344 index -= (R8 - X86_R8);
345 }
346 out++;
347 }
348 if (size == SZ_B) {
349 if (reg >= AH && reg <= BH) {
350 reg -= (AH-X86_AH);
351 }
352 } else {
353 opcode |= BIT_SIZE;
354 }
355 *(out++) = opcode | dir;
356 *(out++) = MODE_REG_INDIRECT | base | (RSP << 3);
357 if (base == RSP) {
358 if (scale == 4) {
359 scale = 3;
360 }
361 *(out++) = scale << 6 | (index << 3) | base;
261 } 362 }
262 return out; 363 return out;
263 } 364 }
264 365
265 uint8_t * x86_r_size(uint8_t * out, uint8_t opcode, uint8_t opex, uint8_t dst, uint8_t size) 366 uint8_t * x86_r_size(uint8_t * out, uint8_t opcode, uint8_t opex, uint8_t dst, uint8_t size)
947 uint8_t * mov_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) 1048 uint8_t * mov_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
948 { 1049 {
949 return x86_rrdisp8_sizedir(out, OP_MOV, dst, src_base, disp, size, BIT_DIR); 1050 return x86_rrdisp8_sizedir(out, OP_MOV, dst, src_base, disp, size, BIT_DIR);
950 } 1051 }
951 1052
1053 uint8_t * mov_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1054 {
1055 return x86_rrdisp32_sizedir(out, OP_MOV, src, dst_base, disp, size, 0);
1056 }
1057
1058 uint8_t * mov_rdisp32r(uint8_t * out, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1059 {
1060 return x86_rrdisp32_sizedir(out, OP_MOV, dst, src_base, disp, size, BIT_DIR);
1061 }
1062
952 uint8_t * mov_rrind(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) 1063 uint8_t * mov_rrind(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
953 { 1064 {
954 return x86_rrind_sizedir(out, OP_MOV, src, dst, size, 0); 1065 return x86_rrind_sizedir(out, OP_MOV, src, dst, size, 0);
955 } 1066 }
956 1067
957 uint8_t * mov_rindr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) 1068 uint8_t * mov_rindr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
958 { 1069 {
959 return x86_rrind_sizedir(out, OP_MOV, dst, src, size, BIT_DIR); 1070 return x86_rrind_sizedir(out, OP_MOV, dst, src, size, BIT_DIR);
1071 }
1072
1073 uint8_t * mov_rrindex(uint8_t * out, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size)
1074 {
1075 return x86_rrindex_sizedir(out, OP_MOV, src, dst_base, dst_index, scale, size, 0);
1076 }
1077
1078 uint8_t * mov_rindexr(uint8_t * out, uint8_t src_base, uint8_t src_index, uint8_t scale, uint8_t dst, uint8_t size)
1079 {
1080 return x86_rrindex_sizedir(out, OP_MOV, dst, src_base, src_index, scale, size, BIT_DIR);
960 } 1081 }
961 1082
962 uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size) 1083 uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size)
963 { 1084 {
964 uint8_t sign_extend = 0; 1085 uint8_t sign_extend = 0;
1368 *(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3); 1489 *(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3);
1369 *(out++) = dst_disp; 1490 *(out++) = dst_disp;
1370 return out; 1491 return out;
1371 } 1492 }
1372 1493
1494 uint8_t * bit_rrdisp32(uint8_t * out, uint8_t op2, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1495 {
1496 if (size == SZ_W) {
1497 *(out++) = PRE_SIZE;
1498 }
1499 if (size == SZ_Q || src >= R8 || dst_base >= R8) {
1500 *out = PRE_REX;
1501 if (size == SZ_Q) {
1502 *out |= REX_QUAD;
1503 }
1504 if (src >= R8) {
1505 *out |= REX_REG_FIELD;
1506 src -= (R8 - X86_R8);
1507 }
1508 if (dst_base >= R8) {
1509 *out |= REX_RM_FIELD;
1510 dst_base -= (R8 - X86_R8);
1511 }
1512 out++;
1513 }
1514 *(out++) = PRE_2BYTE;
1515 *(out++) = op2;
1516 *(out++) = MODE_REG_DISPLACE32 | dst_base | (src << 3);
1517 *(out++) = dst_disp;
1518 *(out++) = dst_disp >> 8;
1519 *(out++) = dst_disp >> 16;
1520 *(out++) = dst_disp >> 24;
1521 return out;
1522 }
1523
1373 uint8_t * bit_ir(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size) 1524 uint8_t * bit_ir(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size)
1374 { 1525 {
1375 if (size == SZ_W) { 1526 if (size == SZ_W) {
1376 *(out++) = PRE_SIZE; 1527 *(out++) = PRE_SIZE;
1377 } 1528 }
1423 } 1574 }
1424 1575
1425 uint8_t * bt_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size) 1576 uint8_t * bt_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size)
1426 { 1577 {
1427 return bit_rrdisp8(out, OP2_BT, src, dst_base, dst_disp, size); 1578 return bit_rrdisp8(out, OP2_BT, src, dst_base, dst_disp, size);
1579 }
1580
1581 uint8_t * bt_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1582 {
1583 return bit_rrdisp32(out, OP2_BT, src, dst_base, dst_disp, size);
1428 } 1584 }
1429 1585
1430 uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) 1586 uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
1431 { 1587 {
1432 return bit_ir(out, OP_EX_BT, val, dst, size); 1588 return bit_ir(out, OP_EX_BT, val, dst, size);