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")) {