Mercurial > repos > blastem
comparison genesis.c @ 2034:8b2ef428d1aa
Implement TMSS ROM and cart mapping register
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 21 Feb 2021 14:35:16 -0800 |
parents | 894bf99a13f1 |
children | b0b0c31338c3 |
comparison
equal
deleted
inserted
replaced
2033:894bf99a13f1 | 2034:8b2ef428d1aa |
---|---|
1174 genesis_context *gen = context->system; | 1174 genesis_context *gen = context->system; |
1175 uint8_t has_tmss = gen->version_reg & 0xF; | 1175 uint8_t has_tmss = gen->version_reg & 0xF; |
1176 if (has_tmss && (location == 0xA14000 || location == 0xA14002)) { | 1176 if (has_tmss && (location == 0xA14000 || location == 0xA14002)) { |
1177 gen->tmss_lock[location >> 1 & 1] = value; | 1177 gen->tmss_lock[location >> 1 & 1] = value; |
1178 } else if (has_tmss && location == 0xA14100) { | 1178 } else if (has_tmss && location == 0xA14100) { |
1179 //TODO: implement TMSS control register | 1179 value &= 1; |
1180 if (gen->tmss != value) { | |
1181 gen->tmss = value; | |
1182 for (int i = 0; i < NUM_MEM_AREAS; i++) | |
1183 { | |
1184 uint16_t *tmp = context->mem_pointers[i]; | |
1185 context->mem_pointers[i] = gen->tmss_pointers[i]; | |
1186 gen->tmss_pointers[i] = tmp; | |
1187 } | |
1188 m68k_invalidate_code_range(context, 0, 0x400000); | |
1189 } | |
1180 } else if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { | 1190 } else if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { |
1181 //these writes are ignored when no relevant hardware is present | 1191 //these writes are ignored when no relevant hardware is present |
1182 } else { | 1192 } else { |
1183 fatal_error("Machine freeze due to unmapped write to %X\n", location); | 1193 fatal_error("Machine freeze due to unmapped write to %X\n", location); |
1184 } | 1194 } |
1198 } else { | 1208 } else { |
1199 gen->tmss_lock[offset] &= 0xFF; | 1209 gen->tmss_lock[offset] &= 0xFF; |
1200 gen->tmss_lock[offset] |= value << 8; | 1210 gen->tmss_lock[offset] |= value << 8; |
1201 } | 1211 } |
1202 } else if (has_tmss && (location == 0xA14100 || location == 0xA14101)) { | 1212 } else if (has_tmss && (location == 0xA14100 || location == 0xA14101)) { |
1203 //TODO: implement TMSS control register | 1213 if (location & 1) { |
1214 value &= 1; | |
1215 if (gen->tmss != value) { | |
1216 gen->tmss = value; | |
1217 for (int i = 0; i < NUM_MEM_AREAS; i++) | |
1218 { | |
1219 uint16_t *tmp = context->mem_pointers[i]; | |
1220 context->mem_pointers[i] = gen->tmss_pointers[i]; | |
1221 gen->tmss_pointers[i] = tmp; | |
1222 } | |
1223 m68k_invalidate_code_range(context, 0, 0x400000); | |
1224 } | |
1225 } | |
1204 } else if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { | 1226 } else if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { |
1205 //these writes are ignored when no relevant hardware is present | 1227 //these writes are ignored when no relevant hardware is present |
1206 } else { | 1228 } else { |
1207 fatal_error("Machine freeze due to unmapped byte write to %X\n", location); | 1229 fatal_error("Machine freeze due to unmapped byte write to %X\n", location); |
1208 } | 1230 } |
1540 puts("Stopped VGM log"); | 1562 puts("Stopped VGM log"); |
1541 genesis_context *gen = (genesis_context *)system; | 1563 genesis_context *gen = (genesis_context *)system; |
1542 vgm_close(gen->ym->vgm); | 1564 vgm_close(gen->ym->vgm); |
1543 gen->ym->vgm = gen->psg->vgm = NULL; | 1565 gen->ym->vgm = gen->psg->vgm = NULL; |
1544 gen->header.vgm_logging = 0; | 1566 gen->header.vgm_logging = 0; |
1567 } | |
1568 | |
1569 static void *tmss_rom_write_16(uint32_t address, void *context, uint16_t value) | |
1570 { | |
1571 m68k_context *m68k = context; | |
1572 genesis_context *gen = m68k->system; | |
1573 if (gen->tmss) { | |
1574 return gen->tmss_write_16(address, context, value); | |
1575 } | |
1576 | |
1577 return context; | |
1578 } | |
1579 | |
1580 static void *tmss_rom_write_8(uint32_t address, void *context, uint8_t value) | |
1581 { | |
1582 m68k_context *m68k = context; | |
1583 genesis_context *gen = m68k->system; | |
1584 if (gen->tmss) { | |
1585 return gen->tmss_write_8(address, context, value); | |
1586 } | |
1587 | |
1588 return context; | |
1589 } | |
1590 | |
1591 static uint16_t tmss_rom_read_16(uint32_t address, void *context) | |
1592 { | |
1593 m68k_context *m68k = context; | |
1594 genesis_context *gen = m68k->system; | |
1595 if (gen->tmss) { | |
1596 return gen->tmss_read_16(address, context); | |
1597 } | |
1598 return ((uint16_t *)gen->tmss_buffer)[address >> 1]; | |
1599 } | |
1600 | |
1601 static uint8_t tmss_rom_read_8(uint32_t address, void *context) | |
1602 { | |
1603 m68k_context *m68k = context; | |
1604 genesis_context *gen = m68k->system; | |
1605 if (gen->tmss) { | |
1606 return gen->tmss_read_8(address, context); | |
1607 } | |
1608 #ifdef BLASTEM_BIG_ENDIAN | |
1609 return gen->tmss_buffer[address]; | |
1610 #else | |
1611 return gen->tmss_buffer[address ^ 1]; | |
1612 #endif | |
1613 } | |
1614 | |
1615 static void *tmss_word_write_16(uint32_t address, void *context, uint16_t value) | |
1616 { | |
1617 m68k_context *m68k = context; | |
1618 genesis_context *gen = m68k->system; | |
1619 if (gen->tmss) { | |
1620 address += gen->tmss_write_offset; | |
1621 uint16_t *dest = get_native_pointer(address, (void **)m68k->mem_pointers, &m68k->options->gen); | |
1622 *dest = value; | |
1623 m68k_handle_code_write(address, m68k); | |
1624 } | |
1625 | |
1626 return context; | |
1627 } | |
1628 | |
1629 static void *tmss_word_write_8(uint32_t address, void *context, uint8_t value) | |
1630 { | |
1631 m68k_context *m68k = context; | |
1632 genesis_context *gen = m68k->system; | |
1633 if (gen->tmss) { | |
1634 address += gen->tmss_write_offset; | |
1635 uint8_t *dest = get_native_pointer(address & ~1, (void **)m68k->mem_pointers, &m68k->options->gen); | |
1636 #ifdef BLASTEM_BIG_ENDIAN | |
1637 dest[address & 1] = value; | |
1638 #else | |
1639 dest[address & 1 ^ 1] = value; | |
1640 #endif | |
1641 m68k_handle_code_write(address & ~1, m68k); | |
1642 } | |
1643 | |
1644 return context; | |
1645 } | |
1646 | |
1647 static void *tmss_odd_write_16(uint32_t address, void *context, uint16_t value) | |
1648 { | |
1649 m68k_context *m68k = context; | |
1650 genesis_context *gen = m68k->system; | |
1651 if (gen->tmss) { | |
1652 memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); | |
1653 address >>= 1; | |
1654 uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; | |
1655 base[address] = value; | |
1656 } | |
1657 return context; | |
1658 } | |
1659 | |
1660 static void *tmss_odd_write_8(uint32_t address, void *context, uint8_t value) | |
1661 { | |
1662 m68k_context *m68k = context; | |
1663 genesis_context *gen = m68k->system; | |
1664 if (gen->tmss && (address & 1)) { | |
1665 memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); | |
1666 address >>= 1; | |
1667 uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; | |
1668 base[address] = value; | |
1669 } | |
1670 return context; | |
1671 } | |
1672 | |
1673 static void *tmss_even_write_16(uint32_t address, void *context, uint16_t value) | |
1674 { | |
1675 m68k_context *m68k = context; | |
1676 genesis_context *gen = m68k->system; | |
1677 if (gen->tmss) { | |
1678 memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); | |
1679 address >>= 1; | |
1680 uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; | |
1681 base[address] = value >> 8; | |
1682 } | |
1683 return context; | |
1684 } | |
1685 | |
1686 static void *tmss_even_write_8(uint32_t address, void *context, uint8_t value) | |
1687 { | |
1688 m68k_context *m68k = context; | |
1689 genesis_context *gen = m68k->system; | |
1690 if (gen->tmss && !(address & 1)) { | |
1691 memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); | |
1692 address >>= 1; | |
1693 uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; | |
1694 base[address] = value; | |
1695 } | |
1696 return context; | |
1545 } | 1697 } |
1546 | 1698 |
1547 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region) | 1699 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region) |
1548 { | 1700 { |
1549 static memmap_chunk z80_map[] = { | 1701 static memmap_chunk z80_map[] = { |
1678 } | 1830 } |
1679 } else { | 1831 } else { |
1680 gen->save_storage = NULL; | 1832 gen->save_storage = NULL; |
1681 } | 1833 } |
1682 | 1834 |
1835 gen->mapper_start_index = rom->mapper_start_index; | |
1836 | |
1683 //This must happen before we generate memory access functions in init_m68k_opts | 1837 //This must happen before we generate memory access functions in init_m68k_opts |
1838 uint8_t next_ptr_index = 0; | |
1839 uint32_t tmss_min_alloc = 16 * 1024; | |
1684 for (int i = 0; i < rom->map_chunks; i++) | 1840 for (int i = 0; i < rom->map_chunks; i++) |
1685 { | 1841 { |
1686 if (rom->map[i].start == 0xE00000) { | 1842 if (rom->map[i].start == 0xE00000) { |
1687 rom->map[i].buffer = gen->work_ram; | 1843 rom->map[i].buffer = gen->work_ram; |
1688 break; | 1844 if (!tmss) { |
1689 } | 1845 break; |
1846 } | |
1847 } | |
1848 if (rom->map[i].flags & MMAP_PTR_IDX && rom->map[i].ptr_index >= next_ptr_index) { | |
1849 next_ptr_index = rom->map[i].ptr_index + 1; | |
1850 } | |
1851 if (rom->map[i].start < 0x400000 && rom->map[i].read_16 != unused_read) { | |
1852 uint32_t highest_offset = (rom->map[i].end & rom->map[i].mask) + 1; | |
1853 if (highest_offset > tmss_min_alloc) { | |
1854 tmss_min_alloc = highest_offset; | |
1855 } | |
1856 } | |
1857 } | |
1858 if (tmss) { | |
1859 char *tmss_path = tern_find_path_default(config, "system\0tmss_path\0", (tern_val){.ptrval = "tmss.md"}, TVAL_PTR).ptrval; | |
1860 uint8_t *buffer = malloc(tmss_min_alloc); | |
1861 uint32_t tmss_size; | |
1862 if (is_absolute_path(tmss_path)) { | |
1863 FILE *f = fopen(tmss_path, "rb"); | |
1864 if (!f) { | |
1865 fatal_error("Configured to use a model with TMSS, but failed to load the TMSS ROM from %s\n", tmss_path); | |
1866 } | |
1867 tmss_size = fread(buffer, 1, tmss_min_alloc, f); | |
1868 fclose(f); | |
1869 } else { | |
1870 char *tmp = read_bundled_file(tmss_path, &tmss_size); | |
1871 if (!tmp) { | |
1872 fatal_error("Configured to use a model with TMSS, but failed to load the TMSS ROM from %s\n", tmss_path); | |
1873 } | |
1874 memcpy(buffer, tmp, tmss_size); | |
1875 free(tmp); | |
1876 } | |
1877 for (uint32_t padded = nearest_pow2(tmss_size); tmss_size < padded; tmss_size++) | |
1878 { | |
1879 buffer[tmss_size] = 0xFF; | |
1880 } | |
1881 #ifndef BLASTEM_BIG_ENDIAN | |
1882 byteswap_rom(tmss_size, (uint16_t *)buffer); | |
1883 #endif | |
1884 //mirror TMSS ROM until we fill up to tmss_min_alloc | |
1885 for (uint32_t dst = tmss_size; dst < tmss_min_alloc; dst += tmss_size) | |
1886 { | |
1887 memcpy(buffer + dst, buffer, dst + tmss_size > tmss_min_alloc ? tmss_min_alloc - dst : tmss_size); | |
1888 } | |
1889 //modify mappings for ROM space to point to the TMSS ROM and fixup flags to allow switching back and forth | |
1890 //WARNING: This code makes some pretty big assumptions about the kinds of map chunks it will encounter | |
1891 for (int i = 0; i < rom->map_chunks; i++) | |
1892 { | |
1893 if (rom->map[i].start < 0x400000 && rom->map[i].read_16 != unused_read) { | |
1894 if (rom->map[i].flags == MMAP_READ) { | |
1895 //Normal ROM | |
1896 rom->map[i].flags |= MMAP_PTR_IDX | MMAP_CODE; | |
1897 rom->map[i].ptr_index = next_ptr_index++; | |
1898 if (rom->map[i].ptr_index >= NUM_MEM_AREAS) { | |
1899 fatal_error("Too many memmap chunks with MMAP_PTR_IDX after TMSS remap\n"); | |
1900 } | |
1901 gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | |
1902 rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); | |
1903 } else if (rom->map[i].flags & MMAP_PTR_IDX) { | |
1904 //Sega mapper page or multi-game mapper | |
1905 gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | |
1906 rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); | |
1907 if (rom->map[i].write_16) { | |
1908 if (!gen->tmss_write_16) { | |
1909 gen->tmss_write_16 = rom->map[i].write_16; | |
1910 gen->tmss_write_8 = rom->map[i].write_8; | |
1911 rom->map[i].write_16 = tmss_rom_write_16; | |
1912 rom->map[i].write_8 = tmss_rom_write_8; | |
1913 } else if (gen->tmss_write_16 == rom->map[i].write_16) { | |
1914 rom->map[i].write_16 = tmss_rom_write_16; | |
1915 rom->map[i].write_8 = tmss_rom_write_8; | |
1916 } else { | |
1917 warning("Chunk starting at %X has a write function, but we've already stored a different one for TMSS remap\n", rom->map[i].start); | |
1918 } | |
1919 } | |
1920 } else if ((rom->map[i].flags & (MMAP_READ | MMAP_WRITE)) == (MMAP_READ | MMAP_WRITE)) { | |
1921 //RAM or SRAM | |
1922 rom->map[i].flags |= MMAP_PTR_IDX; | |
1923 rom->map[i].ptr_index = next_ptr_index++; | |
1924 gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | |
1925 rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); | |
1926 if (!gen->tmss_write_offset || gen->tmss_write_offset == rom->map[i].start) { | |
1927 gen->tmss_write_offset = rom->map[i].start; | |
1928 rom->map[i].flags &= ~MMAP_WRITE; | |
1929 if (rom->map[i].flags & MMAP_ONLY_ODD) { | |
1930 rom->map[i].write_16 = tmss_odd_write_16; | |
1931 rom->map[i].write_8 = tmss_odd_write_8; | |
1932 } else if (rom->map[i].flags & MMAP_ONLY_EVEN) { | |
1933 rom->map[i].write_16 = tmss_even_write_16; | |
1934 rom->map[i].write_8 = tmss_even_write_8; | |
1935 } else { | |
1936 rom->map[i].write_16 = tmss_word_write_16; | |
1937 rom->map[i].write_8 = tmss_word_write_8; | |
1938 } | |
1939 } else { | |
1940 warning("Could not remap writes for chunk starting at %X for TMSS because write_offset is %X\n", rom->map[i].start, gen->tmss_write_offset); | |
1941 } | |
1942 } else if (rom->map[i].flags & MMAP_READ_CODE) { | |
1943 //NOR flash | |
1944 rom->map[i].flags |= MMAP_PTR_IDX; | |
1945 rom->map[i].ptr_index = next_ptr_index++; | |
1946 if (rom->map[i].ptr_index >= NUM_MEM_AREAS) { | |
1947 fatal_error("Too many memmap chunks with MMAP_PTR_IDX after TMSS remap\n"); | |
1948 } | |
1949 gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | |
1950 rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); | |
1951 if (!gen->tmss_write_16) { | |
1952 gen->tmss_write_16 = rom->map[i].write_16; | |
1953 gen->tmss_write_8 = rom->map[i].write_8; | |
1954 gen->tmss_read_16 = rom->map[i].read_16; | |
1955 gen->tmss_read_8 = rom->map[i].read_8; | |
1956 rom->map[i].write_16 = tmss_rom_write_16; | |
1957 rom->map[i].write_8 = tmss_rom_write_8; | |
1958 rom->map[i].read_16 = tmss_rom_read_16; | |
1959 rom->map[i].read_8 = tmss_rom_read_8; | |
1960 } else if (gen->tmss_write_16 == rom->map[i].write_16) { | |
1961 rom->map[i].write_16 = tmss_rom_write_16; | |
1962 rom->map[i].write_8 = tmss_rom_write_8; | |
1963 rom->map[i].read_16 = tmss_rom_read_16; | |
1964 rom->map[i].read_8 = tmss_rom_read_8; | |
1965 } else { | |
1966 warning("Chunk starting at %X has a write function, but we've already stored a different one for TMSS remap\n", rom->map[i].start); | |
1967 } | |
1968 } else { | |
1969 warning("Didn't remap chunk starting at %X for TMSS because it has flags %X\n", rom->map[i].start, rom->map[i].flags); | |
1970 } | |
1971 } | |
1972 } | |
1973 gen->tmss_buffer = buffer; | |
1690 } | 1974 } |
1691 | 1975 |
1692 m68k_options *opts = malloc(sizeof(m68k_options)); | 1976 m68k_options *opts = malloc(sizeof(m68k_options)); |
1693 init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K); | 1977 init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K); |
1694 if (!strcmp(tern_find_ptr_default(model, "tas", "broken"), "broken")) { | 1978 if (!strcmp(tern_find_ptr_default(model, "tas", "broken"), "broken")) { |