Mercurial > repos > blastem
comparison m68k_core_x86.c @ 582:c05fcbfe1b1a
Refactored translate_m68k so that it contains no host-cpu specific code and moved it to m68k_core.c
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 07 Mar 2014 17:42:29 -0800 |
parents | 9f40aa5243c2 |
children | 819921b76b4b |
comparison
equal
deleted
inserted
replaced
581:9f40aa5243c2 | 582:c05fcbfe1b1a |
---|---|
333 { | 333 { |
334 areg_to_native(opts, op->params.regs.pri, native_reg); | 334 areg_to_native(opts, op->params.regs.pri, native_reg); |
335 calc_index_disp8(opts, op, native_reg); | 335 calc_index_disp8(opts, op, native_reg); |
336 } | 336 } |
337 | 337 |
338 void translate_m68k_op(m68kinst * inst, x86_ea * ea, m68k_options * opts, uint8_t dst) | 338 void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst) |
339 { | 339 { |
340 code_info *code = &opts->gen.code; | 340 code_info *code = &opts->gen.code; |
341 m68k_op_info *op = dst ? &inst->dst : &inst->src; | 341 m68k_op_info *op = dst ? &inst->dst : &inst->src; |
342 int8_t reg = native_reg(op, opts); | 342 int8_t reg = native_reg(op, opts); |
343 uint8_t sec_reg; | 343 uint8_t sec_reg; |
534 code_info *code = &opts->gen.code; | 534 code_info *code = &opts->gen.code; |
535 int8_t reg, flags_reg, sec_reg; | 535 int8_t reg, flags_reg, sec_reg; |
536 uint8_t dir = 0; | 536 uint8_t dir = 0; |
537 int32_t offset; | 537 int32_t offset; |
538 int32_t inc_amount, dec_amount; | 538 int32_t inc_amount, dec_amount; |
539 x86_ea src; | 539 host_ea src; |
540 translate_m68k_op(inst, &src, opts, 0); | 540 translate_m68k_op(inst, &src, opts, 0); |
541 reg = native_reg(&(inst->dst), opts); | 541 reg = native_reg(&(inst->dst), opts); |
542 | 542 |
543 if (inst->dst.addr_mode != MODE_AREG) { | 543 if (inst->dst.addr_mode != MODE_AREG) { |
544 if (src.mode == MODE_REG_DIRECT) { | 544 if (src.mode == MODE_REG_DIRECT) { |
849 if (reg >= 0) { | 849 if (reg >= 0) { |
850 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 6 : 4)); | 850 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 6 : 4)); |
851 xor_rr(code, reg, reg, inst->extra.size); | 851 xor_rr(code, reg, reg, inst->extra.size); |
852 return; | 852 return; |
853 } | 853 } |
854 x86_ea dst_op; | 854 host_ea dst_op; |
855 //TODO: fix timing | 855 //TODO: fix timing |
856 translate_m68k_op(inst, &dst_op, opts, 1); | 856 translate_m68k_op(inst, &dst_op, opts, 1); |
857 if (dst_op.mode == MODE_REG_DIRECT) { | 857 if (dst_op.mode == MODE_REG_DIRECT) { |
858 xor_rr(code, dst_op.base, dst_op.base, inst->extra.size); | 858 xor_rr(code, dst_op.base, dst_op.base, inst->extra.size); |
859 } else { | 859 } else { |
863 } | 863 } |
864 | 864 |
865 void translate_m68k_ext(m68k_options * opts, m68kinst * inst) | 865 void translate_m68k_ext(m68k_options * opts, m68kinst * inst) |
866 { | 866 { |
867 code_info *code = &opts->gen.code; | 867 code_info *code = &opts->gen.code; |
868 x86_ea dst_op; | 868 host_ea dst_op; |
869 uint8_t dst_size = inst->extra.size; | 869 uint8_t dst_size = inst->extra.size; |
870 inst->extra.size--; | 870 inst->extra.size--; |
871 translate_m68k_op(inst, &dst_op, opts, 1); | 871 translate_m68k_op(inst, &dst_op, opts, 1); |
872 if (dst_op.mode == MODE_REG_DIRECT) { | 872 if (dst_op.mode == MODE_REG_DIRECT) { |
873 movsx_rr(code, dst_op.base, dst_op.base, inst->extra.size, dst_size); | 873 movsx_rr(code, dst_op.base, dst_op.base, inst->extra.size, dst_size); |
951 | 951 |
952 void translate_m68k_scc(m68k_options * opts, m68kinst * inst) | 952 void translate_m68k_scc(m68k_options * opts, m68kinst * inst) |
953 { | 953 { |
954 code_info *code = &opts->gen.code; | 954 code_info *code = &opts->gen.code; |
955 uint8_t cond = inst->extra.cond; | 955 uint8_t cond = inst->extra.cond; |
956 x86_ea dst_op; | 956 host_ea dst_op; |
957 inst->extra.size = OPSIZE_BYTE; | 957 inst->extra.size = OPSIZE_BYTE; |
958 translate_m68k_op(inst, &dst_op, opts, 1); | 958 translate_m68k_op(inst, &dst_op, opts, 1); |
959 if (cond == COND_TRUE || cond == COND_FALSE) { | 959 if (cond == COND_TRUE || cond == COND_FALSE) { |
960 if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) { | 960 if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) { |
961 cycles(&opts->gen, 6); | 961 cycles(&opts->gen, 6); |
1125 typedef void (*shift_ir_t)(code_info *code, uint8_t val, uint8_t dst, uint8_t size); | 1125 typedef void (*shift_ir_t)(code_info *code, uint8_t val, uint8_t dst, uint8_t size); |
1126 typedef void (*shift_irdisp_t)(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size); | 1126 typedef void (*shift_irdisp_t)(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size); |
1127 typedef void (*shift_clr_t)(code_info *code, uint8_t dst, uint8_t size); | 1127 typedef void (*shift_clr_t)(code_info *code, uint8_t dst, uint8_t size); |
1128 typedef void (*shift_clrdisp_t)(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); | 1128 typedef void (*shift_clrdisp_t)(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); |
1129 | 1129 |
1130 void translate_shift(m68k_options * opts, m68kinst * inst, x86_ea *src_op, x86_ea * dst_op, shift_ir_t shift_ir, shift_irdisp_t shift_irdisp, shift_clr_t shift_clr, shift_clrdisp_t shift_clrdisp, shift_ir_t special, shift_irdisp_t special_disp) | 1130 void translate_shift(m68k_options * opts, m68kinst * inst, host_ea *src_op, host_ea * dst_op, shift_ir_t shift_ir, shift_irdisp_t shift_irdisp, shift_clr_t shift_clr, shift_clrdisp_t shift_clrdisp, shift_ir_t special, shift_irdisp_t special_disp) |
1131 { | 1131 { |
1132 code_info *code = &opts->gen.code; | 1132 code_info *code = &opts->gen.code; |
1133 code_ptr end_off = NULL; | 1133 code_ptr end_off = NULL; |
1134 code_ptr nz_off = NULL; | 1134 code_ptr nz_off = NULL; |
1135 code_ptr z_off = NULL; | 1135 code_ptr z_off = NULL; |
1302 case M68K_AND: and_ir(code, val, dst, size); break; | 1302 case M68K_AND: and_ir(code, val, dst, size); break; |
1303 case M68K_BTST: bt_ir(code, val, dst, size); break; | 1303 case M68K_BTST: bt_ir(code, val, dst, size); break; |
1304 case M68K_BSET: bts_ir(code, val, dst, size); break; | 1304 case M68K_BSET: bts_ir(code, val, dst, size); break; |
1305 case M68K_BCLR: btr_ir(code, val, dst, size); break; | 1305 case M68K_BCLR: btr_ir(code, val, dst, size); break; |
1306 case M68K_BCHG: btc_ir(code, val, dst, size); break; | 1306 case M68K_BCHG: btc_ir(code, val, dst, size); break; |
1307 case M68K_CMP: cmp_ir(code, val, dst, size); break; | |
1307 case M68K_EOR: xor_ir(code, val, dst, size); break; | 1308 case M68K_EOR: xor_ir(code, val, dst, size); break; |
1308 case M68K_OR: or_ir(code, val, dst, size); break; | 1309 case M68K_OR: or_ir(code, val, dst, size); break; |
1309 case M68K_ROL: rol_ir(code, val, dst, size); break; | 1310 case M68K_ROL: rol_ir(code, val, dst, size); break; |
1310 case M68K_ROR: ror_ir(code, val, dst, size); break; | 1311 case M68K_ROR: ror_ir(code, val, dst, size); break; |
1311 case M68K_ROXL: rcl_ir(code, val, dst, size); break; | 1312 case M68K_ROXL: rcl_ir(code, val, dst, size); break; |
1324 case M68K_AND: and_irdisp(code, val, dst, disp, size); break; | 1325 case M68K_AND: and_irdisp(code, val, dst, disp, size); break; |
1325 case M68K_BTST: bt_irdisp(code, val, dst, disp, size); break; | 1326 case M68K_BTST: bt_irdisp(code, val, dst, disp, size); break; |
1326 case M68K_BSET: bts_irdisp(code, val, dst, disp, size); break; | 1327 case M68K_BSET: bts_irdisp(code, val, dst, disp, size); break; |
1327 case M68K_BCLR: btr_irdisp(code, val, dst, disp, size); break; | 1328 case M68K_BCLR: btr_irdisp(code, val, dst, disp, size); break; |
1328 case M68K_BCHG: btc_irdisp(code, val, dst, disp, size); break; | 1329 case M68K_BCHG: btc_irdisp(code, val, dst, disp, size); break; |
1330 case M68K_CMP: cmp_irdisp(code, val, dst, disp, size); break; | |
1329 case M68K_EOR: xor_irdisp(code, val, dst, disp, size); break; | 1331 case M68K_EOR: xor_irdisp(code, val, dst, disp, size); break; |
1330 case M68K_OR: or_irdisp(code, val, dst, disp, size); break; | 1332 case M68K_OR: or_irdisp(code, val, dst, disp, size); break; |
1331 case M68K_ROL: rol_irdisp(code, val, dst, disp, size); break; | 1333 case M68K_ROL: rol_irdisp(code, val, dst, disp, size); break; |
1332 case M68K_ROR: ror_irdisp(code, val, dst, disp, size); break; | 1334 case M68K_ROR: ror_irdisp(code, val, dst, disp, size); break; |
1333 case M68K_ROXL: rcl_irdisp(code, val, dst, disp, size); break; | 1335 case M68K_ROXL: rcl_irdisp(code, val, dst, disp, size); break; |
1346 case M68K_AND: and_rr(code, src, dst, size); break; | 1348 case M68K_AND: and_rr(code, src, dst, size); break; |
1347 case M68K_BTST: bt_rr(code, src, dst, size); break; | 1349 case M68K_BTST: bt_rr(code, src, dst, size); break; |
1348 case M68K_BSET: bts_rr(code, src, dst, size); break; | 1350 case M68K_BSET: bts_rr(code, src, dst, size); break; |
1349 case M68K_BCLR: btr_rr(code, src, dst, size); break; | 1351 case M68K_BCLR: btr_rr(code, src, dst, size); break; |
1350 case M68K_BCHG: btc_rr(code, src, dst, size); break; | 1352 case M68K_BCHG: btc_rr(code, src, dst, size); break; |
1353 case M68K_CMP: cmp_rr(code, src, dst, size); break; | |
1351 case M68K_EOR: xor_rr(code, src, dst, size); break; | 1354 case M68K_EOR: xor_rr(code, src, dst, size); break; |
1352 case M68K_OR: or_rr(code, src, dst, size); break; | 1355 case M68K_OR: or_rr(code, src, dst, size); break; |
1353 case M68K_SUB: sub_rr(code, src, dst, size); break; | 1356 case M68K_SUB: sub_rr(code, src, dst, size); break; |
1354 case M68K_SUBX: sbb_rr(code, src, dst, size); break; | 1357 case M68K_SUBX: sbb_rr(code, src, dst, size); break; |
1355 } | 1358 } |
1364 case M68K_AND: and_rrdisp(code, src, dst, disp, size); break; | 1367 case M68K_AND: and_rrdisp(code, src, dst, disp, size); break; |
1365 case M68K_BTST: bt_rrdisp(code, src, dst, disp, size); break; | 1368 case M68K_BTST: bt_rrdisp(code, src, dst, disp, size); break; |
1366 case M68K_BSET: bts_rrdisp(code, src, dst, disp, size); break; | 1369 case M68K_BSET: bts_rrdisp(code, src, dst, disp, size); break; |
1367 case M68K_BCLR: btr_rrdisp(code, src, dst, disp, size); break; | 1370 case M68K_BCLR: btr_rrdisp(code, src, dst, disp, size); break; |
1368 case M68K_BCHG: btc_rrdisp(code, src, dst, disp, size); break; | 1371 case M68K_BCHG: btc_rrdisp(code, src, dst, disp, size); break; |
1372 case M68K_CMP: cmp_rrdisp(code, src, dst, disp, size); break; | |
1369 case M68K_EOR: xor_rrdisp(code, src, dst, disp, size); break; | 1373 case M68K_EOR: xor_rrdisp(code, src, dst, disp, size); break; |
1370 case M68K_OR: or_rrdisp(code, src, dst, disp, size); break; | 1374 case M68K_OR: or_rrdisp(code, src, dst, disp, size); break; |
1371 case M68K_SUB: sub_rrdisp(code, src, dst, disp, size); break; | 1375 case M68K_SUB: sub_rrdisp(code, src, dst, disp, size); break; |
1372 case M68K_SUBX: sbb_rrdisp(code, src, dst, disp, size); break; | 1376 case M68K_SUBX: sbb_rrdisp(code, src, dst, disp, size); break; |
1373 } | 1377 } |
1378 switch (inst->op) | 1382 switch (inst->op) |
1379 { | 1383 { |
1380 case M68K_ADD: add_rdispr(code, src, disp, dst, size); break; | 1384 case M68K_ADD: add_rdispr(code, src, disp, dst, size); break; |
1381 case M68K_ADDX: adc_rdispr(code, src, disp, dst, size); break; | 1385 case M68K_ADDX: adc_rdispr(code, src, disp, dst, size); break; |
1382 case M68K_AND: and_rdispr(code, src, disp, dst, size); break; | 1386 case M68K_AND: and_rdispr(code, src, disp, dst, size); break; |
1387 case M68K_CMP: cmp_rdispr(code, src, disp, dst, size); break; | |
1383 case M68K_EOR: xor_rdispr(code, src, disp, dst, size); break; | 1388 case M68K_EOR: xor_rdispr(code, src, disp, dst, size); break; |
1384 case M68K_OR: or_rdispr(code, src, disp, dst, size); break; | 1389 case M68K_OR: or_rdispr(code, src, disp, dst, size); break; |
1385 case M68K_SUB: sub_rdispr(code, src, disp, dst, size); break; | 1390 case M68K_SUB: sub_rdispr(code, src, disp, dst, size); break; |
1386 case M68K_SUBX: sbb_rdispr(code, src, disp, dst, size); break; | 1391 case M68K_SUBX: sbb_rdispr(code, src, disp, dst, size); break; |
1387 } | 1392 } |
1388 } | 1393 } |
1389 | 1394 |
1390 void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, x86_ea *src_op, x86_ea *dst_op) | 1395 void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op) |
1391 { | 1396 { |
1392 code_info *code = &opts->gen.code; | 1397 code_info *code = &opts->gen.code; |
1393 cycles(&opts->gen, BUS); | 1398 cycles(&opts->gen, BUS); |
1394 if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) { | 1399 if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) { |
1395 flag_to_carry(opts, FLAG_X); | 1400 flag_to_carry(opts, FLAG_X); |
1427 | 1432 |
1428 void translate_m68k_cmp(m68k_options * opts, m68kinst * inst) | 1433 void translate_m68k_cmp(m68k_options * opts, m68kinst * inst) |
1429 { | 1434 { |
1430 code_info *code = &opts->gen.code; | 1435 code_info *code = &opts->gen.code; |
1431 uint8_t size = inst->extra.size; | 1436 uint8_t size = inst->extra.size; |
1432 x86_ea src_op, dst_op; | 1437 host_ea src_op, dst_op; |
1433 translate_m68k_op(inst, &src_op, opts, 0); | 1438 translate_m68k_op(inst, &src_op, opts, 0); |
1434 if (inst->dst.addr_mode == MODE_AREG_POSTINC) { | 1439 if (inst->dst.addr_mode == MODE_AREG_POSTINC) { |
1435 push_r(code, opts->gen.scratch1); | 1440 push_r(code, opts->gen.scratch1); |
1436 translate_m68k_op(inst, &dst_op, opts, 1); | 1441 translate_m68k_op(inst, &dst_op, opts, 1); |
1437 pop_r(code, opts->gen.scratch2); | 1442 pop_r(code, opts->gen.scratch2); |
1473 case M68K_SWAP: rol_irdisp(code, 16, dst, disp, SZ_D); cmp_irdisp(code, 0, dst, disp, SZ_D); break; | 1478 case M68K_SWAP: rol_irdisp(code, 16, dst, disp, SZ_D); cmp_irdisp(code, 0, dst, disp, SZ_D); break; |
1474 case M68K_TST: cmp_irdisp(code, 0, dst, disp, size); break; | 1479 case M68K_TST: cmp_irdisp(code, 0, dst, disp, size); break; |
1475 } | 1480 } |
1476 } | 1481 } |
1477 | 1482 |
1478 void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, x86_ea *dst_op) | 1483 void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, host_ea *dst_op) |
1479 { | 1484 { |
1480 code_info *code = &opts->gen.code; | 1485 code_info *code = &opts->gen.code; |
1481 cycles(&opts->gen, BUS); | 1486 cycles(&opts->gen, BUS); |
1482 if (dst_op->mode == MODE_REG_DIRECT) { | 1487 if (dst_op->mode == MODE_REG_DIRECT) { |
1483 op_r(code, inst, dst_op->base, inst->extra.size); | 1488 op_r(code, inst, dst_op->base, inst->extra.size); |
1486 } | 1491 } |
1487 update_flags(opts, flag_mask); | 1492 update_flags(opts, flag_mask); |
1488 m68k_save_result(inst, opts); | 1493 m68k_save_result(inst, opts); |
1489 } | 1494 } |
1490 | 1495 |
1491 #define BIT_SUPERVISOR 5 | 1496 void translate_m68k_invalid(m68k_options *opts, m68kinst *inst) |
1492 | 1497 { |
1493 void translate_m68k(m68k_options * opts, m68kinst * inst) | 1498 code_info *code = &opts->gen.code; |
1494 { | 1499 if (inst->src.params.immed == 0x7100) { |
1495 code_ptr end_off, zero_off, norm_off; | 1500 retn(code); |
1501 return; | |
1502 } | |
1503 mov_ir(code, inst->address, opts->gen.scratch1, SZ_D); | |
1504 call(code, (code_ptr)m68k_invalid); | |
1505 } | |
1506 | |
1507 void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | |
1508 { | |
1509 code_info *code = &opts->gen.code; | |
1510 if (src_op->base != opts->gen.scratch2) { | |
1511 if (src_op->mode == MODE_REG_DIRECT) { | |
1512 mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B); | |
1513 } else { | |
1514 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B); | |
1515 } | |
1516 } | |
1517 if (dst_op->base != opts->gen.scratch1) { | |
1518 if (dst_op->mode == MODE_REG_DIRECT) { | |
1519 mov_rr(code, dst_op->base, opts->gen.scratch1, SZ_B); | |
1520 } else { | |
1521 mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, SZ_B); | |
1522 } | |
1523 } | |
1524 flag_to_carry(opts, FLAG_X); | |
1525 jcc(code, CC_NC, code->cur + 5); | |
1526 if (inst->op == M68K_ABCD) { | |
1527 add_ir(code, 1, opts->gen.scratch1, SZ_B); | |
1528 } else { | |
1529 sub_ir(code, 1, opts->gen.scratch1, SZ_B); | |
1530 } | |
1531 call(code, (code_ptr) (inst->op == M68K_ABCD ? bcd_add : bcd_sub)); | |
1532 reg_to_flag(opts, CH, FLAG_C); | |
1533 reg_to_flag(opts, CH, FLAG_X); | |
1534 cmp_ir(code, 0, opts->gen.scratch1, SZ_B); | |
1535 jcc(code, CC_Z, code->cur + 4); | |
1536 set_flag(opts, 0, FLAG_Z); | |
1537 if (dst_op->base != opts->gen.scratch1) { | |
1538 if (dst_op->mode == MODE_REG_DIRECT) { | |
1539 mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_B); | |
1540 } else { | |
1541 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_B); | |
1542 } | |
1543 } | |
1544 m68k_save_result(inst, opts); | |
1545 } | |
1546 | |
1547 void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | |
1548 { | |
1549 translate_shift(opts, inst, src_op, dst_op, shl_ir, shl_irdisp, shl_clr, shl_clrdisp, shr_ir, shr_irdisp); | |
1550 } | |
1551 | |
1552 void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | |
1553 { | |
1554 translate_shift(opts, inst, src_op, dst_op, sar_ir, sar_irdisp, sar_clr, sar_clrdisp, NULL, NULL); | |
1555 } | |
1556 | |
1557 void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | |
1558 { | |
1559 translate_shift(opts, inst, src_op, dst_op, shr_ir, shr_irdisp, shr_clr, shr_clrdisp, shl_ir, shl_irdisp); | |
1560 } | |
1561 | |
1562 void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | |
1563 { | |
1564 code_info *code = &opts->gen.code; | |
1565 cycles(&opts->gen, inst->extra.size == OPSIZE_BYTE ? 4 : ( | |
1566 inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8)) | |
1567 ); | |
1568 if (src_op->mode == MODE_IMMED) { | |
1569 if (inst->extra.size == OPSIZE_BYTE) { | |
1570 src_op->disp &= 0x7; | |
1571 } | |
1572 if (dst_op->mode == MODE_REG_DIRECT) { | |
1573 op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size); | |
1574 } else { | |
1575 op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); | |
1576 } | |
1577 } else { | |
1578 if (src_op->mode == MODE_REG_DISPLACE8 || (inst->dst.addr_mode != MODE_REG && src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2)) { | |
1579 if (dst_op->base == opts->gen.scratch1) { | |
1580 push_r(code, opts->gen.scratch2); | |
1581 if (src_op->mode == MODE_REG_DIRECT) { | |
1582 mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B); | |
1583 } else { | |
1584 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B); | |
1585 } | |
1586 src_op->base = opts->gen.scratch2; | |
1587 } else { | |
1588 if (src_op->mode == MODE_REG_DIRECT) { | |
1589 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B); | |
1590 } else { | |
1591 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B); | |
1592 } | |
1593 src_op->base = opts->gen.scratch1; | |
1594 } | |
1595 } | |
1596 uint8_t size = inst->extra.size; | |
1597 if (dst_op->mode == MODE_REG_DISPLACE8) { | |
1598 if (src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2) { | |
1599 if (src_op->mode == MODE_REG_DIRECT) { | |
1600 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_D); | |
1601 } else { | |
1602 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D); | |
1603 src_op->mode = MODE_REG_DIRECT; | |
1604 } | |
1605 src_op->base = opts->gen.scratch1; | |
1606 } | |
1607 //b### with register destination is modulo 32 | |
1608 //x86 with a memory destination isn't modulo anything | |
1609 //so use an and here to force the value to be modulo 32 | |
1610 and_ir(code, 31, opts->gen.scratch1, SZ_D); | |
1611 } else if(inst->dst.addr_mode != MODE_REG) { | |
1612 //b### with memory destination is modulo 8 | |
1613 //x86-64 doesn't support 8-bit bit operations | |
1614 //so we fake it by forcing the bit number to be modulo 8 | |
1615 and_ir(code, 7, src_op->base, SZ_D); | |
1616 size = SZ_D; | |
1617 } | |
1618 if (dst_op->mode == MODE_REG_DIRECT) { | |
1619 op_rr(code, inst, src_op->base, dst_op->base, size); | |
1620 } else { | |
1621 op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size); | |
1622 } | |
1623 if (src_op->base == opts->gen.scratch2) { | |
1624 pop_r(code, opts->gen.scratch2); | |
1625 } | |
1626 } | |
1627 //x86 sets the carry flag to the value of the bit tested | |
1628 //68K sets the zero flag to the complement of the bit tested | |
1629 set_flag_cond(opts, CC_NC, FLAG_Z); | |
1630 if (inst->op != M68K_BTST) { | |
1631 m68k_save_result(inst, opts); | |
1632 } | |
1633 } | |
1634 | |
1635 void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | |
1636 { | |
1637 code_info *code = &opts->gen.code; | |
1638 cycles(&opts->gen, 6); | |
1639 if (dst_op->mode == MODE_REG_DIRECT) { | |
1640 cmp_ir(code, 0, dst_op->base, inst->extra.size); | |
1641 } else { | |
1642 cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); | |
1643 } | |
1644 uint32_t isize; | |
1645 switch(inst->src.addr_mode) | |
1646 { | |
1647 case MODE_AREG_DISPLACE: | |
1648 case MODE_AREG_INDEX_DISP8: | |
1649 case MODE_ABSOLUTE_SHORT: | |
1650 case MODE_PC_INDEX_DISP8: | |
1651 case MODE_PC_DISPLACE: | |
1652 case MODE_IMMEDIATE: | |
1653 isize = 4; | |
1654 break; | |
1655 case MODE_ABSOLUTE: | |
1656 isize = 6; | |
1657 break; | |
1658 default: | |
1659 isize = 2; | |
1660 } | |
1661 //make sure we won't start a new chunk in the middle of these branches | |
1662 check_alloc_code(code, MAX_INST_LEN * 11); | |
1663 code_ptr passed = code->cur + 1; | |
1664 jcc(code, CC_GE, code->cur + 2); | |
1665 set_flag(opts, 1, FLAG_N); | |
1666 mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); | |
1667 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); | |
1668 jmp(code, opts->trap); | |
1669 *passed = code->cur - (passed+1); | |
1670 if (dst_op->mode == MODE_REG_DIRECT) { | |
1671 if (src_op->mode == MODE_REG_DIRECT) { | |
1672 cmp_rr(code, src_op->base, dst_op->base, inst->extra.size); | |
1673 } else if(src_op->mode == MODE_REG_DISPLACE8) { | |
1674 cmp_rdispr(code, src_op->base, src_op->disp, dst_op->base, inst->extra.size); | |
1675 } else { | |
1676 cmp_ir(code, src_op->disp, dst_op->base, inst->extra.size); | |
1677 } | |
1678 } else if(dst_op->mode == MODE_REG_DISPLACE8) { | |
1679 if (src_op->mode == MODE_REG_DIRECT) { | |
1680 cmp_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, inst->extra.size); | |
1681 } else { | |
1682 cmp_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); | |
1683 } | |
1684 } | |
1685 passed = code->cur + 1; | |
1686 jcc(code, CC_LE, code->cur + 2); | |
1687 set_flag(opts, 0, FLAG_N); | |
1688 mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); | |
1689 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); | |
1690 jmp(code, opts->trap); | |
1691 *passed = code->cur - (passed+1); | |
1692 cycles(&opts->gen, 4); | |
1693 } | |
1694 | |
1695 void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | |
1696 { | |
1697 code_info *code = &opts->gen.code; | |
1698 check_alloc_code(code, MAX_NATIVE_SIZE); | |
1699 //TODO: cycle exact division | |
1700 cycles(&opts->gen, inst->op == M68K_DIVS ? 158 : 140); | |
1701 set_flag(opts, 0, FLAG_C); | |
1702 push_r(code, RDX); | |
1703 push_r(code, RAX); | |
1704 if (dst_op->mode == MODE_REG_DIRECT) { | |
1705 mov_rr(code, dst_op->base, RAX, SZ_D); | |
1706 } else { | |
1707 mov_rdispr(code, dst_op->base, dst_op->disp, RAX, SZ_D); | |
1708 } | |
1709 if (src_op->mode == MODE_IMMED) { | |
1710 mov_ir(code, (src_op->disp & 0x8000) && inst->op == M68K_DIVS ? src_op->disp | 0xFFFF0000 : src_op->disp, opts->gen.scratch2, SZ_D); | |
1711 } else if (src_op->mode == MODE_REG_DIRECT) { | |
1712 if (inst->op == M68K_DIVS) { | |
1713 movsx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D); | |
1714 } else { | |
1715 movzx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D); | |
1716 } | |
1717 } else if (src_op->mode == MODE_REG_DISPLACE8) { | |
1718 if (inst->op == M68K_DIVS) { | |
1719 movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D); | |
1720 } else { | |
1721 movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D); | |
1722 } | |
1723 } | |
1724 cmp_ir(code, 0, opts->gen.scratch2, SZ_D); | |
1725 check_alloc_code(code, 6*MAX_INST_LEN); | |
1726 code_ptr not_zero = code->cur + 1; | |
1727 jcc(code, CC_NZ, code->cur + 2); | |
1728 pop_r(code, RAX); | |
1729 pop_r(code, RDX); | |
1730 mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D); | |
1731 mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D); | |
1732 jmp(code, opts->trap); | |
1733 *not_zero = code->cur - (not_zero+1); | |
1734 if (inst->op == M68K_DIVS) { | |
1735 cdq(code); | |
1736 } else { | |
1737 xor_rr(code, RDX, RDX, SZ_D); | |
1738 } | |
1739 if (inst->op == M68K_DIVS) { | |
1740 idiv_r(code, opts->gen.scratch2, SZ_D); | |
1741 } else { | |
1742 div_r(code, opts->gen.scratch2, SZ_D); | |
1743 } | |
1744 code_ptr skip_sec_check, norm_off; | |
1745 if (inst->op == M68K_DIVS) { | |
1746 cmp_ir(code, 0x8000, RAX, SZ_D); | |
1747 skip_sec_check = code->cur + 1; | |
1748 jcc(code, CC_GE, code->cur + 2); | |
1749 cmp_ir(code, -0x8000, RAX, SZ_D); | |
1750 norm_off = code->cur + 1; | |
1751 jcc(code, CC_L, code->cur + 2); | |
1752 } else { | |
1753 cmp_ir(code, 0x10000, RAX, SZ_D); | |
1754 norm_off = code->cur + 1; | |
1755 jcc(code, CC_NC, code->cur + 2); | |
1756 } | |
1757 if (dst_op->mode == MODE_REG_DIRECT) { | |
1758 mov_rr(code, RDX, dst_op->base, SZ_W); | |
1759 shl_ir(code, 16, dst_op->base, SZ_D); | |
1760 mov_rr(code, RAX, dst_op->base, SZ_W); | |
1761 } else { | |
1762 mov_rrdisp(code, RDX, dst_op->base, dst_op->disp, SZ_W); | |
1763 shl_irdisp(code, 16, dst_op->base, dst_op->disp, SZ_D); | |
1764 mov_rrdisp(code, RAX, dst_op->base, dst_op->disp, SZ_W); | |
1765 } | |
1766 cmp_ir(code, 0, RAX, SZ_W); | |
1767 pop_r(code, RAX); | |
1768 pop_r(code, RDX); | |
1769 set_flag(opts, 0, FLAG_V); | |
1770 set_flag_cond(opts, CC_Z, FLAG_Z); | |
1771 set_flag_cond(opts, CC_S, FLAG_N); | |
1772 code_ptr end_off = code->cur + 1; | |
1773 jmp(code, code->cur + 2); | |
1774 *norm_off = code->cur - (norm_off + 1); | |
1775 if (inst->op == M68K_DIVS) { | |
1776 *skip_sec_check = code->cur - (skip_sec_check+1); | |
1777 } | |
1778 pop_r(code, RAX); | |
1779 pop_r(code, RDX); | |
1780 set_flag(opts, 1, FLAG_V); | |
1781 *end_off = code->cur - (end_off + 1); | |
1782 } | |
1783 | |
1784 void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | |
1785 { | |
1786 code_info *code = &opts->gen.code; | |
1787 cycles(&opts->gen, 6); | |
1788 if (dst_op->mode == MODE_REG_DIRECT) { | |
1789 mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_D); | |
1790 if (src_op->mode == MODE_REG_DIRECT) { | |
1791 mov_rr(code, src_op->base, dst_op->base, SZ_D); | |
1792 mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D); | |
1793 } else { | |
1794 mov_rdispr(code, src_op->base, src_op->disp, dst_op->base, SZ_D); | |
1795 mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D); | |
1796 } | |
1797 } else { | |
1798 mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_D); | |
1799 if (src_op->mode == MODE_REG_DIRECT) { | |
1800 mov_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, SZ_D); | |
1801 mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D); | |
1802 } else { | |
1803 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D); | |
1804 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_D); | |
1805 mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D); | |
1806 } | |
1807 } | |
1808 } | |
1809 | |
1810 void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | |
1811 { | |
1812 code_info *code = &opts->gen.code; | |
1813 cycles(&opts->gen, 70); //TODO: Calculate the actual value based on the value of the <ea> parameter | |
1814 if (src_op->mode == MODE_IMMED) { | |
1815 mov_ir(code, inst->op == M68K_MULU ? (src_op->disp & 0xFFFF) : ((src_op->disp & 0x8000) ? src_op->disp | 0xFFFF0000 : src_op->disp), opts->gen.scratch1, SZ_D); | |
1816 } else if (src_op->mode == MODE_REG_DIRECT) { | |
1817 if (inst->op == M68K_MULS) { | |
1818 movsx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); | |
1819 } else { | |
1820 movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); | |
1821 } | |
1822 } else { | |
1823 if (inst->op == M68K_MULS) { | |
1824 movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); | |
1825 } else { | |
1826 movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); | |
1827 } | |
1828 } | |
1496 uint8_t dst_reg; | 1829 uint8_t dst_reg; |
1497 code_info *code = &opts->gen.code; | 1830 if (dst_op->mode == MODE_REG_DIRECT) { |
1498 check_cycles_int(&opts->gen, inst->address); | 1831 dst_reg = dst_op->base; |
1499 if (inst->op == M68K_MOVE) { | 1832 if (inst->op == M68K_MULS) { |
1500 return translate_m68k_move(opts, inst); | 1833 movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); |
1501 } else if(inst->op == M68K_LEA || inst->op == M68K_PEA) { | 1834 } else { |
1502 return translate_m68k_lea_pea(opts, inst); | 1835 movzx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); |
1503 } else if(inst->op == M68K_BSR) { | 1836 } |
1504 return translate_m68k_bsr(opts, inst); | 1837 } else { |
1505 } else if(inst->op == M68K_BCC) { | 1838 dst_reg = opts->gen.scratch2; |
1506 return translate_m68k_bcc(opts, inst); | 1839 if (inst->op == M68K_MULS) { |
1507 } else if(inst->op == M68K_JMP) { | 1840 movsx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D); |
1508 return translate_m68k_jmp_jsr(opts, inst); | 1841 } else { |
1509 } else if(inst->op == M68K_JSR) { | 1842 movzx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D); |
1510 return translate_m68k_jmp_jsr(opts, inst); | 1843 } |
1511 } else if(inst->op == M68K_RTS) { | 1844 } |
1512 return translate_m68k_rts(opts, inst); | 1845 imul_rr(code, opts->gen.scratch1, dst_reg, SZ_D); |
1513 } else if(inst->op == M68K_DBCC) { | 1846 if (dst_op->mode == MODE_REG_DISPLACE8) { |
1514 return translate_m68k_dbcc(opts, inst); | 1847 mov_rrdisp(code, dst_reg, dst_op->base, dst_op->disp, SZ_D); |
1515 } else if(inst->op == M68K_CLR) { | 1848 } |
1516 return translate_m68k_clr(opts, inst); | 1849 cmp_ir(code, 0, dst_reg, SZ_D); |
1517 } else if(inst->op == M68K_MOVEM) { | 1850 update_flags(opts, N|Z|V0|C0); |
1518 return translate_m68k_movem(opts, inst); | 1851 } |
1519 } else if(inst->op == M68K_LINK) { | 1852 |
1520 return translate_m68k_link(opts, inst); | 1853 void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) |
1521 } else if(inst->op == M68K_UNLK) { | 1854 { |
1522 return translate_m68k_unlk(opts, inst); | 1855 code_info *code = &opts->gen.code; |
1523 } else if(inst->op == M68K_EXT) { | 1856 cycles(&opts->gen, BUS); |
1524 return translate_m68k_ext(opts, inst); | 1857 if (dst_op->mode == MODE_REG_DIRECT) { |
1525 } else if(inst->op == M68K_SCC) { | 1858 if (dst_op->base == opts->gen.scratch1) { |
1526 return translate_m68k_scc(opts, inst); | 1859 push_r(code, opts->gen.scratch2); |
1527 } else if(inst->op == M68K_MOVEP) { | 1860 xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, inst->extra.size); |
1528 return translate_m68k_movep(opts, inst); | 1861 flag_to_carry(opts, FLAG_X); |
1529 } else if(inst->op == M68K_INVALID) { | 1862 sbb_rr(code, dst_op->base, opts->gen.scratch2, inst->extra.size); |
1530 if (inst->src.params.immed == 0x7100) { | 1863 mov_rr(code, opts->gen.scratch2, dst_op->base, inst->extra.size); |
1531 return retn(code); | 1864 pop_r(code, opts->gen.scratch2); |
1532 } | |
1533 mov_ir(code, inst->address, opts->gen.scratch1, SZ_D); | |
1534 return call(code, (code_ptr)m68k_invalid); | |
1535 } else if(inst->op == M68K_CMP) { | |
1536 return translate_m68k_cmp(opts, inst); | |
1537 } | |
1538 x86_ea src_op, dst_op; | |
1539 if (inst->src.addr_mode != MODE_UNUSED) { | |
1540 translate_m68k_op(inst, &src_op, opts, 0); | |
1541 } | |
1542 if (inst->dst.addr_mode != MODE_UNUSED) { | |
1543 translate_m68k_op(inst, &dst_op, opts, 1); | |
1544 } | |
1545 uint8_t size; | |
1546 switch(inst->op) | |
1547 { | |
1548 case M68K_ABCD: | |
1549 case M68K_SBCD: | |
1550 if (src_op.base != opts->gen.scratch2) { | |
1551 if (src_op.mode == MODE_REG_DIRECT) { | |
1552 mov_rr(code, src_op.base, opts->gen.scratch2, SZ_B); | |
1553 } else { | |
1554 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, SZ_B); | |
1555 } | |
1556 } | |
1557 if (dst_op.base != opts->gen.scratch1) { | |
1558 if (dst_op.mode == MODE_REG_DIRECT) { | |
1559 mov_rr(code, dst_op.base, opts->gen.scratch1, SZ_B); | |
1560 } else { | |
1561 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B); | |
1562 } | |
1563 } | |
1564 flag_to_carry(opts, FLAG_X); | |
1565 jcc(code, CC_NC, code->cur + 5); | |
1566 if (inst->op == M68K_ABCD) { | |
1567 add_ir(code, 1, opts->gen.scratch1, SZ_B); | |
1568 } else { | |
1569 sub_ir(code, 1, opts->gen.scratch1, SZ_B); | |
1570 } | |
1571 call(code, (code_ptr) (inst->op == M68K_ABCD ? bcd_add : bcd_sub)); | |
1572 reg_to_flag(opts, CH, FLAG_C); | |
1573 reg_to_flag(opts, CH, FLAG_X); | |
1574 cmp_ir(code, 0, opts->gen.scratch1, SZ_B); | |
1575 jcc(code, CC_Z, code->cur + 4); | |
1576 set_flag(opts, 0, FLAG_Z); | |
1577 if (dst_op.base != opts->gen.scratch1) { | |
1578 if (dst_op.mode == MODE_REG_DIRECT) { | |
1579 mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B); | |
1580 } else { | |
1581 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B); | |
1582 } | |
1583 } | |
1584 m68k_save_result(inst, opts); | |
1585 break; | |
1586 case M68K_ADD: | |
1587 case M68K_SUB: | |
1588 translate_m68k_arith(opts, inst, X|N|Z|V|C, &src_op, &dst_op); | |
1589 break; | |
1590 case M68K_ADDX: | |
1591 case M68K_SUBX: | |
1592 //z flag is special cased in translate_m68k_arith | |
1593 translate_m68k_arith(opts, inst, X|N|V|C, &src_op, &dst_op); | |
1594 break; | |
1595 case M68K_AND: | |
1596 case M68K_EOR: | |
1597 case M68K_OR: | |
1598 translate_m68k_arith(opts, inst, N|Z|V0|C0, &src_op, &dst_op); | |
1599 break; | |
1600 case M68K_ANDI_CCR: | |
1601 case M68K_ANDI_SR: { | |
1602 cycles(&opts->gen, 20); | |
1603 //TODO: If ANDI to SR, trap if not in supervisor mode | |
1604 uint32_t flag_mask = 0; | |
1605 if (!(inst->src.params.immed & 0x1)) { | |
1606 flag_mask |= C0; | |
1607 } | |
1608 if (!(inst->src.params.immed & 0x2)) { | |
1609 flag_mask |= V0; | |
1610 } | |
1611 if (!(inst->src.params.immed & 0x4)) { | |
1612 flag_mask |= Z0; | |
1613 } | |
1614 if (!(inst->src.params.immed & 0x8)) { | |
1615 flag_mask |= N0; | |
1616 } | |
1617 if (!(inst->src.params.immed & 0x10)) { | |
1618 flag_mask |= X0; | |
1619 } | |
1620 update_flags(opts, flag_mask); | |
1621 if (inst->op == M68K_ANDI_SR) { | |
1622 and_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | |
1623 if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { | |
1624 //leave supervisor mode | |
1625 swap_ssp_usp(opts); | |
1626 } | |
1627 if (inst->src.params.immed & 0x700) { | |
1628 call(code, opts->do_sync); | |
1629 } | |
1630 } | |
1631 break; | |
1632 } | |
1633 case M68K_ASL: | |
1634 case M68K_LSL: | |
1635 translate_shift(opts, inst, &src_op, &dst_op, shl_ir, shl_irdisp, shl_clr, shl_clrdisp, shr_ir, shr_irdisp); | |
1636 break; | |
1637 case M68K_ASR: | |
1638 translate_shift(opts, inst, &src_op, &dst_op, sar_ir, sar_irdisp, sar_clr, sar_clrdisp, NULL, NULL); | |
1639 break; | |
1640 case M68K_LSR: | |
1641 translate_shift(opts, inst, &src_op, &dst_op, shr_ir, shr_irdisp, shr_clr, shr_clrdisp, shl_ir, shl_irdisp); | |
1642 break; | |
1643 case M68K_BCHG: | |
1644 case M68K_BCLR: | |
1645 case M68K_BSET: | |
1646 case M68K_BTST: | |
1647 cycles(&opts->gen, inst->extra.size == OPSIZE_BYTE ? 4 : ( | |
1648 inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8)) | |
1649 ); | |
1650 if (src_op.mode == MODE_IMMED) { | |
1651 if (inst->extra.size == OPSIZE_BYTE) { | |
1652 src_op.disp &= 0x7; | |
1653 } | |
1654 if (dst_op.mode == MODE_REG_DIRECT) { | |
1655 op_ir(code, inst, src_op.disp, dst_op.base, inst->extra.size); | |
1656 } else { | |
1657 op_irdisp(code, inst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); | |
1658 } | |
1659 } else { | |
1660 if (src_op.mode == MODE_REG_DISPLACE8 || (inst->dst.addr_mode != MODE_REG && src_op.base != opts->gen.scratch1 && src_op.base != opts->gen.scratch2)) { | |
1661 if (dst_op.base == opts->gen.scratch1) { | |
1662 push_r(code, opts->gen.scratch2); | |
1663 if (src_op.mode == MODE_REG_DIRECT) { | |
1664 mov_rr(code, src_op.base, opts->gen.scratch2, SZ_B); | |
1665 } else { | |
1666 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, SZ_B); | |
1667 } | |
1668 src_op.base = opts->gen.scratch2; | |
1669 } else { | |
1670 if (src_op.mode == MODE_REG_DIRECT) { | |
1671 mov_rr(code, src_op.base, opts->gen.scratch1, SZ_B); | |
1672 } else { | |
1673 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B); | |
1674 } | |
1675 src_op.base = opts->gen.scratch1; | |
1676 } | |
1677 } | |
1678 uint8_t size = inst->extra.size; | |
1679 if (dst_op.mode == MODE_REG_DISPLACE8) { | |
1680 if (src_op.base != opts->gen.scratch1 && src_op.base != opts->gen.scratch2) { | |
1681 if (src_op.mode == MODE_REG_DIRECT) { | |
1682 mov_rr(code, src_op.base, opts->gen.scratch1, SZ_D); | |
1683 } else { | |
1684 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_D); | |
1685 src_op.mode = MODE_REG_DIRECT; | |
1686 } | |
1687 src_op.base = opts->gen.scratch1; | |
1688 } | |
1689 //b### with register destination is modulo 32 | |
1690 //x86 with a memory destination isn't modulo anything | |
1691 //so use an and here to force the value to be modulo 32 | |
1692 and_ir(code, 31, opts->gen.scratch1, SZ_D); | |
1693 } else if(inst->dst.addr_mode != MODE_REG) { | |
1694 //b### with memory destination is modulo 8 | |
1695 //x86-64 doesn't support 8-bit bit operations | |
1696 //so we fake it by forcing the bit number to be modulo 8 | |
1697 and_ir(code, 7, src_op.base, SZ_D); | |
1698 size = SZ_D; | |
1699 } | |
1700 if (dst_op.mode == MODE_REG_DIRECT) { | |
1701 op_rr(code, inst, src_op.base, dst_op.base, size); | |
1702 } else { | |
1703 op_rrdisp(code, inst, src_op.base, dst_op.base, dst_op.disp, size); | |
1704 } | |
1705 if (src_op.base == opts->gen.scratch2) { | |
1706 pop_r(code, opts->gen.scratch2); | |
1707 } | |
1708 } | |
1709 //x86 sets the carry flag to the value of the bit tested | |
1710 //68K sets the zero flag to the complement of the bit tested | |
1711 set_flag_cond(opts, CC_NC, FLAG_Z); | |
1712 if (inst->op != M68K_BTST) { | |
1713 m68k_save_result(inst, opts); | |
1714 } | |
1715 break; | |
1716 case M68K_CHK: | |
1717 { | |
1718 cycles(&opts->gen, 6); | |
1719 if (dst_op.mode == MODE_REG_DIRECT) { | |
1720 cmp_ir(code, 0, dst_op.base, inst->extra.size); | |
1721 } else { | |
1722 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size); | |
1723 } | |
1724 uint32_t isize; | |
1725 switch(inst->src.addr_mode) | |
1726 { | |
1727 case MODE_AREG_DISPLACE: | |
1728 case MODE_AREG_INDEX_DISP8: | |
1729 case MODE_ABSOLUTE_SHORT: | |
1730 case MODE_PC_INDEX_DISP8: | |
1731 case MODE_PC_DISPLACE: | |
1732 case MODE_IMMEDIATE: | |
1733 isize = 4; | |
1734 break; | |
1735 case MODE_ABSOLUTE: | |
1736 isize = 6; | |
1737 break; | |
1738 default: | |
1739 isize = 2; | |
1740 } | |
1741 //make sure we won't start a new chunk in the middle of these branches | |
1742 check_alloc_code(code, MAX_INST_LEN * 11); | |
1743 code_ptr passed = code->cur + 1; | |
1744 jcc(code, CC_GE, code->cur + 2); | |
1745 set_flag(opts, 1, FLAG_N); | |
1746 mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); | |
1747 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); | |
1748 jmp(code, opts->trap); | |
1749 *passed = code->cur - (passed+1); | |
1750 if (dst_op.mode == MODE_REG_DIRECT) { | |
1751 if (src_op.mode == MODE_REG_DIRECT) { | |
1752 cmp_rr(code, src_op.base, dst_op.base, inst->extra.size); | |
1753 } else if(src_op.mode == MODE_REG_DISPLACE8) { | |
1754 cmp_rdispr(code, src_op.base, src_op.disp, dst_op.base, inst->extra.size); | |
1755 } else { | |
1756 cmp_ir(code, src_op.disp, dst_op.base, inst->extra.size); | |
1757 } | |
1758 } else if(dst_op.mode == MODE_REG_DISPLACE8) { | |
1759 if (src_op.mode == MODE_REG_DIRECT) { | |
1760 cmp_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); | |
1761 } else { | |
1762 cmp_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); | |
1763 } | |
1764 } | |
1765 passed = code->cur + 1; | |
1766 jcc(code, CC_LE, code->cur + 2); | |
1767 set_flag(opts, 0, FLAG_N); | |
1768 mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); | |
1769 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); | |
1770 jmp(code, opts->trap); | |
1771 *passed = code->cur - (passed+1); | |
1772 cycles(&opts->gen, 4); | |
1773 break; | |
1774 } | |
1775 case M68K_DIVS: | |
1776 case M68K_DIVU: | |
1777 { | |
1778 check_alloc_code(code, MAX_NATIVE_SIZE); | |
1779 //TODO: cycle exact division | |
1780 cycles(&opts->gen, inst->op == M68K_DIVS ? 158 : 140); | |
1781 set_flag(opts, 0, FLAG_C); | |
1782 push_r(code, RDX); | |
1783 push_r(code, RAX); | |
1784 if (dst_op.mode == MODE_REG_DIRECT) { | |
1785 mov_rr(code, dst_op.base, RAX, SZ_D); | |
1786 } else { | |
1787 mov_rdispr(code, dst_op.base, dst_op.disp, RAX, SZ_D); | |
1788 } | |
1789 if (src_op.mode == MODE_IMMED) { | |
1790 mov_ir(code, (src_op.disp & 0x8000) && inst->op == M68K_DIVS ? src_op.disp | 0xFFFF0000 : src_op.disp, opts->gen.scratch2, SZ_D); | |
1791 } else if (src_op.mode == MODE_REG_DIRECT) { | |
1792 if (inst->op == M68K_DIVS) { | |
1793 movsx_rr(code, src_op.base, opts->gen.scratch2, SZ_W, SZ_D); | |
1794 } else { | |
1795 movzx_rr(code, src_op.base, opts->gen.scratch2, SZ_W, SZ_D); | |
1796 } | |
1797 } else if (src_op.mode == MODE_REG_DISPLACE8) { | |
1798 if (inst->op == M68K_DIVS) { | |
1799 movsx_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, SZ_W, SZ_D); | |
1800 } else { | |
1801 movzx_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, SZ_W, SZ_D); | |
1802 } | |
1803 } | |
1804 cmp_ir(code, 0, opts->gen.scratch2, SZ_D); | |
1805 check_alloc_code(code, 6*MAX_INST_LEN); | |
1806 code_ptr not_zero = code->cur + 1; | |
1807 jcc(code, CC_NZ, code->cur + 2); | |
1808 pop_r(code, RAX); | |
1809 pop_r(code, RDX); | |
1810 mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D); | |
1811 mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D); | |
1812 jmp(code, opts->trap); | |
1813 *not_zero = code->cur - (not_zero+1); | |
1814 if (inst->op == M68K_DIVS) { | |
1815 cdq(code); | |
1816 } else { | |
1817 xor_rr(code, RDX, RDX, SZ_D); | |
1818 } | |
1819 if (inst->op == M68K_DIVS) { | |
1820 idiv_r(code, opts->gen.scratch2, SZ_D); | |
1821 } else { | |
1822 div_r(code, opts->gen.scratch2, SZ_D); | |
1823 } | |
1824 code_ptr skip_sec_check; | |
1825 if (inst->op == M68K_DIVS) { | |
1826 cmp_ir(code, 0x8000, RAX, SZ_D); | |
1827 skip_sec_check = code->cur + 1; | |
1828 jcc(code, CC_GE, code->cur + 2); | |
1829 cmp_ir(code, -0x8000, RAX, SZ_D); | |
1830 norm_off = code->cur + 1; | |
1831 jcc(code, CC_L, code->cur + 2); | |
1832 } else { | |
1833 cmp_ir(code, 0x10000, RAX, SZ_D); | |
1834 norm_off = code->cur + 1; | |
1835 jcc(code, CC_NC, code->cur + 2); | |
1836 } | |
1837 if (dst_op.mode == MODE_REG_DIRECT) { | |
1838 mov_rr(code, RDX, dst_op.base, SZ_W); | |
1839 shl_ir(code, 16, dst_op.base, SZ_D); | |
1840 mov_rr(code, RAX, dst_op.base, SZ_W); | |
1841 } else { | |
1842 mov_rrdisp(code, RDX, dst_op.base, dst_op.disp, SZ_W); | |
1843 shl_irdisp(code, 16, dst_op.base, dst_op.disp, SZ_D); | |
1844 mov_rrdisp(code, RAX, dst_op.base, dst_op.disp, SZ_W); | |
1845 } | |
1846 cmp_ir(code, 0, RAX, SZ_W); | |
1847 pop_r(code, RAX); | |
1848 pop_r(code, RDX); | |
1849 set_flag(opts, 0, FLAG_V); | |
1850 set_flag_cond(opts, CC_Z, FLAG_Z); | |
1851 set_flag_cond(opts, CC_S, FLAG_N); | |
1852 end_off = code->cur + 1; | |
1853 jmp(code, code->cur + 2); | |
1854 *norm_off = code->cur - (norm_off + 1); | |
1855 if (inst->op == M68K_DIVS) { | |
1856 *skip_sec_check = code->cur - (skip_sec_check+1); | |
1857 } | |
1858 pop_r(code, RAX); | |
1859 pop_r(code, RDX); | |
1860 set_flag(opts, 1, FLAG_V); | |
1861 *end_off = code->cur - (end_off + 1); | |
1862 break; | |
1863 } | |
1864 case M68K_EORI_CCR: | |
1865 case M68K_EORI_SR: | |
1866 cycles(&opts->gen, 20); | |
1867 //TODO: If ANDI to SR, trap if not in supervisor mode | |
1868 if (inst->src.params.immed & 0x1) { | |
1869 xor_flag(opts, 1, FLAG_C); | |
1870 } | |
1871 if (inst->src.params.immed & 0x2) { | |
1872 xor_flag(opts, 1, FLAG_V); | |
1873 } | |
1874 if (inst->src.params.immed & 0x4) { | |
1875 xor_flag(opts, 1, FLAG_Z); | |
1876 } | |
1877 if (inst->src.params.immed & 0x8) { | |
1878 xor_flag(opts, 1, FLAG_N); | |
1879 } | |
1880 if (inst->src.params.immed & 0x10) { | |
1881 xor_flag(opts, 1, FLAG_X); | |
1882 } | |
1883 if (inst->op == M68K_ORI_SR) { | |
1884 xor_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | |
1885 if (inst->src.params.immed & 0x700) { | |
1886 call(code, opts->do_sync); | |
1887 } | |
1888 } | |
1889 break; | |
1890 case M68K_EXG: | |
1891 cycles(&opts->gen, 6); | |
1892 if (dst_op.mode == MODE_REG_DIRECT) { | |
1893 mov_rr(code, dst_op.base, opts->gen.scratch2, SZ_D); | |
1894 if (src_op.mode == MODE_REG_DIRECT) { | |
1895 mov_rr(code, src_op.base, dst_op.base, SZ_D); | |
1896 mov_rr(code, opts->gen.scratch2, src_op.base, SZ_D); | |
1897 } else { | |
1898 mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, SZ_D); | |
1899 mov_rrdisp(code, opts->gen.scratch2, src_op.base, src_op.disp, SZ_D); | |
1900 } | |
1901 } else { | |
1902 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, SZ_D); | |
1903 if (src_op.mode == MODE_REG_DIRECT) { | |
1904 mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, SZ_D); | |
1905 mov_rr(code, opts->gen.scratch2, src_op.base, SZ_D); | |
1906 } else { | |
1907 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_D); | |
1908 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_D); | |
1909 mov_rrdisp(code, opts->gen.scratch2, src_op.base, src_op.disp, SZ_D); | |
1910 } | |
1911 } | |
1912 break; | |
1913 case M68K_ILLEGAL: | |
1914 call(code, opts->gen.save_context); | |
1915 #ifdef X86_64 | |
1916 mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); | |
1917 #else | |
1918 push_r(code, opts->gen.context_reg); | |
1919 #endif | |
1920 call(code, (code_ptr)print_regs_exit); | |
1921 break; | |
1922 case M68K_MOVE_FROM_SR: | |
1923 //TODO: Trap if not in system mode | |
1924 call(code, opts->get_sr); | |
1925 if (dst_op.mode == MODE_REG_DIRECT) { | |
1926 mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_W); | |
1927 } else { | |
1928 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_W); | |
1929 } | |
1930 m68k_save_result(inst, opts); | |
1931 break; | |
1932 case M68K_MOVE_CCR: | |
1933 case M68K_MOVE_SR: | |
1934 //TODO: Privilege check for MOVE to SR | |
1935 if (src_op.mode == MODE_IMMED) { | |
1936 uint32_t flag_mask = src_op.disp & 0x10 ? X1 : X0; | |
1937 flag_mask |= src_op.disp & 0x8 ? N1 : N0; | |
1938 flag_mask |= src_op.disp & 0x4 ? Z1 : Z0; | |
1939 flag_mask |= src_op.disp & 0x2 ? V1 : V0; | |
1940 flag_mask |= src_op.disp & 0x1 ? C1 : C0; | |
1941 update_flags(opts, flag_mask); | |
1942 if (inst->op == M68K_MOVE_SR) { | |
1943 mov_irdisp(code, (src_op.disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | |
1944 if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { | |
1945 //leave supervisor mode | |
1946 mov_rr(code, opts->aregs[7], opts->gen.scratch1, SZ_D); | |
1947 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D); | |
1948 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D); | |
1949 } | |
1950 call(code, opts->do_sync); | |
1951 } | |
1952 cycles(&opts->gen, 12); | |
1953 } else { | |
1954 if (src_op.base != opts->gen.scratch1) { | |
1955 if (src_op.mode == MODE_REG_DIRECT) { | |
1956 mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W); | |
1957 } else { | |
1958 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_W); | |
1959 } | |
1960 } | |
1961 call(code, inst->op == M68K_MOVE_SR ? opts->set_sr : opts->set_ccr); | |
1962 cycles(&opts->gen, 12); | |
1963 | |
1964 } | |
1965 break; | |
1966 case M68K_MOVE_USP: | |
1967 cycles(&opts->gen, BUS); | |
1968 //TODO: Trap if not in supervisor mode | |
1969 //bt_irdisp(code, BIT_SUPERVISOR, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | |
1970 if (inst->src.addr_mode == MODE_UNUSED) { | |
1971 areg_to_native(opts, 8, dst_op.mode == MODE_REG_DIRECT ? dst_op.base : opts->gen.scratch1); | |
1972 if (dst_op.mode != MODE_REG_DIRECT) { | |
1973 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_D); | |
1974 } | |
1975 } else { | |
1976 if (src_op.mode != MODE_REG_DIRECT) { | |
1977 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_D); | |
1978 src_op.base = opts->gen.scratch1; | |
1979 } | |
1980 native_to_areg(opts, src_op.base, 8); | |
1981 } | |
1982 break; | |
1983 //case M68K_MOVEP: | |
1984 case M68K_MULS: | |
1985 case M68K_MULU: | |
1986 cycles(&opts->gen, 70); //TODO: Calculate the actual value based on the value of the <ea> parameter | |
1987 if (src_op.mode == MODE_IMMED) { | |
1988 mov_ir(code, inst->op == M68K_MULU ? (src_op.disp & 0xFFFF) : ((src_op.disp & 0x8000) ? src_op.disp | 0xFFFF0000 : src_op.disp), opts->gen.scratch1, SZ_D); | |
1989 } else if (src_op.mode == MODE_REG_DIRECT) { | |
1990 if (inst->op == M68K_MULS) { | |
1991 movsx_rr(code, src_op.base, opts->gen.scratch1, SZ_W, SZ_D); | |
1992 } else { | |
1993 movzx_rr(code, src_op.base, opts->gen.scratch1, SZ_W, SZ_D); | |
1994 } | |
1995 } else { | |
1996 if (inst->op == M68K_MULS) { | |
1997 movsx_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_W, SZ_D); | |
1998 } else { | |
1999 movzx_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_W, SZ_D); | |
2000 } | |
2001 } | |
2002 if (dst_op.mode == MODE_REG_DIRECT) { | |
2003 dst_reg = dst_op.base; | |
2004 if (inst->op == M68K_MULS) { | |
2005 movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); | |
2006 } else { | |
2007 movzx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); | |
2008 } | |
2009 } else { | |
2010 dst_reg = opts->gen.scratch2; | |
2011 if (inst->op == M68K_MULS) { | |
2012 movsx_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, SZ_W, SZ_D); | |
2013 } else { | |
2014 movzx_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, SZ_W, SZ_D); | |
2015 } | |
2016 } | |
2017 imul_rr(code, opts->gen.scratch1, dst_reg, SZ_D); | |
2018 if (dst_op.mode == MODE_REG_DISPLACE8) { | |
2019 mov_rrdisp(code, dst_reg, dst_op.base, dst_op.disp, SZ_D); | |
2020 } | |
2021 cmp_ir(code, 0, dst_reg, SZ_D); | |
2022 update_flags(opts, N|Z|V0|C0); | |
2023 break; | |
2024 //case M68K_NBCD: | |
2025 case M68K_NEG: | |
2026 translate_m68k_unary(opts, inst, X|N|Z|V|C, &dst_op); | |
2027 break; | |
2028 case M68K_NEGX: { | |
2029 cycles(&opts->gen, BUS); | |
2030 if (dst_op.mode == MODE_REG_DIRECT) { | |
2031 if (dst_op.base == opts->gen.scratch1) { | |
2032 push_r(code, opts->gen.scratch2); | |
2033 xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, inst->extra.size); | |
2034 flag_to_carry(opts, FLAG_X); | |
2035 sbb_rr(code, dst_op.base, opts->gen.scratch2, inst->extra.size); | |
2036 mov_rr(code, opts->gen.scratch2, dst_op.base, inst->extra.size); | |
2037 pop_r(code, opts->gen.scratch2); | |
2038 } else { | |
2039 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size); | |
2040 flag_to_carry(opts, FLAG_X); | |
2041 sbb_rr(code, dst_op.base, opts->gen.scratch1, inst->extra.size); | |
2042 mov_rr(code, opts->gen.scratch1, dst_op.base, inst->extra.size); | |
2043 } | |
2044 } else { | 1865 } else { |
2045 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size); | 1866 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size); |
2046 flag_to_carry(opts, FLAG_X); | 1867 flag_to_carry(opts, FLAG_X); |
2047 sbb_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, inst->extra.size); | 1868 sbb_rr(code, dst_op->base, opts->gen.scratch1, inst->extra.size); |
2048 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, inst->extra.size); | 1869 mov_rr(code, opts->gen.scratch1, dst_op->base, inst->extra.size); |
2049 } | 1870 } |
2050 set_flag_cond(opts, CC_C, FLAG_C); | 1871 } else { |
2051 code_ptr after_flag_set = code->cur + 1; | 1872 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size); |
2052 jcc(code, CC_Z, code->cur + 2); | 1873 flag_to_carry(opts, FLAG_X); |
2053 set_flag(opts, 0, FLAG_Z); | 1874 sbb_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, inst->extra.size); |
2054 *after_flag_set = code->cur - (after_flag_set+1); | 1875 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, inst->extra.size); |
2055 set_flag_cond(opts, CC_S, FLAG_N); | 1876 } |
2056 set_flag_cond(opts, CC_O, FLAG_V); | 1877 set_flag_cond(opts, CC_C, FLAG_C); |
2057 if (opts->flag_regs[FLAG_C] >= 0) { | 1878 code_ptr after_flag_set = code->cur + 1; |
2058 flag_to_flag(opts, FLAG_C, FLAG_X); | 1879 jcc(code, CC_Z, code->cur + 2); |
2059 } else { | 1880 set_flag(opts, 0, FLAG_Z); |
2060 set_flag_cond(opts, CC_C, FLAG_X); | 1881 *after_flag_set = code->cur - (after_flag_set+1); |
2061 } | 1882 set_flag_cond(opts, CC_S, FLAG_N); |
1883 set_flag_cond(opts, CC_O, FLAG_V); | |
1884 if (opts->flag_regs[FLAG_C] >= 0) { | |
1885 flag_to_flag(opts, FLAG_C, FLAG_X); | |
1886 } else { | |
1887 set_flag_cond(opts, CC_C, FLAG_X); | |
1888 } | |
1889 m68k_save_result(inst, opts); | |
1890 } | |
1891 | |
1892 void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | |
1893 { | |
1894 code_info *code = &opts->gen.code; | |
1895 int32_t init_flags = C|V0; | |
1896 if (inst->src.addr_mode == MODE_UNUSED) { | |
1897 cycles(&opts->gen, BUS); | |
1898 //Memory rotate | |
1899 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { | |
1900 flag_to_carry(opts, FLAG_X); | |
1901 init_flags |= X; | |
1902 } | |
1903 op_ir(code, inst, 1, dst_op->base, inst->extra.size); | |
1904 update_flags(opts, init_flags); | |
1905 cmp_ir(code, 0, dst_op->base, inst->extra.size); | |
1906 update_flags(opts, Z|N); | |
2062 m68k_save_result(inst, opts); | 1907 m68k_save_result(inst, opts); |
2063 break; | 1908 } else { |
2064 } | 1909 if (src_op->mode == MODE_IMMED) { |
2065 case M68K_NOP: | 1910 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op->disp*2); |
2066 cycles(&opts->gen, BUS); | |
2067 break; | |
2068 case M68K_NOT: | |
2069 translate_m68k_unary(opts, inst, N|Z|V0|C0, &dst_op); | |
2070 break; | |
2071 case M68K_ORI_CCR: | |
2072 case M68K_ORI_SR: | |
2073 cycles(&opts->gen, 20); | |
2074 //TODO: If ORI to SR, trap if not in supervisor mode | |
2075 uint32_t flag_mask = 0; | |
2076 if (inst->src.params.immed & 0x1) { | |
2077 flag_mask |= C1; | |
2078 } | |
2079 if (inst->src.params.immed & 0x2) { | |
2080 flag_mask |= V1; | |
2081 } | |
2082 if (inst->src.params.immed & 0x4) { | |
2083 flag_mask |= Z1; | |
2084 } | |
2085 if (inst->src.params.immed & 0x8) { | |
2086 flag_mask |= N1; | |
2087 } | |
2088 if (inst->src.params.immed & 0x10) { | |
2089 flag_mask |= X1; | |
2090 } | |
2091 update_flags(opts, flag_mask); | |
2092 if (inst->op == M68K_ORI_SR) { | |
2093 or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | |
2094 if (inst->src.params.immed & 0x700) { | |
2095 call(code, opts->do_sync); | |
2096 } | |
2097 } | |
2098 break; | |
2099 case M68K_RESET: | |
2100 call(code, opts->gen.save_context); | |
2101 #ifdef X86_64 | |
2102 mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); | |
2103 #else | |
2104 push_r(code, opts->gen.context_reg); | |
2105 #endif | |
2106 call(code, (code_ptr)print_regs_exit); | |
2107 break; | |
2108 case M68K_ROL: | |
2109 case M68K_ROR: | |
2110 case M68K_ROXL: | |
2111 case M68K_ROXR: { | |
2112 int32_t init_flags = C|V0; | |
2113 if (inst->src.addr_mode == MODE_UNUSED) { | |
2114 cycles(&opts->gen, BUS); | |
2115 //Memory rotate | |
2116 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { | 1911 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { |
2117 flag_to_carry(opts, FLAG_X); | 1912 flag_to_carry(opts, FLAG_X); |
2118 init_flags |= X; | 1913 init_flags |= X; |
2119 } | 1914 } |
2120 op_ir(code, inst, 1, dst_op.base, inst->extra.size); | 1915 if (dst_op->mode == MODE_REG_DIRECT) { |
1916 op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size); | |
1917 } else { | |
1918 op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); | |
1919 } | |
2121 update_flags(opts, init_flags); | 1920 update_flags(opts, init_flags); |
2122 cmp_ir(code, 0, dst_op.base, inst->extra.size); | 1921 } else { |
2123 update_flags(opts, Z|N); | 1922 if (src_op->mode == MODE_REG_DIRECT) { |
2124 m68k_save_result(inst, opts); | 1923 if (src_op->base != opts->gen.scratch1) { |
2125 } else { | 1924 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B); |
2126 if (src_op.mode == MODE_IMMED) { | |
2127 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op.disp*2); | |
2128 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { | |
2129 flag_to_carry(opts, FLAG_X); | |
2130 init_flags |= X; | |
2131 } | 1925 } |
2132 if (dst_op.mode == MODE_REG_DIRECT) { | |
2133 op_ir(code, inst, src_op.disp, dst_op.base, inst->extra.size); | |
2134 } else { | |
2135 op_irdisp(code, inst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); | |
2136 } | |
2137 update_flags(opts, init_flags); | |
2138 } else { | 1926 } else { |
2139 if (src_op.mode == MODE_REG_DIRECT) { | 1927 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B); |
2140 if (src_op.base != opts->gen.scratch1) { | 1928 } |
2141 mov_rr(code, src_op.base, opts->gen.scratch1, SZ_B); | 1929 and_ir(code, 63, opts->gen.scratch1, SZ_D); |
2142 } | 1930 code_ptr zero_off = code->cur + 1; |
2143 } else { | 1931 jcc(code, CC_Z, code->cur + 2); |
2144 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B); | 1932 add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); |
2145 } | 1933 add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); |
2146 and_ir(code, 63, opts->gen.scratch1, SZ_D); | 1934 cmp_ir(code, 32, opts->gen.scratch1, SZ_B); |
2147 zero_off = code->cur + 1; | 1935 code_ptr norm_off = code->cur + 1; |
2148 jcc(code, CC_Z, code->cur + 2); | 1936 jcc(code, CC_L, code->cur + 2); |
2149 add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); | 1937 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { |
2150 add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); | 1938 flag_to_carry(opts, FLAG_X); |
2151 cmp_ir(code, 32, opts->gen.scratch1, SZ_B); | 1939 init_flags |= X; |
2152 norm_off = code->cur + 1; | |
2153 jcc(code, CC_L, code->cur + 2); | |
2154 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { | |
2155 flag_to_carry(opts, FLAG_X); | |
2156 init_flags |= X; | |
2157 } else { | |
2158 sub_ir(code, 32, opts->gen.scratch1, SZ_B); | |
2159 } | |
2160 if (dst_op.mode == MODE_REG_DIRECT) { | |
2161 op_ir(code, inst, 31, dst_op.base, inst->extra.size); | |
2162 op_ir(code, inst, 1, dst_op.base, inst->extra.size); | |
2163 } else { | |
2164 op_irdisp(code, inst, 31, dst_op.base, dst_op.disp, inst->extra.size); | |
2165 op_irdisp(code, inst, 1, dst_op.base, dst_op.disp, inst->extra.size); | |
2166 } | |
2167 | |
2168 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { | |
2169 set_flag_cond(opts, CC_C, FLAG_X); | |
2170 sub_ir(code, 32, opts->gen.scratch1, SZ_B); | |
2171 *norm_off = code->cur - (norm_off+1); | |
2172 flag_to_carry(opts, FLAG_X); | |
2173 } else { | |
2174 *norm_off = code->cur - (norm_off+1); | |
2175 } | |
2176 if (dst_op.mode == MODE_REG_DIRECT) { | |
2177 op_r(code, inst, dst_op.base, inst->extra.size); | |
2178 } else { | |
2179 op_rdisp(code, inst, dst_op.base, dst_op.disp, inst->extra.size); | |
2180 } | |
2181 update_flags(opts, init_flags); | |
2182 end_off = code->cur + 1; | |
2183 jmp(code, code->cur + 2); | |
2184 *zero_off = code->cur - (zero_off+1); | |
2185 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { | |
2186 //Carry flag is set to X flag when count is 0, this is different from ROR/ROL | |
2187 flag_to_flag(opts, FLAG_X, FLAG_C); | |
2188 } else { | |
2189 set_flag(opts, 0, FLAG_C); | |
2190 } | |
2191 *end_off = code->cur - (end_off+1); | |
2192 } | |
2193 if (dst_op.mode == MODE_REG_DIRECT) { | |
2194 cmp_ir(code, 0, dst_op.base, inst->extra.size); | |
2195 } else { | 1940 } else { |
2196 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size); | 1941 sub_ir(code, 32, opts->gen.scratch1, SZ_B); |
2197 } | 1942 } |
2198 update_flags(opts, Z|N); | 1943 if (dst_op->mode == MODE_REG_DIRECT) { |
2199 } | 1944 op_ir(code, inst, 31, dst_op->base, inst->extra.size); |
2200 break; | 1945 op_ir(code, inst, 1, dst_op->base, inst->extra.size); |
2201 } | 1946 } else { |
2202 case M68K_RTE: | 1947 op_irdisp(code, inst, 31, dst_op->base, dst_op->disp, inst->extra.size); |
2203 //TODO: Trap if not in system mode | 1948 op_irdisp(code, inst, 1, dst_op->base, dst_op->disp, inst->extra.size); |
2204 //Read saved SR | 1949 } |
2205 areg_to_native(opts, 7, opts->gen.scratch1); | 1950 |
2206 call(code, opts->read_16); | 1951 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { |
2207 addi_areg(opts, 2, 7); | 1952 set_flag_cond(opts, CC_C, FLAG_X); |
2208 call(code, opts->set_sr); | 1953 sub_ir(code, 32, opts->gen.scratch1, SZ_B); |
2209 //Read saved PC | 1954 *norm_off = code->cur - (norm_off+1); |
2210 areg_to_native(opts, 7, opts->gen.scratch1); | 1955 flag_to_carry(opts, FLAG_X); |
2211 call(code, opts->read_32); | 1956 } else { |
2212 addi_areg(opts, 4, 7); | 1957 *norm_off = code->cur - (norm_off+1); |
2213 //Check if we've switched to user mode and swap stack pointers if needed | 1958 } |
2214 bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | 1959 if (dst_op->mode == MODE_REG_DIRECT) { |
2215 end_off = code->cur + 1; | 1960 op_r(code, inst, dst_op->base, inst->extra.size); |
2216 jcc(code, CC_C, code->cur + 2); | 1961 } else { |
2217 swap_ssp_usp(opts); | 1962 op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size); |
2218 *end_off = code->cur - (end_off+1); | 1963 } |
2219 //Get native address, sync components, recalculate integer points and jump to returned address | 1964 update_flags(opts, init_flags); |
2220 call(code, opts->native_addr_and_sync); | 1965 code_ptr end_off = code->cur + 1; |
2221 jmp_r(code, opts->gen.scratch1); | 1966 jmp(code, code->cur + 2); |
2222 break; | 1967 *zero_off = code->cur - (zero_off+1); |
2223 case M68K_RTR: | 1968 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { |
2224 translate_m68k_rtr(opts, inst); | 1969 //Carry flag is set to X flag when count is 0, this is different from ROR/ROL |
2225 break; | 1970 flag_to_flag(opts, FLAG_X, FLAG_C); |
2226 case M68K_STOP: { | 1971 } else { |
2227 //TODO: Trap if not in system mode | 1972 set_flag(opts, 0, FLAG_C); |
2228 //manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction | 1973 } |
2229 //possibly even 12 since that's how long MOVE to SR takes | 1974 *end_off = code->cur - (end_off+1); |
2230 cycles(&opts->gen, BUS*2); | 1975 } |
2231 uint32_t flag_mask = src_op.disp & 0x10 ? X1 : X0; | 1976 if (dst_op->mode == MODE_REG_DIRECT) { |
2232 flag_mask |= src_op.disp & 0x8 ? N1 : N0; | 1977 cmp_ir(code, 0, dst_op->base, inst->extra.size); |
2233 flag_mask |= src_op.disp & 0x4 ? Z1 : Z0; | 1978 } else { |
2234 flag_mask |= src_op.disp & 0x2 ? V1 : V0; | 1979 cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); |
2235 flag_mask |= src_op.disp & 0x1 ? C1 : C0; | 1980 } |
2236 update_flags(opts, flag_mask); | 1981 update_flags(opts, Z|N); |
2237 mov_irdisp(code, (src_op.disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | 1982 } |
1983 } | |
1984 | |
1985 void translate_m68k_illegal(m68k_options *opts, m68kinst *inst) | |
1986 { | |
1987 code_info *code = &opts->gen.code; | |
1988 call(code, opts->gen.save_context); | |
1989 #ifdef X86_64 | |
1990 mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); | |
1991 #else | |
1992 push_r(code, opts->gen.context_reg); | |
1993 #endif | |
1994 call(code, (code_ptr)print_regs_exit); | |
1995 } | |
1996 | |
1997 #define BIT_SUPERVISOR 5 | |
1998 | |
1999 void translate_m68k_andi_ccr_sr(m68k_options *opts, m68kinst *inst) | |
2000 { | |
2001 code_info *code = &opts->gen.code; | |
2002 cycles(&opts->gen, 20); | |
2003 //TODO: If ANDI to SR, trap if not in supervisor mode | |
2004 uint32_t flag_mask = 0; | |
2005 if (!(inst->src.params.immed & 0x1)) { | |
2006 flag_mask |= C0; | |
2007 } | |
2008 if (!(inst->src.params.immed & 0x2)) { | |
2009 flag_mask |= V0; | |
2010 } | |
2011 if (!(inst->src.params.immed & 0x4)) { | |
2012 flag_mask |= Z0; | |
2013 } | |
2014 if (!(inst->src.params.immed & 0x8)) { | |
2015 flag_mask |= N0; | |
2016 } | |
2017 if (!(inst->src.params.immed & 0x10)) { | |
2018 flag_mask |= X0; | |
2019 } | |
2020 update_flags(opts, flag_mask); | |
2021 if (inst->op == M68K_ANDI_SR) { | |
2022 and_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | |
2238 if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { | 2023 if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { |
2239 //leave supervisor mode | 2024 //leave supervisor mode |
2240 swap_ssp_usp(opts); | 2025 swap_ssp_usp(opts); |
2241 } | 2026 } |
2242 code_ptr loop_top = code->cur; | 2027 if (inst->src.params.immed & 0x700) { |
2243 call(code, opts->do_sync); | 2028 call(code, opts->do_sync); |
2244 cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); | 2029 } |
2245 code_ptr normal_cycle_up = code->cur + 1; | 2030 } |
2246 jcc(code, CC_A, code->cur + 2); | 2031 } |
2247 cycles(&opts->gen, BUS); | 2032 |
2248 code_ptr after_cycle_up = code->cur + 1; | 2033 void translate_m68k_ori_ccr_sr(m68k_options *opts, m68kinst *inst) |
2249 jmp(code, code->cur + 2); | 2034 { |
2250 *normal_cycle_up = code->cur - (normal_cycle_up + 1); | 2035 code_info *code = &opts->gen.code; |
2251 mov_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); | 2036 cycles(&opts->gen, 20); |
2252 *after_cycle_up = code->cur - (after_cycle_up+1); | 2037 //TODO: If ORI to SR, trap if not in supervisor mode |
2253 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); | 2038 uint32_t flag_mask = 0; |
2254 jcc(code, CC_C, loop_top); | 2039 if (inst->src.params.immed & 0x1) { |
2255 break; | 2040 flag_mask |= C1; |
2256 } | 2041 } |
2257 //case M68K_TAS: | 2042 if (inst->src.params.immed & 0x2) { |
2258 case M68K_TRAP: | 2043 flag_mask |= V1; |
2259 translate_m68k_trap(opts, inst); | 2044 } |
2260 break; | 2045 if (inst->src.params.immed & 0x4) { |
2261 //case M68K_TRAPV: | 2046 flag_mask |= Z1; |
2262 case M68K_TST: | 2047 } |
2263 case M68K_SWAP: | 2048 if (inst->src.params.immed & 0x8) { |
2264 translate_m68k_unary(opts, inst, N|Z|V0|C0, &src_op); | 2049 flag_mask |= N1; |
2265 break; | 2050 } |
2266 default: | 2051 if (inst->src.params.immed & 0x10) { |
2267 m68k_disasm(inst, disasm_buf); | 2052 flag_mask |= X1; |
2268 printf("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op); | 2053 } |
2269 exit(1); | 2054 update_flags(opts, flag_mask); |
2270 } | 2055 if (inst->op == M68K_ORI_SR) { |
2056 or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | |
2057 if (inst->src.params.immed & 0x700) { | |
2058 call(code, opts->do_sync); | |
2059 } | |
2060 } | |
2061 } | |
2062 | |
2063 void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst) | |
2064 { | |
2065 code_info *code = &opts->gen.code; | |
2066 cycles(&opts->gen, 20); | |
2067 //TODO: If ANDI to SR, trap if not in supervisor mode | |
2068 if (inst->src.params.immed & 0x1) { | |
2069 xor_flag(opts, 1, FLAG_C); | |
2070 } | |
2071 if (inst->src.params.immed & 0x2) { | |
2072 xor_flag(opts, 1, FLAG_V); | |
2073 } | |
2074 if (inst->src.params.immed & 0x4) { | |
2075 xor_flag(opts, 1, FLAG_Z); | |
2076 } | |
2077 if (inst->src.params.immed & 0x8) { | |
2078 xor_flag(opts, 1, FLAG_N); | |
2079 } | |
2080 if (inst->src.params.immed & 0x10) { | |
2081 xor_flag(opts, 1, FLAG_X); | |
2082 } | |
2083 if (inst->op == M68K_ORI_SR) { | |
2084 xor_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | |
2085 if (inst->src.params.immed & 0x700) { | |
2086 call(code, opts->do_sync); | |
2087 } | |
2088 } | |
2089 } | |
2090 | |
2091 void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | |
2092 { | |
2093 code_info *code = &opts->gen.code; | |
2094 //TODO: Privilege check for MOVE to SR | |
2095 if (src_op->mode == MODE_IMMED) { | |
2096 uint32_t flag_mask = src_op->disp & 0x10 ? X1 : X0; | |
2097 flag_mask |= src_op->disp & 0x8 ? N1 : N0; | |
2098 flag_mask |= src_op->disp & 0x4 ? Z1 : Z0; | |
2099 flag_mask |= src_op->disp & 0x2 ? V1 : V0; | |
2100 flag_mask |= src_op->disp & 0x1 ? C1 : C0; | |
2101 update_flags(opts, flag_mask); | |
2102 if (inst->op == M68K_MOVE_SR) { | |
2103 mov_irdisp(code, (src_op->disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | |
2104 if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { | |
2105 //leave supervisor mode | |
2106 mov_rr(code, opts->aregs[7], opts->gen.scratch1, SZ_D); | |
2107 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D); | |
2108 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D); | |
2109 } | |
2110 call(code, opts->do_sync); | |
2111 } | |
2112 cycles(&opts->gen, 12); | |
2113 } else { | |
2114 if (src_op->base != opts->gen.scratch1) { | |
2115 if (src_op->mode == MODE_REG_DIRECT) { | |
2116 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_W); | |
2117 } else { | |
2118 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W); | |
2119 } | |
2120 } | |
2121 call(code, inst->op == M68K_MOVE_SR ? opts->set_sr : opts->set_ccr); | |
2122 cycles(&opts->gen, 12); | |
2123 | |
2124 } | |
2125 } | |
2126 | |
2127 void translate_m68k_stop(m68k_options *opts, m68kinst *inst) | |
2128 { | |
2129 //TODO: Trap if not in system mode | |
2130 //manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction | |
2131 //possibly even 12 since that's how long MOVE to SR takes | |
2132 //On further thought prefetch + the fact that this stops the CPU may make | |
2133 //Motorola's accounting make sense here | |
2134 code_info *code = &opts->gen.code; | |
2135 cycles(&opts->gen, BUS*2); | |
2136 uint32_t flag_mask = inst->src.params.immed & 0x10 ? X1 : X0; | |
2137 flag_mask |= inst->src.params.immed & 0x8 ? N1 : N0; | |
2138 flag_mask |= inst->src.params.immed & 0x4 ? Z1 : Z0; | |
2139 flag_mask |= inst->src.params.immed & 0x2 ? V1 : V0; | |
2140 flag_mask |= inst->src.params.immed & 0x1 ? C1 : C0; | |
2141 update_flags(opts, flag_mask); | |
2142 mov_irdisp(code, (inst->src.params.immed >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | |
2143 if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { | |
2144 //leave supervisor mode | |
2145 swap_ssp_usp(opts); | |
2146 } | |
2147 code_ptr loop_top = code->cur; | |
2148 call(code, opts->do_sync); | |
2149 cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); | |
2150 code_ptr normal_cycle_up = code->cur + 1; | |
2151 jcc(code, CC_A, code->cur + 2); | |
2152 cycles(&opts->gen, BUS); | |
2153 code_ptr after_cycle_up = code->cur + 1; | |
2154 jmp(code, code->cur + 2); | |
2155 *normal_cycle_up = code->cur - (normal_cycle_up + 1); | |
2156 mov_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); | |
2157 *after_cycle_up = code->cur - (after_cycle_up+1); | |
2158 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); | |
2159 jcc(code, CC_C, loop_top); | |
2160 } | |
2161 | |
2162 void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | |
2163 { | |
2164 code_info *code = &opts->gen.code; | |
2165 //TODO: Trap if not in system mode | |
2166 call(code, opts->get_sr); | |
2167 if (dst_op->mode == MODE_REG_DIRECT) { | |
2168 mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_W); | |
2169 } else { | |
2170 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_W); | |
2171 } | |
2172 m68k_save_result(inst, opts); | |
2173 } | |
2174 | |
2175 void translate_m68k_reset(m68k_options *opts, m68kinst *inst) | |
2176 { | |
2177 code_info *code = &opts->gen.code; | |
2178 call(code, opts->gen.save_context); | |
2179 #ifdef X86_64 | |
2180 mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); | |
2181 #else | |
2182 push_r(code, opts->gen.context_reg); | |
2183 #endif | |
2184 call(code, (code_ptr)print_regs_exit); | |
2185 } | |
2186 | |
2187 void translate_m68k_rte(m68k_options *opts, m68kinst *inst) | |
2188 { | |
2189 code_info *code = &opts->gen.code; | |
2190 //TODO: Trap if not in system mode | |
2191 //Read saved SR | |
2192 areg_to_native(opts, 7, opts->gen.scratch1); | |
2193 call(code, opts->read_16); | |
2194 addi_areg(opts, 2, 7); | |
2195 call(code, opts->set_sr); | |
2196 //Read saved PC | |
2197 areg_to_native(opts, 7, opts->gen.scratch1); | |
2198 call(code, opts->read_32); | |
2199 addi_areg(opts, 4, 7); | |
2200 //Check if we've switched to user mode and swap stack pointers if needed | |
2201 bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | |
2202 code_ptr end_off = code->cur + 1; | |
2203 jcc(code, CC_C, code->cur + 2); | |
2204 swap_ssp_usp(opts); | |
2205 *end_off = code->cur - (end_off+1); | |
2206 //Get native address, sync components, recalculate integer points and jump to returned address | |
2207 call(code, opts->native_addr_and_sync); | |
2208 jmp_r(code, opts->gen.scratch1); | |
2271 } | 2209 } |
2272 | 2210 |
2273 void translate_out_of_bounds(code_info *code) | 2211 void translate_out_of_bounds(code_info *code) |
2274 { | 2212 { |
2275 xor_rr(code, RDI, RDI, SZ_D); | 2213 xor_rr(code, RDI, RDI, SZ_D); |