Mercurial > repos > blastem
diff genesis.c @ 2041:638eb2d25696 mame_interp
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 05 Aug 2021 09:29:33 -0700 |
parents | 0d5f88e53dca 3b8e29ef1145 |
children | 804954731e3f |
line wrap: on
line diff
--- a/genesis.c Sun May 10 00:16:00 2020 -0700 +++ b/genesis.c Thu Aug 05 09:29:33 2021 -0700 @@ -104,6 +104,16 @@ save_buffer8(buf, gen->zram, Z80_RAM_BYTES); end_section(buf); + if (gen->version_reg & 0xF) { + //only save TMSS info if it's present + //that will allow a state saved on a model lacking TMSS + //to be loaded on a model that has it + start_section(buf, SECTION_TMSS); + save_int8(buf, gen->tmss); + save_buffer16(buf, gen->tmss_lock, 2); + end_section(buf); + } + cart_serialize(&gen->header, buf); } } @@ -173,7 +183,16 @@ gen->z80_bank_reg = load_int16(buf) & 0x1FF; } +static void tmss_deserialize(deserialize_buffer *buf, void *vgen) +{ + genesis_context *gen = vgen; + gen->tmss = load_int8(buf); + load_buffer16(buf, gen->tmss_lock, 2); +} + static void adjust_int_cycle(m68k_context * context, vdp_context * v_context); +static void check_tmss_lock(genesis_context *gen); +static void toggle_tmss_rom(genesis_context *gen); void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen) { register_section_handler(buf, (section_handler){.fun = m68k_deserialize, .data = gen->m68k}, SECTION_68000); @@ -188,10 +207,26 @@ register_section_handler(buf, (section_handler){.fun = ram_deserialize, .data = gen}, SECTION_MAIN_RAM); register_section_handler(buf, (section_handler){.fun = zram_deserialize, .data = gen}, SECTION_SOUND_RAM); register_section_handler(buf, (section_handler){.fun = cart_deserialize, .data = gen}, SECTION_MAPPER); + register_section_handler(buf, (section_handler){.fun = tmss_deserialize, .data = gen}, SECTION_TMSS); + uint8_t tmss_old = gen->tmss; + gen->tmss = 0xFF; while (buf->cur_pos < buf->size) { load_section(buf); } + if (gen->version_reg & 0xF) { + if (gen->tmss == 0xFF) { + //state lacked a TMSS section, assume that the game ROM is mapped in + //and that the VDP is unlocked + gen->tmss_lock[0] = 0x5345; + gen->tmss_lock[1] = 0x4741; + gen->tmss = 1; + } + if (gen->tmss != tmss_old) { + toggle_tmss_rom(gen); + } + check_tmss_lock(gen); + } update_z80_bank_pointer(gen); adjust_int_cycle(gen->m68k, gen->vdp); free(buf->handlers); @@ -242,13 +277,14 @@ context->sync_cycle = context->current_cycle + gen->max_cycles; } context->int_cycle = CYCLE_NEVER; - if ((context->status & 0x7) < 6) { + uint8_t mask = context->status & 0x7; + if (mask < 6) { uint32_t next_vint = vdp_next_vint(v_context); if (next_vint != CYCLE_NEVER) { context->int_cycle = next_vint; context->int_num = 6; } - if ((context->status & 0x7) < 4) { + if (mask < 4) { uint32_t next_hint = vdp_next_hint(v_context); if (next_hint != CYCLE_NEVER) { next_hint = next_hint < context->current_cycle ? context->current_cycle : next_hint; @@ -258,6 +294,21 @@ } } + if (mask < 2 && (v_context->regs[REG_MODE_3] & BIT_EINT_EN)) { + uint32_t next_eint_port0 = io_next_interrupt(gen->io.ports, context->current_cycle); + uint32_t next_eint_port1 = io_next_interrupt(gen->io.ports + 1, context->current_cycle); + uint32_t next_eint_port2 = io_next_interrupt(gen->io.ports + 2, context->current_cycle); + uint32_t next_eint = next_eint_port0 < next_eint_port1 + ? (next_eint_port0 < next_eint_port2 ? next_eint_port0 : next_eint_port2) + : (next_eint_port1 < next_eint_port2 ? next_eint_port1 : next_eint_port2); + if (next_eint != CYCLE_NEVER) { + next_eint = next_eint < context->current_cycle ? context->current_cycle : next_eint; + if (next_eint < context->int_cycle) { + context->int_cycle = next_eint; + context->int_num = 2; + } + } + } } } if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) { @@ -274,7 +325,7 @@ } context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; - if (context->should_return) { + if (context->should_return || gen->header.enter_debugger) { context->target_cycle = context->current_cycle; } else if (context->target_cycle < context->current_cycle) { //Changes to SR can result in an interrupt cycle that's in the past @@ -389,6 +440,9 @@ sync_z80(z_context, mclks); sync_sound(gen, mclks); vdp_run_context(v_context, mclks); + io_run(gen->io.ports, mclks); + io_run(gen->io.ports + 1, mclks); + io_run(gen->io.ports + 2, mclks); if (mclks >= gen->reset_cycle) { gen->reset_requested = 1; context->should_return = 1; @@ -451,7 +505,11 @@ #ifndef NEW_CORE if (gen->header.enter_debugger) { gen->header.enter_debugger = 0; - debugger(context, address); + if (gen->header.debugger_type == DEBUGGER_NATIVE) { + debugger(context, address); + } else { + gdb_debug_enter(context, address); + } } #endif #ifdef NEW_CORE @@ -512,6 +570,10 @@ if (vdp_port & 0x2700E0) { fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); } + genesis_context * gen = context->system; + if (!gen->vdp_unlocked) { + fatal_error("machine freeze due to VDP write to %X without TMSS unlock\n", 0xC00000 | vdp_port); + } vdp_port &= 0x1F; //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); #ifdef REFRESH_EMULATION @@ -524,7 +586,6 @@ } #endif sync_components(context, 0); - genesis_context * gen = context->system; vdp_context *v_context = gen->vdp; uint32_t before_cycle = v_context->cycles; if (vdp_port < 0x10) { @@ -601,7 +662,7 @@ vdp_test_port_write(gen->vdp, value); } #ifdef REFRESH_EMULATION - last_sync_cycle -= 4; + last_sync_cycle -= 4 * MCLKS_PER_68K; //refresh may have happened while we were waiting on the VDP, //so advance refresh_counter but don't add any delays if (vdp_port >= 4 && vdp_port < 8 && v_context->cycles != before_cycle) { @@ -653,6 +714,10 @@ if (vdp_port & 0x2700E0) { fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); } + genesis_context *gen = context->system; + if (!gen->vdp_unlocked) { + fatal_error("machine freeze due to VDP read from %X without TMSS unlock\n", 0xC00000 | vdp_port); + } vdp_port &= 0x1F; uint16_t value; #ifdef REFRESH_EMULATION @@ -664,27 +729,15 @@ last_sync_cycle = context->current_cycle; } #endif - genesis_context *gen = context->system; + sync_components(context, 0); vdp_context * v_context = gen->vdp; + uint32_t before_cycle = v_context->cycles; if (vdp_port < 0x10) { if (vdp_port < 4) { - sync_components(context, 0); - uint32_t before_cycle = v_context->cycles; value = vdp_data_port_read(v_context); - if (v_context->cycles != before_cycle) { - //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); - context->current_cycle = v_context->cycles; - //Lock the Z80 out of the bus until the VDP access is complete - genesis_context *gen = context->system; - gen->bus_busy = 1; - sync_z80(gen->z80, v_context->cycles); - gen->bus_busy = 0; - } } else if(vdp_port < 8) { - vdp_run_context(v_context, context->current_cycle); value = vdp_control_port_read(v_context); } else { - vdp_run_context(v_context, context->current_cycle); value = vdp_hv_counter_read(v_context); //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); } @@ -693,8 +746,17 @@ } else { value = get_open_bus_value(&gen->header); } + if (v_context->cycles != before_cycle) { + //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); + context->current_cycle = v_context->cycles; + //Lock the Z80 out of the bus until the VDP access is complete + genesis_context *gen = context->system; + gen->bus_busy = 1; + sync_z80(gen->z80, v_context->cycles); + gen->bus_busy = 0; + } #ifdef REFRESH_EMULATION - last_sync_cycle -= 4; + last_sync_cycle -= 4 * MCLKS_PER_68K; //refresh may have happened while we were waiting on the VDP, //so advance refresh_counter but don't add any delays refresh_counter += (context->current_cycle - last_sync_cycle); @@ -755,6 +817,13 @@ static m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value) { genesis_context * gen = context->system; +#ifdef REFRESH_EMULATION + //do refresh check here so we can avoid adding a penalty for a refresh that happens during an IO area access + refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; + context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); + refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); + last_sync_cycle = context->current_cycle - 4*MCLKS_PER_68K; +#endif if (location < 0x10000) { //Access to Z80 memory incurs a one 68K cycle wait state context->current_cycle += MCLKS_PER_68K; @@ -808,7 +877,7 @@ io_control_write(gen->io.ports+2, value, context->current_cycle); break; case 0x7: - gen->io.ports[0].serial_out = value; + io_tx_write(gen->io.ports, value, context->current_cycle); break; case 0x8: case 0xB: @@ -816,19 +885,20 @@ //serial input port is not writeable break; case 0x9: + io_sctrl_write(gen->io.ports, value, context->current_cycle); gen->io.ports[0].serial_ctrl = value; break; case 0xA: - gen->io.ports[1].serial_out = value; + io_tx_write(gen->io.ports + 1, value, context->current_cycle); break; case 0xC: - gen->io.ports[1].serial_ctrl = value; + io_sctrl_write(gen->io.ports + 1, value, context->current_cycle); break; case 0xD: - gen->io.ports[2].serial_out = value; + io_tx_write(gen->io.ports + 2, value, context->current_cycle); break; case 0xF: - gen->io.ports[2].serial_ctrl = value; + io_sctrl_write(gen->io.ports + 2, value, context->current_cycle); break; } } else { @@ -879,6 +949,11 @@ } } } +#ifdef REFRESH_EMULATION + //no refresh delays during IO access + refresh_counter += context->current_cycle - last_sync_cycle; + refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); +#endif return context; } @@ -902,6 +977,13 @@ { uint8_t value; genesis_context *gen = context->system; +#ifdef REFRESH_EMULATION + //do refresh check here so we can avoid adding a penalty for a refresh that happens during an IO area access + refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; + context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); + refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); + last_sync_cycle = context->current_cycle - 4*MCLKS_PER_68K; +#endif if (location < 0x10000) { //Access to Z80 memory incurs a one 68K cycle wait state context->current_cycle += MCLKS_PER_68K; @@ -952,28 +1034,28 @@ value = gen->io.ports[0].serial_out; break; case 0x8: - value = gen->io.ports[0].serial_in; + value = io_rx_read(gen->io.ports, context->current_cycle); break; case 0x9: - value = gen->io.ports[0].serial_ctrl; + value = io_sctrl_read(gen->io.ports, context->current_cycle); break; case 0xA: value = gen->io.ports[1].serial_out; break; case 0xB: - value = gen->io.ports[1].serial_in; + value = io_rx_read(gen->io.ports + 1, context->current_cycle); break; case 0xC: - value = gen->io.ports[1].serial_ctrl; + value = io_sctrl_read(gen->io.ports, context->current_cycle); break; case 0xD: value = gen->io.ports[2].serial_out; break; case 0xE: - value = gen->io.ports[2].serial_in; + value = io_rx_read(gen->io.ports + 1, context->current_cycle); break; case 0xF: - value = gen->io.ports[2].serial_ctrl; + value = io_sctrl_read(gen->io.ports, context->current_cycle); break; default: value = get_open_bus_value(&gen->header) >> 8; @@ -997,6 +1079,11 @@ } } } +#ifdef REFRESH_EMULATION + //no refresh delays during IO access + refresh_counter += context->current_cycle - last_sync_cycle; + refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); +#endif return value; } @@ -1109,7 +1196,7 @@ { m68k_context *context = vcontext; genesis_context *gen = context->system; - if ((location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { + if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { //Only called if the cart/exp doesn't have a more specific handler for this region return get_open_bus_value(&gen->header); } else if (location == 0xA14000 || location == 0xA14002) { @@ -1142,6 +1229,23 @@ } } +static void check_tmss_lock(genesis_context *gen) +{ + gen->vdp_unlocked = gen->tmss_lock[0] == 0x5345 && gen->tmss_lock[1] == 0x4741; +} + +static void toggle_tmss_rom(genesis_context *gen) +{ + m68k_context *context = gen->m68k; + for (int i = 0; i < NUM_MEM_AREAS; i++) + { + uint16_t *tmp = context->mem_pointers[i]; + context->mem_pointers[i] = gen->tmss_pointers[i]; + gen->tmss_pointers[i] = tmp; + } + m68k_invalidate_code_range(context, 0, 0x400000); +} + static void *unused_write(uint32_t location, void *vcontext, uint16_t value) { m68k_context *context = vcontext; @@ -1149,9 +1253,16 @@ uint8_t has_tmss = gen->version_reg & 0xF; if (has_tmss && (location == 0xA14000 || location == 0xA14002)) { gen->tmss_lock[location >> 1 & 1] = value; + check_tmss_lock(gen); } else if (has_tmss && location == 0xA14100) { - //TODO: implement TMSS control register - } else if (location < 0xA12000 || location >= 0xA13100 || (location >= 0xA12100 && location < 0xA13000)) { + value &= 1; + if (gen->tmss != value) { + gen->tmss = value; + toggle_tmss_rom(gen); + } + } else if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { + //these writes are ignored when no relevant hardware is present + } else { fatal_error("Machine freeze due to unmapped write to %X\n", location); } return vcontext; @@ -1171,9 +1282,18 @@ gen->tmss_lock[offset] &= 0xFF; gen->tmss_lock[offset] |= value << 8; } + check_tmss_lock(gen); } else if (has_tmss && (location == 0xA14100 || location == 0xA14101)) { - //TODO: implement TMSS control register - } else if (location < 0xA12000 || location >= 0xA13100 || (location >= 0xA12100 && location < 0xA13000)) { + if (location & 1) { + value &= 1; + if (gen->tmss != value) { + gen->tmss = value; + toggle_tmss_rom(gen); + } + } + } else if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { + //these writes are ignored when no relevant hardware is present + } else { fatal_error("Machine freeze due to unmapped byte write to %X\n", location); } return vcontext; @@ -1528,6 +1648,136 @@ gen->header.vgm_logging = 0; } +static void *tmss_rom_write_16(uint32_t address, void *context, uint16_t value) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + if (gen->tmss) { + return gen->tmss_write_16(address, context, value); + } + + return context; +} + +static void *tmss_rom_write_8(uint32_t address, void *context, uint8_t value) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + if (gen->tmss) { + return gen->tmss_write_8(address, context, value); + } + + return context; +} + +static uint16_t tmss_rom_read_16(uint32_t address, void *context) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + if (gen->tmss) { + return gen->tmss_read_16(address, context); + } + return ((uint16_t *)gen->tmss_buffer)[address >> 1]; +} + +static uint8_t tmss_rom_read_8(uint32_t address, void *context) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + if (gen->tmss) { + return gen->tmss_read_8(address, context); + } +#ifdef BLASTEM_BIG_ENDIAN + return gen->tmss_buffer[address]; +#else + return gen->tmss_buffer[address ^ 1]; +#endif +} + +static void *tmss_word_write_16(uint32_t address, void *context, uint16_t value) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + if (gen->tmss) { + address += gen->tmss_write_offset; + uint16_t *dest = get_native_pointer(address, (void **)m68k->mem_pointers, &m68k->options->gen); + *dest = value; + m68k_handle_code_write(address, m68k); + } + + return context; +} + +static void *tmss_word_write_8(uint32_t address, void *context, uint8_t value) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + if (gen->tmss) { + address += gen->tmss_write_offset; + uint8_t *dest = get_native_pointer(address & ~1, (void **)m68k->mem_pointers, &m68k->options->gen); +#ifdef BLASTEM_BIG_ENDIAN + dest[address & 1] = value; +#else + dest[address & 1 ^ 1] = value; +#endif + m68k_handle_code_write(address & ~1, m68k); + } + + return context; +} + +static void *tmss_odd_write_16(uint32_t address, void *context, uint16_t value) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + if (gen->tmss) { + memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); + address >>= 1; + uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; + base[address] = value; + } + return context; +} + +static void *tmss_odd_write_8(uint32_t address, void *context, uint8_t value) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + if (gen->tmss && (address & 1)) { + memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); + address >>= 1; + uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; + base[address] = value; + } + return context; +} + +static void *tmss_even_write_16(uint32_t address, void *context, uint16_t value) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + if (gen->tmss) { + memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); + address >>= 1; + uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; + base[address] = value >> 8; + } + return context; +} + +static void *tmss_even_write_8(uint32_t address, void *context, uint8_t value) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + if (gen->tmss && !(address & 1)) { + memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); + address >>= 1; + uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; + base[address] = value; + } + return context; +} + genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region) { static memmap_chunk z80_map[] = { @@ -1569,6 +1819,8 @@ uint8_t tmss = !strcmp(tern_find_ptr_default(model, "tmss", "off"), "on"); if (tmss) { gen->version_reg |= 1; + } else { + gen->vdp_unlocked = 1; } uint8_t max_vsram = !strcmp(tern_find_ptr_default(model, "vsram", "40"), "64"); @@ -1664,13 +1916,145 @@ gen->save_storage = NULL; } + gen->mapper_start_index = rom->mapper_start_index; + //This must happen before we generate memory access functions in init_m68k_opts + uint8_t next_ptr_index = 0; + uint32_t tmss_min_alloc = 16 * 1024; for (int i = 0; i < rom->map_chunks; i++) { if (rom->map[i].start == 0xE00000) { rom->map[i].buffer = gen->work_ram; - break; + if (!tmss) { + break; + } + } + if (rom->map[i].flags & MMAP_PTR_IDX && rom->map[i].ptr_index >= next_ptr_index) { + next_ptr_index = rom->map[i].ptr_index + 1; + } + if (rom->map[i].start < 0x400000 && rom->map[i].read_16 != unused_read) { + uint32_t highest_offset = (rom->map[i].end & rom->map[i].mask) + 1; + if (highest_offset > tmss_min_alloc) { + tmss_min_alloc = highest_offset; + } + } + } + if (tmss) { + char *tmss_path = tern_find_path_default(config, "system\0tmss_path\0", (tern_val){.ptrval = "tmss.md"}, TVAL_PTR).ptrval; + uint8_t *buffer = malloc(tmss_min_alloc); + uint32_t tmss_size; + if (is_absolute_path(tmss_path)) { + FILE *f = fopen(tmss_path, "rb"); + if (!f) { + fatal_error("Configured to use a model with TMSS, but failed to load the TMSS ROM from %s\n", tmss_path); + } + tmss_size = fread(buffer, 1, tmss_min_alloc, f); + fclose(f); + } else { + char *tmp = read_bundled_file(tmss_path, &tmss_size); + if (!tmp) { + fatal_error("Configured to use a model with TMSS, but failed to load the TMSS ROM from %s\n", tmss_path); + } + memcpy(buffer, tmp, tmss_size); + free(tmp); + } + for (uint32_t padded = nearest_pow2(tmss_size); tmss_size < padded; tmss_size++) + { + buffer[tmss_size] = 0xFF; + } +#ifndef BLASTEM_BIG_ENDIAN + byteswap_rom(tmss_size, (uint16_t *)buffer); +#endif + //mirror TMSS ROM until we fill up to tmss_min_alloc + for (uint32_t dst = tmss_size; dst < tmss_min_alloc; dst += tmss_size) + { + memcpy(buffer + dst, buffer, dst + tmss_size > tmss_min_alloc ? tmss_min_alloc - dst : tmss_size); } + //modify mappings for ROM space to point to the TMSS ROM and fixup flags to allow switching back and forth + //WARNING: This code makes some pretty big assumptions about the kinds of map chunks it will encounter + for (int i = 0; i < rom->map_chunks; i++) + { + if (rom->map[i].start < 0x400000 && rom->map[i].read_16 != unused_read) { + if (rom->map[i].flags == MMAP_READ) { + //Normal ROM + rom->map[i].flags |= MMAP_PTR_IDX | MMAP_CODE; + rom->map[i].ptr_index = next_ptr_index++; + if (rom->map[i].ptr_index >= NUM_MEM_AREAS) { + fatal_error("Too many memmap chunks with MMAP_PTR_IDX after TMSS remap\n"); + } + gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; + rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); + } else if (rom->map[i].flags & MMAP_PTR_IDX) { + //Sega mapper page or multi-game mapper + gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; + rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); + if (rom->map[i].write_16) { + if (!gen->tmss_write_16) { + gen->tmss_write_16 = rom->map[i].write_16; + gen->tmss_write_8 = rom->map[i].write_8; + rom->map[i].write_16 = tmss_rom_write_16; + rom->map[i].write_8 = tmss_rom_write_8; + } else if (gen->tmss_write_16 == rom->map[i].write_16) { + rom->map[i].write_16 = tmss_rom_write_16; + rom->map[i].write_8 = tmss_rom_write_8; + } else { + 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); + } + } + } else if ((rom->map[i].flags & (MMAP_READ | MMAP_WRITE)) == (MMAP_READ | MMAP_WRITE)) { + //RAM or SRAM + rom->map[i].flags |= MMAP_PTR_IDX; + rom->map[i].ptr_index = next_ptr_index++; + gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; + rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); + if (!gen->tmss_write_offset || gen->tmss_write_offset == rom->map[i].start) { + gen->tmss_write_offset = rom->map[i].start; + rom->map[i].flags &= ~MMAP_WRITE; + if (rom->map[i].flags & MMAP_ONLY_ODD) { + rom->map[i].write_16 = tmss_odd_write_16; + rom->map[i].write_8 = tmss_odd_write_8; + } else if (rom->map[i].flags & MMAP_ONLY_EVEN) { + rom->map[i].write_16 = tmss_even_write_16; + rom->map[i].write_8 = tmss_even_write_8; + } else { + rom->map[i].write_16 = tmss_word_write_16; + rom->map[i].write_8 = tmss_word_write_8; + } + } else { + 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); + } + } else if (rom->map[i].flags & MMAP_READ_CODE) { + //NOR flash + rom->map[i].flags |= MMAP_PTR_IDX; + rom->map[i].ptr_index = next_ptr_index++; + if (rom->map[i].ptr_index >= NUM_MEM_AREAS) { + fatal_error("Too many memmap chunks with MMAP_PTR_IDX after TMSS remap\n"); + } + gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; + rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); + if (!gen->tmss_write_16) { + gen->tmss_write_16 = rom->map[i].write_16; + gen->tmss_write_8 = rom->map[i].write_8; + gen->tmss_read_16 = rom->map[i].read_16; + gen->tmss_read_8 = rom->map[i].read_8; + rom->map[i].write_16 = tmss_rom_write_16; + rom->map[i].write_8 = tmss_rom_write_8; + rom->map[i].read_16 = tmss_rom_read_16; + rom->map[i].read_8 = tmss_rom_read_8; + } else if (gen->tmss_write_16 == rom->map[i].write_16) { + rom->map[i].write_16 = tmss_rom_write_16; + rom->map[i].write_8 = tmss_rom_write_8; + rom->map[i].read_16 = tmss_rom_read_16; + rom->map[i].read_8 = tmss_rom_read_8; + } else { + 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); + } + } else { + warning("Didn't remap chunk starting at %X for TMSS because it has flags %X\n", rom->map[i].start, rom->map[i].flags); + } + } + } + gen->tmss_buffer = buffer; } m68k_options *opts = malloc(sizeof(m68k_options));