comparison m68k_core_x86.c @ 1262:462d9770d467

Cycle accurate divu and undefined flags for overflow case
author Michael Pavone <pavone@retrodev.com>
date Fri, 03 Mar 2017 23:51:29 -0800
parents 2e6dcb5c11a2
children 779920729249
comparison
equal deleted inserted replaced
1261:f13f51e9f9f2 1262:462d9770d467
1688 mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); 1688 mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D);
1689 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); 1689 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
1690 jmp(code, opts->trap); 1690 jmp(code, opts->trap);
1691 *passed = code->cur - (passed+1); 1691 *passed = code->cur - (passed+1);
1692 cycles(&opts->gen, 4); 1692 cycles(&opts->gen, 4);
1693 }
1694
1695 static uint32_t divu(uint32_t dividend, m68k_context *context, uint32_t divisor_shift)
1696 {
1697 uint16_t quotient = 0;
1698 uint8_t force = 0;
1699 uint16_t bit = 0;
1700 uint32_t cycles = 6;
1701 for (int i = 0; i < 16; i++)
1702 {
1703 force = dividend >> 31;
1704 quotient = quotient << 1 | bit;
1705 dividend = dividend << 1;
1706
1707 if (force || dividend >= divisor_shift) {
1708 dividend -= divisor_shift;
1709 cycles += force ? 4 : 6;
1710 bit = 1;
1711 } else {
1712 bit = 0;
1713 cycles += 8;
1714 }
1715 }
1716 cycles += force ? 6 : bit ? 4 : 2;
1717 context->current_cycle += cycles * context->options->gen.clock_divider;
1718 quotient = quotient << 1 | bit;
1719 return dividend | quotient;
1720 }
1721
1722 void translate_m68k_divu(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1723 {
1724 code_info *code = &opts->gen.code;
1725 check_alloc_code(code, MAX_NATIVE_SIZE);
1726 set_flag(opts, 0, FLAG_C);
1727 if (dst_op->mode == MODE_REG_DIRECT) {
1728 mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_D);
1729 } else {
1730 mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_D);
1731 }
1732 if (src_op->mode == MODE_IMMED) {
1733 mov_ir(code, src_op->disp << 16, opts->gen.scratch1, SZ_D);
1734 } else {
1735 if (src_op->mode == MODE_REG_DISPLACE8) {
1736 movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D);
1737 } else if (src_op->base != opts->gen.scratch1) {
1738 movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D);
1739 }
1740 shl_ir(code, 16, opts->gen.scratch1, SZ_D);
1741 }
1742 cmp_ir(code, 0, opts->gen.scratch1, SZ_D);
1743 code_ptr not_zero = code->cur+1;
1744 jcc(code, CC_NZ, not_zero);
1745
1746 //TODO: Check that opts->trap includes the cycles conumed by the first trap0 microinstruction
1747 cycles(&opts->gen, 4);
1748 uint32_t isize = 2;
1749 switch(inst->src.addr_mode)
1750 {
1751 case MODE_AREG_DISPLACE:
1752 case MODE_AREG_INDEX_DISP8:
1753 case MODE_ABSOLUTE_SHORT:
1754 case MODE_PC_INDEX_DISP8:
1755 case MODE_IMMEDIATE:
1756 isize = 4;
1757 break;
1758 case MODE_ABSOLUTE:
1759 isize = 6;
1760 break;
1761 }
1762 mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D);
1763 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
1764 jmp(code, opts->trap);
1765
1766 *not_zero = code->cur - (not_zero + 1);
1767 cmp_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_D);
1768 code_ptr not_overflow = code->cur+1;
1769 jcc(code, CC_C, not_overflow);
1770
1771 //flags N and Z flags are set based on internal subtraction of src from top 16-bits of dst
1772 and_ir(code, 0xFFFF0000, opts->gen.scratch2, SZ_D);
1773 cmp_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_D);
1774 //TODO: verify N and Z flags are set like I think they are, microcode was a bit confusing
1775 update_flags(opts, N|Z|V1);
1776 cycles(&opts->gen, 10);
1777 code_ptr end = code->cur+1;
1778 jmp(code, end);
1779
1780 *not_overflow = code->cur - (not_overflow + 1);
1781 call(code, opts->gen.save_context);
1782 push_r(code, opts->gen.context_reg);
1783 //TODO: inline the functionality of divu so we don't need to dump context to memory
1784 call_args(code, (code_ptr)divu, 3, opts->gen.scratch2, opts->gen.context_reg, opts->gen.scratch1);
1785 pop_r(code, opts->gen.context_reg);
1786 if (dst_op->mode == MODE_REG_DIRECT) {
1787 mov_rr(code, RAX, opts->gen.scratch1, SZ_D);
1788 } else {
1789 mov_rrdisp(code, RAX, dst_op->base, dst_op->disp, SZ_D);
1790 }
1791 call(code, opts->gen.load_context);
1792
1793 if (dst_op->mode == MODE_REG_DIRECT) {
1794 mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_D);
1795 }
1796
1797 *end = code->cur - (end + 1);
1693 } 1798 }
1694 1799
1695 void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) 1800 void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1696 { 1801 {
1697 code_info *code = &opts->gen.code; 1802 code_info *code = &opts->gen.code;