Mercurial > repos > blastem
comparison m68k_core_x86.c @ 1216:0649cd8ca097
Cycle accurate MULU/MULS emulation
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 04 Feb 2017 00:41:15 -0800 |
parents | e0fc8967d380 |
children | 4399044adbef |
comparison
equal
deleted
inserted
replaced
1215:cf69a179aeaf | 1216:0649cd8ca097 |
---|---|
1805 mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D); | 1805 mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D); |
1806 } | 1806 } |
1807 } | 1807 } |
1808 } | 1808 } |
1809 | 1809 |
1810 | |
1811 | |
1812 static uint32_t mulu_cycles(uint16_t value) | |
1813 { | |
1814 //4 for prefetch, 2-cycles per bit x 16, 2 for cleanup | |
1815 uint32_t cycles = 38; | |
1816 uint16_t a = (value & 0b1010101010101010) >> 1; | |
1817 uint16_t b = value & 0b0101010101010101; | |
1818 value = a + b; | |
1819 a = (value & 0b1100110011001100) >> 2; | |
1820 b = value & 0b0011001100110011; | |
1821 value = a + b; | |
1822 a = (value & 0b1111000011110000) >> 4; | |
1823 b = value & 0b0000111100001111; | |
1824 value = a + b; | |
1825 a = (value & 0b1111111100000000) >> 8; | |
1826 b = value & 0b0000000011111111; | |
1827 value = a + b; | |
1828 return cycles + 2*value; | |
1829 } | |
1830 | |
1831 static uint32_t muls_cycles(uint16_t value) | |
1832 { | |
1833 //muls timing is essentially the same as muls, but it's based on the number of 0/1 | |
1834 //transitions rather than the number of 1 bits. xoring the value with itself shifted | |
1835 //by one effectively sets one bit for every transition | |
1836 return mulu_cycles((value << 1) ^ value); | |
1837 } | |
1838 | |
1810 void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) | 1839 void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) |
1811 { | 1840 { |
1812 code_info *code = &opts->gen.code; | 1841 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) { | 1842 if (src_op->mode == MODE_IMMED) { |
1843 cycles(&opts->gen, inst->op == M68K_MULU ? mulu_cycles(src_op->disp) : muls_cycles(src_op->disp)); | |
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); | 1844 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) { | 1845 } else if (src_op->mode == MODE_REG_DIRECT) { |
1817 if (inst->op == M68K_MULS) { | 1846 if (inst->op == M68K_MULS) { |
1818 movsx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); | 1847 movsx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); |
1819 } else { | 1848 } else { |
1824 movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); | 1853 movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); |
1825 } else { | 1854 } else { |
1826 movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); | 1855 movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); |
1827 } | 1856 } |
1828 } | 1857 } |
1858 if (src_op->mode != MODE_IMMED) { | |
1859 //TODO: Inline cycle calculation so we don't need to save/restore a bunch of registers | |
1860 //save context to memory and call the relevant C function for calculating the cycle count | |
1861 call(code, opts->gen.save_context); | |
1862 push_r(code, opts->gen.scratch1); | |
1863 push_r(code, opts->gen.context_reg); | |
1864 call_args(code, (code_ptr)(inst->op == M68K_MULS ? muls_cycles : mulu_cycles), 1, opts->gen.scratch1); | |
1865 pop_r(code, opts->gen.context_reg); | |
1866 //turn 68K cycles into master clock cycles and add to the current cycle count | |
1867 imul_irr(code, opts->gen.clock_divider, RAX, RAX, SZ_D); | |
1868 add_rrdisp(code, RAX, opts->gen.context_reg, offsetof(m68k_context, current_cycle), SZ_D); | |
1869 //restore context and scratch1 | |
1870 call(code, opts->gen.load_context); | |
1871 pop_r(code, opts->gen.scratch1); | |
1872 } | |
1873 | |
1829 uint8_t dst_reg; | 1874 uint8_t dst_reg; |
1830 if (dst_op->mode == MODE_REG_DIRECT) { | 1875 if (dst_op->mode == MODE_REG_DIRECT) { |
1831 dst_reg = dst_op->base; | 1876 dst_reg = dst_op->base; |
1832 if (inst->op == M68K_MULS) { | 1877 if (inst->op == M68K_MULS) { |
1833 movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); | 1878 movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); |