Mercurial > repos > blastem
comparison z80_to_x86.c @ 627:c5820734a5b6
Added some preliminary support for interpreting Z80 code from non-RAM addresses
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 20 Jun 2014 07:57:32 -0700 |
parents | 7c46891a29b1 |
children | 041578693329 |
comparison
equal
deleted
inserted
replaced
626:7c46891a29b1 | 627:c5820734a5b6 |
---|---|
326 (context->alt_regs[Z80_IXH] << 8) | context->alt_regs[Z80_IXL], | 326 (context->alt_regs[Z80_IXH] << 8) | context->alt_regs[Z80_IXL], |
327 (context->alt_regs[Z80_IYH] << 8) | context->alt_regs[Z80_IYL]); | 327 (context->alt_regs[Z80_IYH] << 8) | context->alt_regs[Z80_IYL]); |
328 exit(0); | 328 exit(0); |
329 } | 329 } |
330 | 330 |
331 uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context, uint16_t address) | 331 uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context, uint16_t address, uint8_t interp) |
332 { | 332 { |
333 uint32_t cycles; | 333 uint32_t cycles; |
334 x86_ea src_op, dst_op; | 334 x86_ea src_op, dst_op; |
335 uint8_t size; | 335 uint8_t size; |
336 x86_z80_options *opts = context->options; | 336 x86_z80_options *opts = context->options; |
337 uint8_t * start = dst; | 337 uint8_t * start = dst; |
338 dst = z80_check_cycles_int(dst, address); | 338 if (!interp) { |
339 if (context->breakpoint_flags[address / sizeof(uint8_t)] & (1 << (address % sizeof(uint8_t)))) { | 339 dst = z80_check_cycles_int(dst, address); |
340 zbreakpoint_patch(context, address, start); | 340 if (context->breakpoint_flags[address / sizeof(uint8_t)] & (1 << (address % sizeof(uint8_t)))) { |
341 zbreakpoint_patch(context, address, start); | |
342 } | |
341 } | 343 } |
342 switch(inst->op) | 344 switch(inst->op) |
343 { | 345 { |
344 case Z80_LD: | 346 case Z80_LD: |
345 size = z80_size(inst); | 347 size = z80_size(inst); |
1658 } | 1660 } |
1659 } | 1661 } |
1660 return dst; | 1662 return dst; |
1661 } | 1663 } |
1662 | 1664 |
1665 uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context) | |
1666 { | |
1667 if (!context->interp_code[opcode]) { | |
1668 if (opcode == 0xCB || (opcode >= 0xDD && opcode & 0xF == 0xD)) { | |
1669 fprintf(stderr, "Encountered prefix byte %X at address %X. Z80 interpeter doesn't support those yet.", opcode, context->pc); | |
1670 exit(1); | |
1671 } | |
1672 uint8_t codebuf[8]; | |
1673 memset(codebuf, 0, sizeof(codebuf)); | |
1674 codebuf[0] = opcode; | |
1675 z80inst inst; | |
1676 uint8_t * after = z80_decode(codebuf, &inst); | |
1677 if (after - codebuf > 1) { | |
1678 fprintf(stderr, "Encountered multi-byte Z80 instruction at %X. Z80 interpeter doesn't support those yet.", context->pc); | |
1679 exit(1); | |
1680 } | |
1681 x86_z80_options * opts = context->options; | |
1682 if (opts->code_end - opts->cur_code < ZMAX_NATIVE_SIZE) { | |
1683 size_t size = 1024*1024; | |
1684 opts->cur_code = alloc_code(&size); | |
1685 opts->code_end = opts->cur_code + size; | |
1686 } | |
1687 context->interp_code[opcode] = opts->cur_code; | |
1688 opts->cur_code = translate_z80inst(&inst, opts->cur_code, context, 0, 1); | |
1689 opts->cur_code = mov_rdisp8r(opts->cur_code, CONTEXT, offsetof(z80_context, pc), SCRATCH1, SZ_W); | |
1690 opts->cur_code = add_ir(opts->cur_code, after - codebuf, SCRATCH1, SZ_W); | |
1691 opts->cur_code = call(opts->cur_code, (uint8_t *)z80_native_addr); | |
1692 opts->cur_code = jmp_r(opts->cur_code, SCRATCH1); | |
1693 } | |
1694 return context->interp_code[opcode]; | |
1695 } | |
1696 | |
1697 uint8_t * z80_make_interp_stub(z80_context * context, uint16_t address) | |
1698 { | |
1699 x86_z80_options *opts = context->options; | |
1700 uint8_t *dst = opts->cur_code; | |
1701 //TODO: make this play well with the breakpoint code | |
1702 dst = mov_ir(dst, address, SCRATCH1, SZ_W); | |
1703 dst = call(dst, (uint8_t *)z80_read_byte); | |
1704 //normal opcode fetch is already factored into instruction timing | |
1705 //back out the base 3 cycles from a read here | |
1706 //not quite perfect, but it will have to do for now | |
1707 dst = sub_ir(dst, 3, ZCYCLES, SZ_D); | |
1708 dst = z80_check_cycles_int(dst, address); | |
1709 dst = call(dst, (uint8_t *)z80_save_context); | |
1710 dst = mov_rr(dst, SCRATCH1, RDI, SZ_B); | |
1711 dst = mov_irdisp8(dst, address, CONTEXT, offsetof(z80_context, pc), SZ_W); | |
1712 dst = push_r(dst, CONTEXT); | |
1713 dst = call(dst, (uint8_t *)z80_interp_handler); | |
1714 dst = mov_rr(dst, RAX, SCRATCH1, SZ_Q); | |
1715 dst = pop_r(dst, CONTEXT); | |
1716 dst = call(dst, (uint8_t *)z80_load_context); | |
1717 dst = jmp_r(dst, SCRATCH1); | |
1718 opts->code_end = dst; | |
1719 return dst; | |
1720 } | |
1721 | |
1722 | |
1663 uint8_t * z80_get_native_address(z80_context * context, uint32_t address) | 1723 uint8_t * z80_get_native_address(z80_context * context, uint32_t address) |
1664 { | 1724 { |
1665 native_map_slot *map; | 1725 native_map_slot *map; |
1666 if (address < 0x4000) { | 1726 if (address < 0x4000) { |
1667 address &= 0x1FFF; | 1727 address &= 0x1FFF; |
1668 map = context->static_code_map; | 1728 map = context->static_code_map; |
1669 } else if (address >= 0x8000) { | |
1670 address &= 0x7FFF; | |
1671 map = context->banked_code_map + context->bank_reg; | |
1672 } else { | 1729 } else { |
1673 //dprintf("z80_get_native_address: %X NULL\n", address); | 1730 address -= 0x4000; |
1674 return NULL; | 1731 map = context->banked_code_map; |
1675 } | 1732 } |
1676 if (!map->base || !map->offsets || map->offsets[address] == INVALID_OFFSET || map->offsets[address] == EXTENSION_WORD) { | 1733 if (!map->base || !map->offsets || map->offsets[address] == INVALID_OFFSET || map->offsets[address] == EXTENSION_WORD) { |
1677 //dprintf("z80_get_native_address: %X NULL\n", address); | 1734 //dprintf("z80_get_native_address: %X NULL\n", address); |
1678 return NULL; | 1735 return NULL; |
1679 } | 1736 } |
1681 return map->base + map->offsets[address]; | 1738 return map->base + map->offsets[address]; |
1682 } | 1739 } |
1683 | 1740 |
1684 uint8_t z80_get_native_inst_size(x86_z80_options * opts, uint32_t address) | 1741 uint8_t z80_get_native_inst_size(x86_z80_options * opts, uint32_t address) |
1685 { | 1742 { |
1743 //TODO: Fix for addresses >= 0x4000 | |
1686 if (address >= 0x4000) { | 1744 if (address >= 0x4000) { |
1687 return 0; | 1745 return 0; |
1688 } | 1746 } |
1689 return opts->ram_inst_sizes[address & 0x1FFF]; | 1747 return opts->ram_inst_sizes[address & 0x1FFF]; |
1690 } | 1748 } |
1698 address &= 0x1FFF; | 1756 address &= 0x1FFF; |
1699 map = context->static_code_map; | 1757 map = context->static_code_map; |
1700 opts->ram_inst_sizes[address] = native_size; | 1758 opts->ram_inst_sizes[address] = native_size; |
1701 context->ram_code_flags[(address & 0x1C00) >> 10] |= 1 << ((address & 0x380) >> 7); | 1759 context->ram_code_flags[(address & 0x1C00) >> 10] |= 1 << ((address & 0x380) >> 7); |
1702 context->ram_code_flags[((address + size) & 0x1C00) >> 10] |= 1 << (((address + size) & 0x380) >> 7); | 1760 context->ram_code_flags[((address + size) & 0x1C00) >> 10] |= 1 << (((address + size) & 0x380) >> 7); |
1703 } else if (address >= 0x8000) { | 1761 } else { |
1704 address &= 0x7FFF; | 1762 //HERE |
1705 map = context->banked_code_map + context->bank_reg; | 1763 address -= 0x4000; |
1764 map = context->banked_code_map; | |
1706 if (!map->offsets) { | 1765 if (!map->offsets) { |
1707 map->offsets = malloc(sizeof(int32_t) * 0x8000); | 1766 map->offsets = malloc(sizeof(int32_t) * 0xC000); |
1708 memset(map->offsets, 0xFF, sizeof(int32_t) * 0x8000); | 1767 memset(map->offsets, 0xFF, sizeof(int32_t) * 0xC000); |
1709 } | 1768 } |
1710 } else { | |
1711 return; | |
1712 } | 1769 } |
1713 if (!map->base) { | 1770 if (!map->base) { |
1714 map->base = native_address; | 1771 map->base = native_address; |
1715 } | 1772 } |
1716 map->offsets[address] = native_address - map->base; | 1773 map->offsets[address] = native_address - map->base; |
1717 for(--size, orig_address++; size; --size, orig_address++) { | 1774 for(--size, orig_address++; size; --size, orig_address++) { |
1718 address = orig_address; | 1775 address = orig_address; |
1719 if (address < 0x4000) { | 1776 if (address < 0x4000) { |
1720 address &= 0x1FFF; | 1777 address &= 0x1FFF; |
1721 map = context->static_code_map; | 1778 map = context->static_code_map; |
1722 } else if (address >= 0x8000) { | 1779 } else { |
1723 address &= 0x7FFF; | 1780 address -= 0x4000; |
1724 map = context->banked_code_map + context->bank_reg; | 1781 map = context->banked_code_map; |
1725 } else { | |
1726 return; | |
1727 } | 1782 } |
1728 if (!map->offsets) { | 1783 if (!map->offsets) { |
1729 map->offsets = malloc(sizeof(int32_t) * 0x8000); | 1784 map->offsets = malloc(sizeof(int32_t) * 0xC000); |
1730 memset(map->offsets, 0xFF, sizeof(int32_t) * 0x8000); | 1785 memset(map->offsets, 0xFF, sizeof(int32_t) * 0xC000); |
1731 } | 1786 } |
1732 map->offsets[address] = EXTENSION_WORD; | 1787 map->offsets[address] = EXTENSION_WORD; |
1733 } | 1788 } |
1734 } | 1789 } |
1735 | 1790 |
1736 #define INVALID_INSTRUCTION_START 0xFEEDFEED | 1791 #define INVALID_INSTRUCTION_START 0xFEEDFEED |
1737 | 1792 |
1738 uint32_t z80_get_instruction_start(native_map_slot * static_code_map, uint32_t address) | 1793 uint32_t z80_get_instruction_start(native_map_slot * static_code_map, uint32_t address) |
1739 { | 1794 { |
1795 //TODO: Fixme for address >= 0x4000 | |
1740 if (!static_code_map->base || address >= 0x4000) { | 1796 if (!static_code_map->base || address >= 0x4000) { |
1741 return INVALID_INSTRUCTION_START; | 1797 return INVALID_INSTRUCTION_START; |
1742 } | 1798 } |
1743 address &= 0x1FFF; | 1799 address &= 0x1FFF; |
1744 if (static_code_map->offsets[address] == INVALID_OFFSET) { | 1800 if (static_code_map->offsets[address] == INVALID_OFFSET) { |
1812 dst = alloc_code(&size); | 1868 dst = alloc_code(&size); |
1813 opts->code_end = dst_end = dst + size; | 1869 opts->code_end = dst_end = dst + size; |
1814 opts->cur_code = dst; | 1870 opts->cur_code = dst; |
1815 } | 1871 } |
1816 deferred_addr * orig_deferred = opts->deferred; | 1872 deferred_addr * orig_deferred = opts->deferred; |
1817 uint8_t * native_end = translate_z80inst(&instbuf, dst, context, address); | 1873 uint8_t * native_end = translate_z80inst(&instbuf, dst, context, address, 0); |
1818 if ((native_end - dst) <= orig_size) { | 1874 if ((native_end - dst) <= orig_size) { |
1819 uint8_t * native_next = z80_get_native_address(context, address + after-inst); | 1875 uint8_t * native_next = z80_get_native_address(context, address + after-inst); |
1820 if (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5)) { | 1876 if (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5)) { |
1821 remove_deferred_until(&opts->deferred, orig_deferred); | 1877 remove_deferred_until(&opts->deferred, orig_deferred); |
1822 native_end = translate_z80inst(&instbuf, orig_start, context, address); | 1878 native_end = translate_z80inst(&instbuf, orig_start, context, address, 0); |
1823 if (native_next == orig_start + orig_size && (native_next-native_end) < 2) { | 1879 if (native_next == orig_start + orig_size && (native_next-native_end) < 2) { |
1824 while (native_end < orig_start + orig_size) { | 1880 while (native_end < orig_start + orig_size) { |
1825 *(native_end++) = 0x90; //NOP | 1881 *(native_end++) = 0x90; //NOP |
1826 } | 1882 } |
1827 } else { | 1883 } else { |
1838 jmp(native_end, z80_get_native_address_trans(context, address + after-inst)); | 1894 jmp(native_end, z80_get_native_address_trans(context, address + after-inst)); |
1839 } | 1895 } |
1840 z80_handle_deferred(context); | 1896 z80_handle_deferred(context); |
1841 return dst; | 1897 return dst; |
1842 } else { | 1898 } else { |
1843 dst = translate_z80inst(&instbuf, orig_start, context, address); | 1899 dst = translate_z80inst(&instbuf, orig_start, context, address, 0); |
1844 if (!z80_is_terminal(&instbuf)) { | 1900 if (!z80_is_terminal(&instbuf)) { |
1845 dst = jmp(dst, z80_get_native_address_trans(context, address + after-inst)); | 1901 dst = jmp(dst, z80_get_native_address_trans(context, address + after-inst)); |
1846 } | 1902 } |
1847 z80_handle_deferred(context); | 1903 z80_handle_deferred(context); |
1848 return orig_start; | 1904 return orig_start; |
1858 x86_z80_options * opts = context->options; | 1914 x86_z80_options * opts = context->options; |
1859 uint32_t start_address = address; | 1915 uint32_t start_address = address; |
1860 uint8_t * encoded = NULL, *next; | 1916 uint8_t * encoded = NULL, *next; |
1861 if (address < 0x4000) { | 1917 if (address < 0x4000) { |
1862 encoded = context->mem_pointers[0] + (address & 0x1FFF); | 1918 encoded = context->mem_pointers[0] + (address & 0x1FFF); |
1863 } else if(address >= 0x8000 && context->mem_pointers[1]) { | 1919 } |
1864 printf("attempt to translate Z80 code from banked area at address %X\n", address); | 1920 |
1865 exit(1); | 1921 while (encoded != NULL || address >= 0x4000) |
1866 //encoded = context->mem_pointers[1] + (address & 0x7FFF); | |
1867 } | |
1868 while (encoded != NULL) | |
1869 { | 1922 { |
1870 z80inst inst; | 1923 z80inst inst; |
1871 dprintf("translating Z80 code at address %X\n", address); | 1924 dprintf("translating Z80 code at address %X\n", address); |
1872 do { | 1925 do { |
1873 if (opts->code_end-opts->cur_code < ZMAX_NATIVE_SIZE) { | 1926 if (opts->code_end-opts->cur_code < ZMAX_NATIVE_SIZE) { |
1878 size_t size = 1024*1024; | 1931 size_t size = 1024*1024; |
1879 opts->cur_code = alloc_code(&size); | 1932 opts->cur_code = alloc_code(&size); |
1880 opts->code_end = opts->cur_code + size; | 1933 opts->code_end = opts->cur_code + size; |
1881 jmp(opts->cur_code, opts->cur_code); | 1934 jmp(opts->cur_code, opts->cur_code); |
1882 } | 1935 } |
1883 if (address > 0x4000 && address < 0x8000) { | 1936 if (address >= 0x4000) { |
1884 opts->cur_code = xor_rr(opts->cur_code, RDI, RDI, SZ_D); | 1937 uint8_t *native_start = opts->cur_code; |
1885 opts->cur_code = call(opts->cur_code, (uint8_t *)exit); | 1938 uint8_t *after = z80_make_interp_stub(context, address); |
1939 z80_map_native_address(context, address, opts->cur_code, 1, after - native_start); | |
1886 break; | 1940 break; |
1887 } | 1941 } |
1888 uint8_t * existing = z80_get_native_address(context, address); | 1942 uint8_t * existing = z80_get_native_address(context, address); |
1889 if (existing) { | 1943 if (existing) { |
1890 opts->cur_code = jmp(opts->cur_code, existing); | 1944 opts->cur_code = jmp(opts->cur_code, existing); |
1897 printf("%X\t%s(%d)\n", address, disbuf, inst.immed); | 1951 printf("%X\t%s(%d)\n", address, disbuf, inst.immed); |
1898 } else { | 1952 } else { |
1899 printf("%X\t%s\n", address, disbuf); | 1953 printf("%X\t%s\n", address, disbuf); |
1900 } | 1954 } |
1901 #endif | 1955 #endif |
1902 uint8_t *after = translate_z80inst(&inst, opts->cur_code, context, address); | 1956 uint8_t *after = translate_z80inst(&inst, opts->cur_code, context, address, 0); |
1903 z80_map_native_address(context, address, opts->cur_code, next-encoded, after - opts->cur_code); | 1957 z80_map_native_address(context, address, opts->cur_code, next-encoded, after - opts->cur_code); |
1904 opts->cur_code = after; | 1958 opts->cur_code = after; |
1905 address += next-encoded; | 1959 address += next-encoded; |
1906 if (address > 0xFFFF) { | 1960 if (address > 0xFFFF) { |
1907 address &= 0xFFFF; | 1961 address &= 0xFFFF; |
1914 if (opts->deferred) { | 1968 if (opts->deferred) { |
1915 address = opts->deferred->address; | 1969 address = opts->deferred->address; |
1916 dprintf("defferred address: %X\n", address); | 1970 dprintf("defferred address: %X\n", address); |
1917 if (address < 0x4000) { | 1971 if (address < 0x4000) { |
1918 encoded = context->mem_pointers[0] + (address & 0x1FFF); | 1972 encoded = context->mem_pointers[0] + (address & 0x1FFF); |
1919 } else if (address > 0x8000 && context->mem_pointers[1]) { | |
1920 encoded = context->mem_pointers[1] + (address & 0x7FFF); | |
1921 } else { | 1973 } else { |
1922 printf("attempt to translate non-memory address: %X\n", address); | 1974 encoded = NULL; |
1923 exit(1); | |
1924 } | 1975 } |
1925 } else { | 1976 } else { |
1926 encoded = NULL; | 1977 encoded = NULL; |
1978 address = 0; | |
1927 } | 1979 } |
1928 } | 1980 } |
1929 } | 1981 } |
1930 | 1982 |
1931 void init_x86_z80_opts(x86_z80_options * options) | 1983 void init_x86_z80_opts(x86_z80_options * options) |
1964 memset(context, 0, sizeof(*context)); | 2016 memset(context, 0, sizeof(*context)); |
1965 context->static_code_map = malloc(sizeof(*context->static_code_map)); | 2017 context->static_code_map = malloc(sizeof(*context->static_code_map)); |
1966 context->static_code_map->base = NULL; | 2018 context->static_code_map->base = NULL; |
1967 context->static_code_map->offsets = malloc(sizeof(int32_t) * 0x2000); | 2019 context->static_code_map->offsets = malloc(sizeof(int32_t) * 0x2000); |
1968 memset(context->static_code_map->offsets, 0xFF, sizeof(int32_t) * 0x2000); | 2020 memset(context->static_code_map->offsets, 0xFF, sizeof(int32_t) * 0x2000); |
1969 context->banked_code_map = malloc(sizeof(native_map_slot) * (1 << 9)); | 2021 context->banked_code_map = malloc(sizeof(native_map_slot)); |
1970 memset(context->banked_code_map, 0, sizeof(native_map_slot) * (1 << 9)); | 2022 memset(context->banked_code_map, 0, sizeof(native_map_slot)); |
1971 context->options = options; | 2023 context->options = options; |
1972 context->int_cycle = 0xFFFFFFFF; | 2024 context->int_cycle = 0xFFFFFFFF; |
1973 } | 2025 } |
1974 | 2026 |
1975 void z80_reset(z80_context * context) | 2027 void z80_reset(z80_context * context) |