Mercurial > repos > blastem
comparison m68k_core_x86.c @ 577:0f367276a80c
Refactor a bunch of the arithmetic instructions in the 68K core to reduce duplicate code
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 04 Mar 2014 22:12:43 -0800 |
parents | a6f2db4df70d |
children | ec1365fb2954 |
comparison
equal
deleted
inserted
replaced
576:a6f2db4df70d | 577:0f367276a80c |
---|---|
508 } | 508 } |
509 | 509 |
510 void m68k_save_result(m68kinst * inst, m68k_options * opts) | 510 void m68k_save_result(m68kinst * inst, m68k_options * opts) |
511 { | 511 { |
512 code_info *code = &opts->gen.code; | 512 code_info *code = &opts->gen.code; |
513 if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) { | 513 if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_UNUSED) { |
514 if (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) { | 514 if (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) { |
515 areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2); | 515 areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2); |
516 } | 516 } |
517 switch (inst->extra.size) | 517 switch (inst->extra.size) |
518 { | 518 { |
1327 if (inst->src.addr_mode == MODE_UNUSED) { | 1327 if (inst->src.addr_mode == MODE_UNUSED) { |
1328 m68k_save_result(inst, opts); | 1328 m68k_save_result(inst, opts); |
1329 } | 1329 } |
1330 } | 1330 } |
1331 | 1331 |
1332 void op_ir(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, uint8_t size) | |
1333 { | |
1334 switch (inst->op) | |
1335 { | |
1336 case M68K_ADD: add_ir(code, val, dst, size); break; | |
1337 case M68K_ADDX: adc_ir(code, val, dst, size); break; | |
1338 case M68K_AND: and_ir(code, val, dst, size); break; | |
1339 case M68K_EOR: xor_ir(code, val, dst, size); break; | |
1340 case M68K_OR: or_ir(code, val, dst, size); break; | |
1341 case M68K_ROL: rol_ir(code, val, dst, size); break; | |
1342 case M68K_ROR: ror_ir(code, val, dst, size); break; | |
1343 case M68K_ROXL: rcl_ir(code, val, dst, size); break; | |
1344 case M68K_ROXR: rcr_ir(code, val, dst, size); break; | |
1345 case M68K_SUB: sub_ir(code, val, dst, size); break; | |
1346 case M68K_SUBX: sbb_ir(code, val, dst, size); break; | |
1347 } | |
1348 } | |
1349 | |
1350 void op_irdisp(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, int32_t disp, uint8_t size) | |
1351 { | |
1352 switch (inst->op) | |
1353 { | |
1354 case M68K_ADD: add_irdisp(code, val, dst, disp, size); break; | |
1355 case M68K_ADDX: adc_irdisp(code, val, dst, disp, size); break; | |
1356 case M68K_AND: and_irdisp(code, val, dst, disp, size); break; | |
1357 case M68K_EOR: xor_irdisp(code, val, dst, disp, size); break; | |
1358 case M68K_OR: or_irdisp(code, val, dst, disp, size); break; | |
1359 case M68K_ROL: rol_irdisp(code, val, dst, disp, size); break; | |
1360 case M68K_ROR: ror_irdisp(code, val, dst, disp, size); break; | |
1361 case M68K_ROXL: rcl_irdisp(code, val, dst, disp, size); break; | |
1362 case M68K_ROXR: rcr_irdisp(code, val, dst, disp, size); break; | |
1363 case M68K_SUB: sub_irdisp(code, val, dst, disp, size); break; | |
1364 case M68K_SUBX: sbb_irdisp(code, val, dst, disp, size); break; | |
1365 } | |
1366 } | |
1367 | |
1368 void op_rr(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, uint8_t size) | |
1369 { | |
1370 switch (inst->op) | |
1371 { | |
1372 case M68K_ADD: add_rr(code, src, dst, size); break; | |
1373 case M68K_ADDX: adc_rr(code, src, dst, size); break; | |
1374 case M68K_AND: and_rr(code, src, dst, size); break; | |
1375 case M68K_EOR: xor_rr(code, src, dst, size); break; | |
1376 case M68K_OR: or_rr(code, src, dst, size); break; | |
1377 case M68K_SUB: sub_rr(code, src, dst, size); break; | |
1378 case M68K_SUBX: sbb_rr(code, src, dst, size); break; | |
1379 } | |
1380 } | |
1381 | |
1382 void op_rrdisp(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, int32_t disp, uint8_t size) | |
1383 { | |
1384 switch (inst->op) | |
1385 { | |
1386 case M68K_ADD: add_rrdisp(code, src, dst, disp, size); break; | |
1387 case M68K_ADDX: adc_rrdisp(code, src, dst, disp, size); break; | |
1388 case M68K_AND: and_rrdisp(code, src, dst, disp, size); break; | |
1389 case M68K_EOR: xor_rrdisp(code, src, dst, disp, size); break; | |
1390 case M68K_OR: or_rrdisp(code, src, dst, disp, size); break; | |
1391 case M68K_SUB: sub_rrdisp(code, src, dst, disp, size); break; | |
1392 case M68K_SUBX: sbb_rrdisp(code, src, dst, disp, size); break; | |
1393 } | |
1394 } | |
1395 | |
1396 void op_rdispr(code_info *code, m68kinst *inst, uint8_t src, int32_t disp, uint8_t dst, uint8_t size) | |
1397 { | |
1398 switch (inst->op) | |
1399 { | |
1400 case M68K_ADD: add_rdispr(code, src, disp, dst, size); break; | |
1401 case M68K_ADDX: adc_rdispr(code, src, disp, dst, size); break; | |
1402 case M68K_AND: and_rdispr(code, src, disp, dst, size); break; | |
1403 case M68K_EOR: xor_rdispr(code, src, disp, dst, size); break; | |
1404 case M68K_OR: or_rdispr(code, src, disp, dst, size); break; | |
1405 case M68K_SUB: sub_rdispr(code, src, disp, dst, size); break; | |
1406 case M68K_SUBX: sbb_rdispr(code, src, disp, dst, size); break; | |
1407 } | |
1408 } | |
1409 | |
1410 void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, x86_ea *src_op, x86_ea *dst_op) | |
1411 { | |
1412 code_info *code = &opts->gen.code; | |
1413 cycles(&opts->gen, BUS); | |
1414 if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) { | |
1415 flag_to_carry(opts, FLAG_X); | |
1416 } | |
1417 uint8_t size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size; | |
1418 if (src_op->mode == MODE_REG_DIRECT) { | |
1419 if (dst_op->mode == MODE_REG_DIRECT) { | |
1420 op_rr(code, inst, src_op->base, dst_op->base, size); | |
1421 } else { | |
1422 op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size); | |
1423 } | |
1424 } else if (src_op->mode == MODE_REG_DISPLACE8) { | |
1425 op_rdispr(code, inst, src_op->base, src_op->disp, dst_op->base, size); | |
1426 } else { | |
1427 if (dst_op->mode == MODE_REG_DIRECT) { | |
1428 op_ir(code, inst, src_op->disp, dst_op->base, size); | |
1429 } else { | |
1430 op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, size); | |
1431 } | |
1432 } | |
1433 if (inst->dst.addr_mode != MODE_AREG) { | |
1434 update_flags(opts, flag_mask); | |
1435 if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) { | |
1436 check_alloc_code(code, 2*MAX_INST_LEN); | |
1437 code_ptr after_flag_set = code->cur + 1; | |
1438 jcc(code, CC_Z, code->cur + 2); | |
1439 set_flag(opts, 0, FLAG_Z); | |
1440 *after_flag_set = code->cur - (after_flag_set+1); | |
1441 } | |
1442 } | |
1443 m68k_save_result(inst, opts); | |
1444 } | |
1445 | |
1446 void op_r(code_info *code, m68kinst *inst, uint8_t dst, uint8_t size) | |
1447 { | |
1448 switch(inst->op) | |
1449 { | |
1450 case M68K_NEG: neg_r(code, dst, size); break; | |
1451 case M68K_NOT: not_r(code, dst, size); cmp_ir(code, 0, dst, size); break; | |
1452 case M68K_ROL: rol_clr(code, dst, size); break; | |
1453 case M68K_ROR: ror_clr(code, dst, size); break; | |
1454 case M68K_ROXL: rcl_clr(code, dst, size); break; | |
1455 case M68K_ROXR: rcr_clr(code, dst, size); break; | |
1456 case M68K_TST: cmp_ir(code, 0, dst, size); break; | |
1457 } | |
1458 } | |
1459 | |
1460 void op_rdisp(code_info *code, m68kinst *inst, uint8_t dst, int32_t disp, uint8_t size) | |
1461 { | |
1462 switch(inst->op) | |
1463 { | |
1464 case M68K_NEG: neg_rdisp(code, dst, disp, size); break; | |
1465 case M68K_NOT: not_rdisp(code, dst, disp, size); cmp_irdisp(code, 0, dst, disp, size); break; | |
1466 case M68K_ROL: rol_clrdisp(code, dst, disp, size); break; | |
1467 case M68K_ROR: ror_clrdisp(code, dst, disp, size); break; | |
1468 case M68K_ROXL: rcl_clrdisp(code, dst, disp, size); break; | |
1469 case M68K_ROXR: rcr_clrdisp(code, dst, disp, size); break; | |
1470 case M68K_TST: cmp_irdisp(code, 0, dst, disp, size); break; | |
1471 } | |
1472 } | |
1473 | |
1474 void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, x86_ea *dst_op) | |
1475 { | |
1476 code_info *code = &opts->gen.code; | |
1477 cycles(&opts->gen, BUS); | |
1478 if (dst_op->mode == MODE_REG_DIRECT) { | |
1479 op_r(code, inst, dst_op->base, inst->extra.size); | |
1480 } else { | |
1481 op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size); | |
1482 } | |
1483 update_flags(opts, flag_mask); | |
1484 m68k_save_result(inst, opts); | |
1485 } | |
1486 | |
1332 #define BIT_SUPERVISOR 5 | 1487 #define BIT_SUPERVISOR 5 |
1333 | 1488 |
1334 void translate_m68k(m68k_options * opts, m68kinst * inst) | 1489 void translate_m68k(m68k_options * opts, m68kinst * inst) |
1335 { | 1490 { |
1336 code_ptr end_off, zero_off, norm_off; | 1491 code_ptr end_off, zero_off, norm_off; |
1420 } | 1575 } |
1421 } | 1576 } |
1422 m68k_save_result(inst, opts); | 1577 m68k_save_result(inst, opts); |
1423 break; | 1578 break; |
1424 case M68K_ADD: | 1579 case M68K_ADD: |
1425 cycles(&opts->gen, BUS); | 1580 case M68K_SUB: |
1426 size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size; | 1581 translate_m68k_arith(opts, inst, X|N|Z|V|C, &src_op, &dst_op); |
1427 if (src_op.mode == MODE_REG_DIRECT) { | 1582 break; |
1428 if (dst_op.mode == MODE_REG_DIRECT) { | 1583 case M68K_ADDX: |
1429 add_rr(code, src_op.base, dst_op.base, size); | 1584 case M68K_SUBX: |
1430 } else { | 1585 //z flag is special cased in translate_m68k_arith |
1431 add_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, size); | 1586 translate_m68k_arith(opts, inst, X|N|V|C, &src_op, &dst_op); |
1432 } | 1587 break; |
1433 } else if (src_op.mode == MODE_REG_DISPLACE8) { | |
1434 add_rdispr(code, src_op.base, src_op.disp, dst_op.base, size); | |
1435 } else { | |
1436 if (dst_op.mode == MODE_REG_DIRECT) { | |
1437 add_ir(code, src_op.disp, dst_op.base, size); | |
1438 } else { | |
1439 add_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, size); | |
1440 } | |
1441 } | |
1442 if (inst->dst.addr_mode != MODE_AREG) { | |
1443 update_flags(opts, X|N|Z|V|C); | |
1444 } | |
1445 m68k_save_result(inst, opts); | |
1446 break; | |
1447 case M68K_ADDX: { | |
1448 cycles(&opts->gen, BUS); | |
1449 flag_to_carry(opts, FLAG_X); | |
1450 if (src_op.mode == MODE_REG_DIRECT) { | |
1451 if (dst_op.mode == MODE_REG_DIRECT) { | |
1452 adc_rr(code, src_op.base, dst_op.base, inst->extra.size); | |
1453 } else { | |
1454 adc_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); | |
1455 } | |
1456 } else if (src_op.mode == MODE_REG_DISPLACE8) { | |
1457 adc_rdispr(code, src_op.base, src_op.disp, dst_op.base, inst->extra.size); | |
1458 } else { | |
1459 if (dst_op.mode == MODE_REG_DIRECT) { | |
1460 adc_ir(code, src_op.disp, dst_op.base, inst->extra.size); | |
1461 } else { | |
1462 adc_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); | |
1463 } | |
1464 } | |
1465 set_flag_cond(opts, CC_C, FLAG_C); | |
1466 | |
1467 check_alloc_code(code, 2*MAX_INST_LEN); | |
1468 code_ptr after_flag_set = code->cur + 1; | |
1469 jcc(code, CC_Z, code->cur + 2); | |
1470 set_flag(opts, 0, FLAG_Z); | |
1471 *after_flag_set = code->cur - (after_flag_set+1); | |
1472 set_flag_cond(opts, CC_S, FLAG_N); | |
1473 set_flag_cond(opts, CC_O, FLAG_V); | |
1474 if (opts->flag_regs[FLAG_C] >= 0) { | |
1475 flag_to_flag(opts, FLAG_C, FLAG_X); | |
1476 } else { | |
1477 set_flag_cond(opts, CC_C, FLAG_X); | |
1478 } | |
1479 m68k_save_result(inst, opts); | |
1480 break; | |
1481 } | |
1482 case M68K_AND: | 1588 case M68K_AND: |
1483 cycles(&opts->gen, BUS); | 1589 case M68K_EOR: |
1484 if (src_op.mode == MODE_REG_DIRECT) { | 1590 case M68K_OR: |
1485 if (dst_op.mode == MODE_REG_DIRECT) { | 1591 translate_m68k_arith(opts, inst, N|Z|V0|C0, &src_op, &dst_op); |
1486 and_rr(code, src_op.base, dst_op.base, inst->extra.size); | |
1487 } else { | |
1488 and_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); | |
1489 } | |
1490 } else if (src_op.mode == MODE_REG_DISPLACE8) { | |
1491 and_rdispr(code, src_op.base, src_op.disp, dst_op.base, inst->extra.size); | |
1492 } else { | |
1493 if (dst_op.mode == MODE_REG_DIRECT) { | |
1494 and_ir(code, src_op.disp, dst_op.base, inst->extra.size); | |
1495 } else { | |
1496 and_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); | |
1497 } | |
1498 } | |
1499 update_flags(opts, N|Z|V0|C0); | |
1500 m68k_save_result(inst, opts); | |
1501 break; | 1592 break; |
1502 case M68K_ANDI_CCR: | 1593 case M68K_ANDI_CCR: |
1503 case M68K_ANDI_SR: { | 1594 case M68K_ANDI_SR: { |
1504 cycles(&opts->gen, 20); | 1595 cycles(&opts->gen, 20); |
1505 //TODO: If ANDI to SR, trap if not in supervisor mode | 1596 //TODO: If ANDI to SR, trap if not in supervisor mode |
1801 pop_r(code, RDX); | 1892 pop_r(code, RDX); |
1802 set_flag(opts, 1, FLAG_V); | 1893 set_flag(opts, 1, FLAG_V); |
1803 *end_off = code->cur - (end_off + 1); | 1894 *end_off = code->cur - (end_off + 1); |
1804 break; | 1895 break; |
1805 } | 1896 } |
1806 case M68K_EOR: | |
1807 cycles(&opts->gen, BUS); | |
1808 if (src_op.mode == MODE_REG_DIRECT) { | |
1809 if (dst_op.mode == MODE_REG_DIRECT) { | |
1810 xor_rr(code, src_op.base, dst_op.base, inst->extra.size); | |
1811 } else { | |
1812 xor_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); | |
1813 } | |
1814 } else if (src_op.mode == MODE_REG_DISPLACE8) { | |
1815 xor_rdispr(code, src_op.base, src_op.disp, dst_op.base, inst->extra.size); | |
1816 } else { | |
1817 if (dst_op.mode == MODE_REG_DIRECT) { | |
1818 xor_ir(code, src_op.disp, dst_op.base, inst->extra.size); | |
1819 } else { | |
1820 xor_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); | |
1821 } | |
1822 } | |
1823 update_flags(opts, N|Z|V0|C0); | |
1824 m68k_save_result(inst, opts); | |
1825 break; | |
1826 case M68K_EORI_CCR: | 1897 case M68K_EORI_CCR: |
1827 case M68K_EORI_SR: | 1898 case M68K_EORI_SR: |
1828 cycles(&opts->gen, 20); | 1899 cycles(&opts->gen, 20); |
1829 //TODO: If ANDI to SR, trap if not in supervisor mode | 1900 //TODO: If ANDI to SR, trap if not in supervisor mode |
1830 if (inst->src.params.immed & 0x1) { | 1901 if (inst->src.params.immed & 0x1) { |
1983 cmp_ir(code, 0, dst_reg, SZ_D); | 2054 cmp_ir(code, 0, dst_reg, SZ_D); |
1984 update_flags(opts, N|Z|V0|C0); | 2055 update_flags(opts, N|Z|V0|C0); |
1985 break; | 2056 break; |
1986 //case M68K_NBCD: | 2057 //case M68K_NBCD: |
1987 case M68K_NEG: | 2058 case M68K_NEG: |
1988 cycles(&opts->gen, BUS); | 2059 translate_m68k_unary(opts, inst, X|N|Z|V|C, &dst_op); |
1989 if (dst_op.mode == MODE_REG_DIRECT) { | |
1990 neg_r(code, dst_op.base, inst->extra.size); | |
1991 } else { | |
1992 neg_rdisp(code, dst_op.base, dst_op.disp, inst->extra.size); | |
1993 } | |
1994 update_flags(opts, X|N|Z|V|C); | |
1995 m68k_save_result(inst, opts); | |
1996 break; | 2060 break; |
1997 case M68K_NEGX: { | 2061 case M68K_NEGX: { |
1998 cycles(&opts->gen, BUS); | 2062 cycles(&opts->gen, BUS); |
1999 if (dst_op.mode == MODE_REG_DIRECT) { | 2063 if (dst_op.mode == MODE_REG_DIRECT) { |
2000 if (dst_op.base == opts->gen.scratch1) { | 2064 if (dst_op.base == opts->gen.scratch1) { |
2033 } | 2097 } |
2034 case M68K_NOP: | 2098 case M68K_NOP: |
2035 cycles(&opts->gen, BUS); | 2099 cycles(&opts->gen, BUS); |
2036 break; | 2100 break; |
2037 case M68K_NOT: | 2101 case M68K_NOT: |
2038 if (dst_op.mode == MODE_REG_DIRECT) { | 2102 translate_m68k_unary(opts, inst, N|Z|V0|C0, &dst_op); |
2039 not_r(code, dst_op.base, inst->extra.size); | |
2040 cmp_ir(code, 0, dst_op.base, inst->extra.size); | |
2041 } else { | |
2042 not_rdisp(code, dst_op.base, dst_op.disp, inst->extra.size); | |
2043 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size); | |
2044 } | |
2045 | |
2046 update_flags(opts, N|Z|V0|C0); | |
2047 m68k_save_result(inst, opts); | |
2048 break; | |
2049 case M68K_OR: | |
2050 cycles(&opts->gen, BUS); | |
2051 if (src_op.mode == MODE_REG_DIRECT) { | |
2052 if (dst_op.mode == MODE_REG_DIRECT) { | |
2053 or_rr(code, src_op.base, dst_op.base, inst->extra.size); | |
2054 } else { | |
2055 or_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); | |
2056 } | |
2057 } else if (src_op.mode == MODE_REG_DISPLACE8) { | |
2058 or_rdispr(code, src_op.base, src_op.disp, dst_op.base, inst->extra.size); | |
2059 } else { | |
2060 if (dst_op.mode == MODE_REG_DIRECT) { | |
2061 or_ir(code, src_op.disp, dst_op.base, inst->extra.size); | |
2062 } else { | |
2063 or_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); | |
2064 } | |
2065 } | |
2066 update_flags(opts, N|Z|V0|C0); | |
2067 m68k_save_result(inst, opts); | |
2068 break; | 2103 break; |
2069 case M68K_ORI_CCR: | 2104 case M68K_ORI_CCR: |
2070 case M68K_ORI_SR: | 2105 case M68K_ORI_SR: |
2071 cycles(&opts->gen, 20); | 2106 cycles(&opts->gen, 20); |
2072 //TODO: If ORI to SR, trap if not in supervisor mode | 2107 //TODO: If ORI to SR, trap if not in supervisor mode |
2103 #endif | 2138 #endif |
2104 call(code, (code_ptr)print_regs_exit); | 2139 call(code, (code_ptr)print_regs_exit); |
2105 break; | 2140 break; |
2106 case M68K_ROL: | 2141 case M68K_ROL: |
2107 case M68K_ROR: | 2142 case M68K_ROR: |
2108 set_flag(opts, 0, FLAG_V); | 2143 case M68K_ROXL: |
2144 case M68K_ROXR: { | |
2145 int32_t init_flags = C|V0; | |
2109 if (inst->src.addr_mode == MODE_UNUSED) { | 2146 if (inst->src.addr_mode == MODE_UNUSED) { |
2110 cycles(&opts->gen, BUS); | 2147 cycles(&opts->gen, BUS); |
2111 //Memory rotate | 2148 //Memory rotate |
2112 if (inst->op == M68K_ROL) { | 2149 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { |
2113 rol_ir(code, 1, dst_op.base, inst->extra.size); | 2150 flag_to_carry(opts, FLAG_X); |
2114 } else { | 2151 init_flags |= X; |
2115 ror_ir(code, 1, dst_op.base, inst->extra.size); | 2152 } |
2116 } | 2153 op_ir(code, inst, 1, dst_op.base, inst->extra.size); |
2117 set_flag_cond(opts, CC_C, FLAG_C); | 2154 update_flags(opts, init_flags); |
2118 cmp_ir(code, 0, dst_op.base, inst->extra.size); | 2155 cmp_ir(code, 0, dst_op.base, inst->extra.size); |
2119 set_flag_cond(opts, CC_Z, FLAG_Z); | 2156 update_flags(opts, Z|N); |
2120 set_flag_cond(opts, CC_S, FLAG_N); | |
2121 m68k_save_result(inst, opts); | 2157 m68k_save_result(inst, opts); |
2122 } else { | 2158 } else { |
2123 if (src_op.mode == MODE_IMMED) { | 2159 if (src_op.mode == MODE_IMMED) { |
2124 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op.disp*2); | 2160 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op.disp*2); |
2161 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { | |
2162 flag_to_carry(opts, FLAG_X); | |
2163 init_flags |= X; | |
2164 } | |
2125 if (dst_op.mode == MODE_REG_DIRECT) { | 2165 if (dst_op.mode == MODE_REG_DIRECT) { |
2126 if (inst->op == M68K_ROL) { | 2166 op_ir(code, inst, src_op.disp, dst_op.base, inst->extra.size); |
2127 rol_ir(code, src_op.disp, dst_op.base, inst->extra.size); | |
2128 } else { | |
2129 ror_ir(code, src_op.disp, dst_op.base, inst->extra.size); | |
2130 } | |
2131 } else { | 2167 } else { |
2132 if (inst->op == M68K_ROL) { | 2168 op_irdisp(code, inst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); |
2133 rol_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); | 2169 } |
2134 } else { | 2170 update_flags(opts, init_flags); |
2135 ror_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); | |
2136 } | |
2137 } | |
2138 set_flag_cond(opts, CC_C, FLAG_C); | |
2139 } else { | 2171 } else { |
2140 if (src_op.mode == MODE_REG_DIRECT) { | 2172 if (src_op.mode == MODE_REG_DIRECT) { |
2141 if (src_op.base != opts->gen.scratch1) { | 2173 if (src_op.base != opts->gen.scratch1) { |
2142 mov_rr(code, src_op.base, opts->gen.scratch1, SZ_B); | 2174 mov_rr(code, src_op.base, opts->gen.scratch1, SZ_B); |
2143 } | 2175 } |
2150 add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); | 2182 add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); |
2151 add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); | 2183 add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); |
2152 cmp_ir(code, 32, opts->gen.scratch1, SZ_B); | 2184 cmp_ir(code, 32, opts->gen.scratch1, SZ_B); |
2153 norm_off = code->cur + 1; | 2185 norm_off = code->cur + 1; |
2154 jcc(code, CC_L, code->cur + 2); | 2186 jcc(code, CC_L, code->cur + 2); |
2155 sub_ir(code, 32, opts->gen.scratch1, SZ_B); | 2187 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { |
2188 flag_to_carry(opts, FLAG_X); | |
2189 init_flags |= X; | |
2190 } else { | |
2191 sub_ir(code, 32, opts->gen.scratch1, SZ_B); | |
2192 } | |
2156 if (dst_op.mode == MODE_REG_DIRECT) { | 2193 if (dst_op.mode == MODE_REG_DIRECT) { |
2157 if (inst->op == M68K_ROL) { | 2194 op_ir(code, inst, 31, dst_op.base, inst->extra.size); |
2158 rol_ir(code, 31, dst_op.base, inst->extra.size); | 2195 op_ir(code, inst, 1, dst_op.base, inst->extra.size); |
2159 rol_ir(code, 1, dst_op.base, inst->extra.size); | |
2160 } else { | |
2161 ror_ir(code, 31, dst_op.base, inst->extra.size); | |
2162 ror_ir(code, 1, dst_op.base, inst->extra.size); | |
2163 } | |
2164 } else { | 2196 } else { |
2165 if (inst->op == M68K_ROL) { | 2197 op_irdisp(code, inst, 31, dst_op.base, dst_op.disp, inst->extra.size); |
2166 rol_irdisp(code, 31, dst_op.base, dst_op.disp, inst->extra.size); | 2198 op_irdisp(code, inst, 1, dst_op.base, dst_op.disp, inst->extra.size); |
2167 rol_irdisp(code, 1, dst_op.base, dst_op.disp, inst->extra.size); | 2199 } |
2168 } else { | 2200 |
2169 ror_irdisp(code, 31, dst_op.base, dst_op.disp, inst->extra.size); | 2201 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { |
2170 ror_irdisp(code, 1, dst_op.base, dst_op.disp, inst->extra.size); | 2202 set_flag_cond(opts, CC_C, FLAG_X); |
2171 } | 2203 sub_ir(code, 32, opts->gen.scratch1, SZ_B); |
2172 } | 2204 *norm_off = code->cur - (norm_off+1); |
2173 *norm_off = code->cur - (norm_off+1); | 2205 flag_to_carry(opts, FLAG_X); |
2206 } else { | |
2207 *norm_off = code->cur - (norm_off+1); | |
2208 } | |
2174 if (dst_op.mode == MODE_REG_DIRECT) { | 2209 if (dst_op.mode == MODE_REG_DIRECT) { |
2175 if (inst->op == M68K_ROL) { | 2210 op_r(code, inst, dst_op.base, inst->extra.size); |
2176 rol_clr(code, dst_op.base, inst->extra.size); | |
2177 } else { | |
2178 ror_clr(code, dst_op.base, inst->extra.size); | |
2179 } | |
2180 } else { | 2211 } else { |
2181 if (inst->op == M68K_ROL) { | 2212 op_rdisp(code, inst, dst_op.base, dst_op.disp, inst->extra.size); |
2182 rol_clrdisp(code, dst_op.base, dst_op.disp, inst->extra.size); | 2213 } |
2183 } else { | 2214 update_flags(opts, init_flags); |
2184 ror_clrdisp(code, dst_op.base, dst_op.disp, inst->extra.size); | |
2185 } | |
2186 } | |
2187 set_flag_cond(opts, CC_C, FLAG_C); | |
2188 end_off = code->cur + 1; | 2215 end_off = code->cur + 1; |
2189 jmp(code, code->cur + 2); | 2216 jmp(code, code->cur + 2); |
2190 *zero_off = code->cur - (zero_off+1); | 2217 *zero_off = code->cur - (zero_off+1); |
2191 set_flag(opts, 0, FLAG_C); | 2218 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { |
2219 //Carry flag is set to X flag when count is 0, this is different from ROR/ROL | |
2220 flag_to_flag(opts, FLAG_X, FLAG_C); | |
2221 } else { | |
2222 set_flag(opts, 0, FLAG_C); | |
2223 } | |
2192 *end_off = code->cur - (end_off+1); | 2224 *end_off = code->cur - (end_off+1); |
2193 } | 2225 } |
2194 if (dst_op.mode == MODE_REG_DIRECT) { | 2226 if (dst_op.mode == MODE_REG_DIRECT) { |
2195 cmp_ir(code, 0, dst_op.base, inst->extra.size); | 2227 cmp_ir(code, 0, dst_op.base, inst->extra.size); |
2196 } else { | 2228 } else { |
2197 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size); | 2229 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size); |
2198 } | 2230 } |
2199 set_flag_cond(opts, CC_Z, FLAG_Z); | 2231 update_flags(opts, Z|N); |
2200 set_flag_cond(opts, CC_S, FLAG_N); | 2232 } |
2201 } | 2233 break; |
2202 break; | 2234 } |
2203 case M68K_ROXL: | |
2204 case M68K_ROXR: | |
2205 set_flag(opts, 0, FLAG_V); | |
2206 if (inst->src.addr_mode == MODE_UNUSED) { | |
2207 cycles(&opts->gen, BUS); | |
2208 //Memory rotate | |
2209 flag_to_carry(opts, FLAG_X); | |
2210 if (inst->op == M68K_ROXL) { | |
2211 rcl_ir(code, 1, dst_op.base, inst->extra.size); | |
2212 } else { | |
2213 rcr_ir(code, 1, dst_op.base, inst->extra.size); | |
2214 } | |
2215 set_flag_cond(opts, CC_C, FLAG_C); | |
2216 if (opts->flag_regs[FLAG_C] < 0) { | |
2217 set_flag_cond(opts, CC_C, FLAG_X); | |
2218 } | |
2219 cmp_ir(code, 0, dst_op.base, inst->extra.size); | |
2220 set_flag_cond(opts, CC_Z, FLAG_Z); | |
2221 set_flag_cond(opts, CC_S, FLAG_N); | |
2222 if (opts->flag_regs[FLAG_C] >= 0) { | |
2223 flag_to_flag(opts, FLAG_C, FLAG_X); | |
2224 } | |
2225 m68k_save_result(inst, opts); | |
2226 } else { | |
2227 if (src_op.mode == MODE_IMMED) { | |
2228 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op.disp*2); | |
2229 flag_to_carry(opts, FLAG_X); | |
2230 if (dst_op.mode == MODE_REG_DIRECT) { | |
2231 if (inst->op == M68K_ROXL) { | |
2232 rcl_ir(code, src_op.disp, dst_op.base, inst->extra.size); | |
2233 } else { | |
2234 rcr_ir(code, src_op.disp, dst_op.base, inst->extra.size); | |
2235 } | |
2236 } else { | |
2237 if (inst->op == M68K_ROXL) { | |
2238 rcl_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); | |
2239 } else { | |
2240 rcr_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); | |
2241 } | |
2242 } | |
2243 set_flag_cond(opts, CC_C, FLAG_C); | |
2244 if (opts->flag_regs[FLAG_C] >= 0) { | |
2245 flag_to_flag(opts, FLAG_C, FLAG_X); | |
2246 } else { | |
2247 set_flag_cond(opts, CC_C, FLAG_X); | |
2248 } | |
2249 } else { | |
2250 if (src_op.mode == MODE_REG_DIRECT) { | |
2251 if (src_op.base != opts->gen.scratch1) { | |
2252 mov_rr(code, src_op.base, opts->gen.scratch1, SZ_B); | |
2253 } | |
2254 } else { | |
2255 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B); | |
2256 } | |
2257 and_ir(code, 63, opts->gen.scratch1, SZ_D); | |
2258 zero_off = code->cur + 1; | |
2259 jcc(code, CC_Z, code->cur + 2); | |
2260 add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); | |
2261 add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); | |
2262 cmp_ir(code, 32, opts->gen.scratch1, SZ_B); | |
2263 norm_off = code->cur + 1; | |
2264 jcc(code, CC_L, code->cur + 2); | |
2265 flag_to_carry(opts, FLAG_X); | |
2266 if (dst_op.mode == MODE_REG_DIRECT) { | |
2267 if (inst->op == M68K_ROXL) { | |
2268 rcl_ir(code, 31, dst_op.base, inst->extra.size); | |
2269 rcl_ir(code, 1, dst_op.base, inst->extra.size); | |
2270 } else { | |
2271 rcr_ir(code, 31, dst_op.base, inst->extra.size); | |
2272 rcr_ir(code, 1, dst_op.base, inst->extra.size); | |
2273 } | |
2274 } else { | |
2275 if (inst->op == M68K_ROXL) { | |
2276 rcl_irdisp(code, 31, dst_op.base, dst_op.disp, inst->extra.size); | |
2277 rcl_irdisp(code, 1, dst_op.base, dst_op.disp, inst->extra.size); | |
2278 } else { | |
2279 rcr_irdisp(code, 31, dst_op.base, dst_op.disp, inst->extra.size); | |
2280 rcr_irdisp(code, 1, dst_op.base, dst_op.disp, inst->extra.size); | |
2281 } | |
2282 } | |
2283 set_flag_cond(opts, CC_C, FLAG_X); | |
2284 sub_ir(code, 32, opts->gen.scratch1, SZ_B); | |
2285 *norm_off = code->cur - (norm_off+1); | |
2286 flag_to_carry(opts, FLAG_X); | |
2287 if (dst_op.mode == MODE_REG_DIRECT) { | |
2288 if (inst->op == M68K_ROXL) { | |
2289 rcl_clr(code, dst_op.base, inst->extra.size); | |
2290 } else { | |
2291 rcr_clr(code, dst_op.base, inst->extra.size); | |
2292 } | |
2293 } else { | |
2294 if (inst->op == M68K_ROXL) { | |
2295 rcl_clrdisp(code, dst_op.base, dst_op.disp, inst->extra.size); | |
2296 } else { | |
2297 rcr_clrdisp(code, dst_op.base, dst_op.disp, inst->extra.size); | |
2298 } | |
2299 } | |
2300 set_flag_cond(opts, CC_C, FLAG_C); | |
2301 if (opts->flag_regs[FLAG_C] >= 0) { | |
2302 flag_to_flag(opts, FLAG_C, FLAG_X); | |
2303 } else { | |
2304 set_flag_cond(opts, CC_C, FLAG_X); | |
2305 } | |
2306 end_off = code->cur + 1; | |
2307 jmp(code, code->cur + 2); | |
2308 *zero_off = code->cur - (zero_off+1); | |
2309 //Carry flag is set to X flag when count is 0, this is different from ROR/ROL | |
2310 flag_to_flag(opts, FLAG_X, FLAG_C); | |
2311 *end_off = code->cur - (end_off+1); | |
2312 } | |
2313 if (dst_op.mode == MODE_REG_DIRECT) { | |
2314 cmp_ir(code, 0, dst_op.base, inst->extra.size); | |
2315 } else { | |
2316 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size); | |
2317 } | |
2318 set_flag_cond(opts, CC_Z, FLAG_Z); | |
2319 set_flag_cond(opts, CC_S, FLAG_N); | |
2320 } | |
2321 break; | |
2322 case M68K_RTE: | 2235 case M68K_RTE: |
2323 //TODO: Trap if not in system mode | 2236 //TODO: Trap if not in system mode |
2324 //Read saved SR | 2237 //Read saved SR |
2325 areg_to_native(opts, 7, opts->gen.scratch1); | 2238 areg_to_native(opts, 7, opts->gen.scratch1); |
2326 call(code, opts->read_16); | 2239 call(code, opts->read_16); |
2408 *after_cycle_up = code->cur - (after_cycle_up+1); | 2321 *after_cycle_up = code->cur - (after_cycle_up+1); |
2409 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); | 2322 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); |
2410 jcc(code, CC_C, loop_top); | 2323 jcc(code, CC_C, loop_top); |
2411 break; | 2324 break; |
2412 } | 2325 } |
2413 case M68K_SUB: | |
2414 size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size; | |
2415 cycles(&opts->gen, BUS); | |
2416 if (src_op.mode == MODE_REG_DIRECT) { | |
2417 if (dst_op.mode == MODE_REG_DIRECT) { | |
2418 sub_rr(code, src_op.base, dst_op.base, size); | |
2419 } else { | |
2420 sub_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, size); | |
2421 } | |
2422 } else if (src_op.mode == MODE_REG_DISPLACE8) { | |
2423 sub_rdispr(code, src_op.base, src_op.disp, dst_op.base, size); | |
2424 } else { | |
2425 if (dst_op.mode == MODE_REG_DIRECT) { | |
2426 sub_ir(code, src_op.disp, dst_op.base, size); | |
2427 } else { | |
2428 sub_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, size); | |
2429 } | |
2430 } | |
2431 if (inst->dst.addr_mode != MODE_AREG) { | |
2432 update_flags(opts, X|N|Z|V|C); | |
2433 } | |
2434 m68k_save_result(inst, opts); | |
2435 break; | |
2436 case M68K_SUBX: { | |
2437 cycles(&opts->gen, BUS); | |
2438 flag_to_carry(opts, FLAG_X); | |
2439 if (src_op.mode == MODE_REG_DIRECT) { | |
2440 if (dst_op.mode == MODE_REG_DIRECT) { | |
2441 sbb_rr(code, src_op.base, dst_op.base, inst->extra.size); | |
2442 } else { | |
2443 sbb_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); | |
2444 } | |
2445 } else if (src_op.mode == MODE_REG_DISPLACE8) { | |
2446 sbb_rdispr(code, src_op.base, src_op.disp, dst_op.base, inst->extra.size); | |
2447 } else { | |
2448 if (dst_op.mode == MODE_REG_DIRECT) { | |
2449 sbb_ir(code, src_op.disp, dst_op.base, inst->extra.size); | |
2450 } else { | |
2451 sbb_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); | |
2452 } | |
2453 } | |
2454 set_flag_cond(opts, CC_C, FLAG_C); | |
2455 if (opts->flag_regs[FLAG_C] < 0) { | |
2456 set_flag_cond(opts, CC_C, FLAG_X); | |
2457 } | |
2458 code_ptr after_flag_set = code->cur + 1; | |
2459 jcc(code, CC_Z, code->cur + 2); | |
2460 set_flag(opts, 0, FLAG_Z); | |
2461 *after_flag_set = code->cur - (after_flag_set+1); | |
2462 set_flag_cond(opts, CC_S, FLAG_N); | |
2463 set_flag_cond(opts, CC_O, FLAG_V); | |
2464 if (opts->flag_regs[FLAG_C] >= 0) { | |
2465 flag_to_flag(opts, FLAG_C, FLAG_X); | |
2466 } | |
2467 m68k_save_result(inst, opts); | |
2468 break; | |
2469 } | |
2470 case M68K_SWAP: | 2326 case M68K_SWAP: |
2471 cycles(&opts->gen, BUS); | 2327 cycles(&opts->gen, BUS); |
2472 if (src_op.mode == MODE_REG_DIRECT) { | 2328 if (src_op.mode == MODE_REG_DIRECT) { |
2473 rol_ir(code, 16, src_op.base, SZ_D); | 2329 rol_ir(code, 16, src_op.base, SZ_D); |
2474 cmp_ir(code, 0, src_op.base, SZ_D); | 2330 cmp_ir(code, 0, src_op.base, SZ_D); |
2483 case M68K_TRAP: | 2339 case M68K_TRAP: |
2484 translate_m68k_trap(opts, inst); | 2340 translate_m68k_trap(opts, inst); |
2485 break; | 2341 break; |
2486 //case M68K_TRAPV: | 2342 //case M68K_TRAPV: |
2487 case M68K_TST: | 2343 case M68K_TST: |
2488 cycles(&opts->gen, BUS); | 2344 translate_m68k_unary(opts, inst, N|Z|V0|C0, &src_op); |
2489 if (src_op.mode == MODE_REG_DIRECT) { | |
2490 cmp_ir(code, 0, src_op.base, inst->extra.size); | |
2491 } else { //M68000 doesn't support immedate operand for tst, so this must be MODE_REG_DISPLACE8 | |
2492 cmp_irdisp(code, 0, src_op.base, src_op.disp, inst->extra.size); | |
2493 } | |
2494 update_flags(opts, N|Z|V0|C0); | |
2495 break; | 2345 break; |
2496 default: | 2346 default: |
2497 m68k_disasm(inst, disasm_buf); | 2347 m68k_disasm(inst, disasm_buf); |
2498 printf("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op); | 2348 printf("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op); |
2499 exit(1); | 2349 exit(1); |