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