Mercurial > repos > blastem
diff sega_mapper.c @ 2052:3748a2a8a4b7
Support Sega mapper without 'SEGA SSF' in header or ROM DB entry and implement a subset of the extended Sega mapper implemented in the Mega Everdrive when 'SEGA SSF' is present
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 01 Jan 2022 18:54:46 -0800 |
parents | d60f2d7c02a5 |
children | b6fdedd3b070 |
line wrap: on
line diff
--- a/sega_mapper.c Fri Dec 31 13:03:21 2021 -0800 +++ b/sega_mapper.c Sat Jan 01 18:54:46 2022 -0800 @@ -1,4 +1,5 @@ #include "genesis.h" +#include "util.h" uint16_t read_sram_w(uint32_t address, m68k_context * context) { @@ -43,6 +44,14 @@ m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value) { genesis_context * gen = context->system; + if (gen->mapper_type == MAPPER_SEGA_MED_V2) { + if (gen->bank_regs[8] & 0x20) { + uint32_t bank = address >> 19; + address &= 0x7FFFF; + context->mem_pointers[gen->mapper_start_index + bank][address >> 1] = value; + } + return context; + } if ((gen->bank_regs[0] & 0x3) == 1) { address &= gen->save_ram_mask; switch(gen->save_type) @@ -87,14 +96,128 @@ return context; } +static void* write_med_ram_w(uint32_t address, void *vcontext, uint16_t value, uint16_t bank) +{ + m68k_context *context = vcontext; + genesis_context * gen = context->system; + if (gen->bank_regs[8] & 0x20) { + context->mem_pointers[gen->mapper_start_index + bank][address >> 1] = value; + address += bank * 0x80000; + m68k_invalidate_code_range(gen->m68k, address, address + 2); + } + return vcontext; +} + +void* write_med_ram0_w(uint32_t address, void *vcontext, uint16_t value) +{ + return write_med_ram_w(address, vcontext, value, 0); +} + +void* write_med_ram1_w(uint32_t address, void *vcontext, uint16_t value) +{ + return write_med_ram_w(address, vcontext, value, 1); +} + +void* write_med_ram2_w(uint32_t address, void *vcontext, uint16_t value) +{ + return write_med_ram_w(address, vcontext, value, 2); +} + +void* write_med_ram3_w(uint32_t address, void *vcontext, uint16_t value) +{ + return write_med_ram_w(address, vcontext, value, 3); +} + +void* write_med_ram4_w(uint32_t address, void *vcontext, uint16_t value) +{ + return write_med_ram_w(address, vcontext, value, 4); +} + +void* write_med_ram5_w(uint32_t address, void *vcontext, uint16_t value) +{ + return write_med_ram_w(address, vcontext, value, 5); +} + +void* write_med_ram6_w(uint32_t address, void *vcontext, uint16_t value) +{ + return write_med_ram_w(address, vcontext, value, 6); +} + +void* write_med_ram7_w(uint32_t address, void *vcontext, uint16_t value) +{ + return write_med_ram_w(address, vcontext, value, 7); +} + +static void* write_med_ram_b(uint32_t address, void *vcontext, uint8_t value, uint16_t bank) +{ + m68k_context *context = vcontext; + genesis_context * gen = context->system; + if (gen->bank_regs[8] & 0x20) { + ((uint8_t*)context->mem_pointers[gen->mapper_start_index + bank])[address ^ 1] = value; + address += bank * 0x80000; + m68k_invalidate_code_range(gen->m68k, address, address + 1); + } + return vcontext; +} + +void* write_med_ram0_b(uint32_t address, void *vcontext, uint8_t value) +{ + return write_med_ram_b(address, vcontext, value, 0); +} + +void* write_med_ram1_b(uint32_t address, void *vcontext, uint8_t value) +{ + return write_med_ram_b(address, vcontext, value, 1); +} + +void* write_med_ram2_b(uint32_t address, void *vcontext, uint8_t value) +{ + return write_med_ram_b(address, vcontext, value, 2); +} + +void* write_med_ram3_b(uint32_t address, void *vcontext, uint8_t value) +{ + return write_med_ram_b(address, vcontext, value, 3); +} + +void* write_med_ram4_b(uint32_t address, void *vcontext, uint8_t value) +{ + return write_med_ram_b(address, vcontext, value, 4); +} + +void* write_med_ram5_b(uint32_t address, void *vcontext, uint8_t value) +{ + return write_med_ram_b(address, vcontext, value, 5); +} + +void* write_med_ram6_b(uint32_t address, void *vcontext, uint8_t value) +{ + return write_med_ram_b(address, vcontext, value, 6); +} + +void* write_med_ram7_b(uint32_t address, void *vcontext, uint8_t value) +{ + return write_med_ram_b(address, vcontext, value, 7); +} + m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value) { genesis_context * gen = context->system; address &= 0xE; address >>= 1; - gen->bank_regs[address] = value; if (!address) { - if (value & 1) { + if (gen->mapper_type == MAPPER_SEGA_MED_V2) { + if (!value & 0x8000) { + //writes without protection bit set are ignored + return context; + } + gen->bank_regs[8] = value >> 8; + void *new_ptr = gen->cart + 0x40000*(value & 0x1F); + if (context->mem_pointers[gen->mapper_start_index] != new_ptr) { + m68k_invalidate_code_range(gen->m68k, 0, 0x80000); + context->mem_pointers[gen->mapper_start_index] = new_ptr; + } + } else if (value & 1) { //Used for games that only use the mapper for SRAM if (context->mem_pointers[gen->mapper_start_index]) { gen->mapper_temp = context->mem_pointers[gen->mapper_start_index]; @@ -116,19 +239,30 @@ context->mem_pointers[gen->mapper_start_index + i] = gen->cart + 0x40000*gen->bank_regs[i]; } } - } else if (gen->mapper_type == MAPPER_SEGA) { - void *new_ptr = gen->cart + 0x40000*value; + } else if (gen->mapper_type != MAPPER_SEGA_SRAM) { + uint32_t mask = ((gen->mapper_type == MAPPER_SEGA_MED_V2 ? (16 *1024 * 1024) : nearest_pow2(gen->header.info.rom_size)) >> 1) - 1; + void *new_ptr = gen->cart + ((0x40000*value) & mask); if (context->mem_pointers[gen->mapper_start_index + address] != new_ptr) { m68k_invalidate_code_range(gen->m68k, address * 0x80000, (address + 1) * 0x80000); context->mem_pointers[gen->mapper_start_index + address] = new_ptr; } } + gen->bank_regs[address] = value; return context; } m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value) { - if (address & 1) { + genesis_context * gen = context->system; + if (gen->mapper_type == MAPPER_SEGA_MED_V2) { + address &= 0xF; + if (!address) { + //not sure if this is correct, possible byte sized writes are always rejected to $A130F0 + write_bank_reg_w(address, context, value << 8 | value); + } else if (address > 2 && (address & 1)) { + write_bank_reg_w(address, context, value); + } + } else if (address & 1) { write_bank_reg_w(address, context, value); } return context; @@ -136,13 +270,23 @@ void sega_mapper_serialize(genesis_context *gen, serialize_buffer *buf) { - save_buffer8(buf, gen->bank_regs, sizeof(gen->bank_regs)); + save_buffer8(buf, gen->bank_regs, gen->mapper_type == MAPPER_SEGA_MED_V2 ? sizeof(gen->bank_regs) : sizeof(gen->bank_regs) - 1); } void sega_mapper_deserialize(deserialize_buffer *buf, genesis_context *gen) { - for (int i = 0; i < sizeof(gen->bank_regs); i++) - { - write_bank_reg_w(i * 2, gen->m68k, load_int8(buf)); + if (gen->mapper_type == MAPPER_SEGA_MED_V2) { + uint16_t reg0 = load_int8(buf); + for (int i = 1; i < sizeof(gen->bank_regs) - 1; i++) + { + write_bank_reg_w(i * 2, gen->m68k, load_int8(buf)); + } + reg0 |= load_int8(buf) << 8; + write_bank_reg_w(0, gen->m68k, reg0); + } else { + for (int i = 0; i < sizeof(gen->bank_regs) - 1; i++) + { + write_bank_reg_w(i * 2, gen->m68k, load_int8(buf)); + } } }