Mercurial > repos > blastem
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); |