diff options
author | Michael Pavone <pavone@retrodev.com> | 2017-02-23 00:08:37 -0800 |
---|---|---|
committer | Michael Pavone <pavone@retrodev.com> | 2017-02-23 00:08:37 -0800 |
commit | 1a3574ab4863a11bc40b6c7f760e905affc3cf31 (patch) | |
tree | 6dae4acce58e2654f2464758145efe97b5fccb48 | |
parent | 7958037a5b03952b8ff467b0d3d90a32678221ee (diff) |
WIP support for XBAND mapper hardware
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | m68k_core.c | 12 | ||||
-rw-r--r-- | m68k_core.h | 1 | ||||
-rw-r--r-- | m68k_core_x86.c | 56 | ||||
-rw-r--r-- | romdb.c | 6 | ||||
-rw-r--r-- | romdb.h | 3 | ||||
-rw-r--r-- | xband.c | 311 | ||||
-rw-r--r-- | xband.h | 17 |
8 files changed, 389 insertions, 19 deletions
@@ -125,7 +125,7 @@ Z80OBJS=z80inst.o z80_to_x86.o AUDIOOBJS=ym2612.o psg.o wave.o CONFIGOBJS=config.o tern.o util.o -MAINOBJS=blastem.o system.o genesis.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o menu.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) +MAINOBJS=blastem.o system.o genesis.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o menu.o xband.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) ifeq ($(CPU),x86_64) CFLAGS+=-DX86_64 -m64 diff --git a/m68k_core.c b/m68k_core.c index 1ca7f2b..b7290d9 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -617,10 +617,10 @@ static void map_native_address(m68k_context * context, uint32_t address, code_pt m68k_options * opts = context->options; native_map_slot * native_code_map = opts->gen.native_code_map; uint32_t meta_off; - memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, MMAP_WRITE | MMAP_CODE, &meta_off); + memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, MMAP_CODE, &meta_off); if (mem_chunk) { - if ((mem_chunk->flags & (MMAP_WRITE | MMAP_CODE)) == (MMAP_WRITE | MMAP_CODE)) { - uint32_t masked = (address & mem_chunk->mask); + if (mem_chunk->flags & MMAP_CODE) { + uint32_t masked = (address - mem_chunk->start) & mem_chunk->mask; uint32_t final_off = masked + meta_off; uint32_t ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3); context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7); @@ -670,7 +670,7 @@ static void map_native_address(m68k_context * context, uint32_t address, code_pt static uint8_t get_native_inst_size(m68k_options * opts, uint32_t address) { uint32_t meta_off; - memmap_chunk const *chunk = find_map_chunk(address, &opts->gen, MMAP_WRITE | MMAP_CODE, &meta_off); + memmap_chunk const *chunk = find_map_chunk(address, &opts->gen, MMAP_CODE, &meta_off); if (chunk) { meta_off += (address - chunk->start) & chunk->mask; } @@ -882,8 +882,10 @@ void translate_m68k_stream(uint32_t address, m68k_context * context) do { encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen); if (!encoded) { - map_native_address(context, address, code->cur, 2, 1); + code_ptr start = code->cur; translate_out_of_bounds(opts, address); + code_ptr after = code->cur; + map_native_address(context, address, code->cur, 2, after-start); break; } code_ptr existing = get_native_address(opts, address); diff --git a/m68k_core.h b/m68k_core.h index 1b1199e..33daa70 100644 --- a/m68k_core.h +++ b/m68k_core.h @@ -86,6 +86,7 @@ m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context); uint32_t get_instruction_start(m68k_options *opts, uint32_t address); uint16_t m68k_get_ir(m68k_context *context); void m68k_print_regs(m68k_context * context); +void m68k_invalidate_code_range(m68k_context *context, uint32_t start, uint32_t end); #endif //M68K_CORE_H_ diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 3d55757..d575b1d 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -2309,6 +2309,7 @@ void m68k_out_of_bounds_execution(uint32_t address) void translate_out_of_bounds(m68k_options *opts, uint32_t address) { code_info *code = &opts->gen.code; + check_cycles_int(&opts->gen, address); mov_ir(code, address, opts->gen.scratch1, SZ_D); call_args(code, (code_ptr)m68k_out_of_bounds_execution, 1, opts->gen.scratch1); } @@ -2340,23 +2341,47 @@ m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context) code_ptr dst = get_native_address(context->options, inst_start); code_info orig = {dst, dst + 128, 0}; mov_ir(&orig, inst_start, options->gen.scratch2, SZ_D); - - if (!options->retrans_stub) { - options->retrans_stub = code->cur; - call(code, options->gen.save_context); - push_r(code, options->gen.context_reg); - call_args(code,(code_ptr)m68k_retranslate_inst, 2, options->gen.scratch2, options->gen.context_reg); - pop_r(code, options->gen.context_reg); - mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); - call(code, options->gen.load_context); - jmp_r(code, options->gen.scratch1); - } jmp(&orig, options->retrans_stub); inst_start = get_instruction_start(options, inst_start - 2); } return context; } +void m68k_invalidate_code_range(m68k_context *context, uint32_t start, uint32_t end) +{ + m68k_options *opts = context->options; + native_map_slot *native_code_map = opts->gen.native_code_map; + memmap_chunk const *mem_chunk = find_map_chunk(start, &opts->gen, 0, NULL); + if (mem_chunk) { + //calculate the lowest alias for this address + start = mem_chunk->start + ((start - mem_chunk->start) & mem_chunk->mask); + } + mem_chunk = find_map_chunk(end, &opts->gen, 0, NULL); + if (mem_chunk) { + //calculate the lowest alias for this address + end = mem_chunk->start + ((end - mem_chunk->start) & mem_chunk->mask); + } + uint32_t start_chunk = start / NATIVE_CHUNK_SIZE, end_chunk = end / NATIVE_CHUNK_SIZE; + for (uint32_t chunk = start_chunk; chunk <= end_chunk; chunk++) + { + if (native_code_map[chunk].base) { + uint32_t start_offset = chunk == start_chunk ? start % NATIVE_CHUNK_SIZE : 0; + uint32_t end_offset = chunk == end_chunk ? end % NATIVE_CHUNK_SIZE : NATIVE_CHUNK_SIZE; + for (uint32_t offset = start_offset; offset < end_offset; offset++) + { + if (native_code_map[chunk].offsets[offset] != INVALID_OFFSET && native_code_map[chunk].offsets[offset] != EXTENSION_WORD) { + code_info code; + code.cur = native_code_map[chunk].base + native_code_map[chunk].offsets[offset]; + code.last = code.cur + 32; + code.stack_off = 0; + mov_ir(&code, chunk * NATIVE_CHUNK_SIZE + offset, opts->gen.scratch2, SZ_D); + jmp(&code, opts->retrans_stub); + } + } + } + } +} + void insert_breakpoint(m68k_context * context, uint32_t address, m68k_debug_handler bp_handler) { static code_ptr bp_stub = NULL; @@ -2948,4 +2973,13 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu call(code, opts->native_addr_and_sync); cycles(&opts->gen, 18); jmp_r(code, opts->gen.scratch1); + + opts->retrans_stub = code->cur; + call(code, opts->gen.save_context); + push_r(code, opts->gen.context_reg); + call_args(code,(code_ptr)m68k_retranslate_inst, 2, opts->gen.scratch2, opts->gen.context_reg); + pop_r(code, opts->gen.context_reg); + mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); + call(code, opts->gen.load_context); + jmp_r(code, opts->gen.scratch1); } @@ -5,13 +5,12 @@ #include "util.h" #include "genesis.h" #include "menu.h" +#include "xband.h" #define DOM_TITLE_START 0x120 #define DOM_TITLE_END 0x150 #define TITLE_START DOM_TITLE_END #define TITLE_END (TITLE_START+48) -#define GAME_ID_OFF 0x183 -#define GAME_ID_LEN 8 #define ROM_END 0x1A4 #define RAM_ID 0x1B0 #define RAM_FLAGS 0x1B2 @@ -848,6 +847,9 @@ rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, void *l tern_node * entry = tern_find_ptr(rom_db, product_id); if (!entry) { puts("Not found in ROM DB, examining header\n"); + if (xband_detect(rom, rom_size)) { + return xband_configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, base_chunks); + } return configure_rom_heuristics(rom, rom_size, base_map, base_chunks); } rom_info info; @@ -57,6 +57,9 @@ struct rom_info { uint8_t regions; }; +#define GAME_ID_OFF 0x183 +#define GAME_ID_LEN 8 + tern_node *load_rom_db(); rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks); rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks); @@ -0,0 +1,311 @@ +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include "romdb.h" +#include "genesis.h" +#include "tern.h" +#include "xband.h" +#include "util.h" + +#define BIT_ROM_HI 4 + +uint8_t xband_detect(uint8_t *rom, uint32_t rom_size) +{ + //Internal ROM is 512KB, accept larger ones for overdumps and custom firmware + if (rom_size < (512*1024)) { + return 0; + } + + //ROM has no standard header, but does have a jump at $100 + if (rom[0x100] != 0x4E || rom[0x101] != 0xF9) { + return 0; + } + + //product ID is all NULL + for (int i = GAME_ID_OFF; i <= (GAME_ID_OFF + GAME_ID_LEN); i++) + { + if (rom[i]) { + return 0; + } + } + return 1; +} + +static xband *get_xband(genesis_context *gen) +{ + if (!gen->extra) { + gen->extra = gen->m68k->options->gen.memmap[0].buffer; + gen->m68k->mem_pointers[2] = (uint16_t *)gen->save_storage; + } + return gen->extra; +} + +static void update_control(genesis_context *gen, uint8_t value) +{ + xband *x = gen->extra; + if ((x->control ^ value) & BIT_ROM_HI) { + if (value & BIT_ROM_HI) { + gen->m68k->mem_pointers[0] = (uint16_t *)gen->save_storage; + gen->m68k->mem_pointers[1] = NULL; + gen->m68k->mem_pointers[2] = x->cart_space; + gen->m68k->mem_pointers[3] = x->cart_space - 0x100000; + } else { + gen->m68k->mem_pointers[0] = x->cart_space; + gen->m68k->mem_pointers[1] = x->cart_space; + gen->m68k->mem_pointers[2] = (uint16_t *)gen->save_storage; + gen->m68k->mem_pointers[3] = NULL; + } + m68k_invalidate_code_range(gen->m68k, 0, 0x3BC000); + } + x->control = value; +} + +static void *xband_write_b(uint32_t address, void *context, uint8_t value) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + xband *x = get_xband(gen); + if (address == 0x181) { + x->kill = value; + printf("Write to \"soft\" kill register %X\n", value); + } else if (address == 0x183) { + update_control(gen, value); + printf("Write to \"soft\" control register %X\n", value); + } else if ((x->control & BIT_ROM_HI && address < 0x200000) || (address >= 0x200000 && !(x->control & BIT_ROM_HI))) { + gen->save_storage[(address & 0xFFFF) ^ 1] = value; + m68k_handle_code_write(address, m68k); + //TODO: handle code at mirror addresses + } else { + printf("Unhandled write to cartridge area %X: %X\n", address, value); + } + return context; +} + +static void *xband_write_hi_b(uint32_t address, void *context, uint8_t value) +{ + return xband_write_b(address | 0x200000, context, value); +} + +static void *xband_write_w(uint32_t address, void *context, uint16_t value) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + xband *x = get_xband(gen); + if (address == 0x180 || address == 0x182) { + return xband_write_b(address | 1, context, value); + } else if ((x->control & BIT_ROM_HI && address < 0x200000) || (address >= 0x200000 && !(x->control & BIT_ROM_HI))) { + gen->save_storage[address & 0xFFFE] = value; + gen->save_storage[(address & 0xFFFE) | 1] = value >> 8; + m68k_handle_code_write(address, m68k); + //TODO: handle code at mirror addresses + return context; + } + printf("Unhandled write to %X: %X\n", address, value); + return context; +} + +static void *xband_write_hi_w(uint32_t address, void *context, uint16_t value) +{ + return xband_write_w(address | 0x200000, context, value); +} + +static uint16_t xband_read_w(uint32_t address, void *context) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + xband *x = get_xband(gen); + //TODO: actually do something intelligent here + return x->cart_space[address >> 1]; +} + +static uint16_t xband_read_hi_w(uint32_t address, void *context) +{ + return xband_read_w(address | 0x200000, context); +} + +static uint8_t xband_read_b(uint32_t address, void *context) +{ + uint16_t val = xband_read_w(address, context); + return address & 1 ? val : val >> 8; +} + +static uint8_t xband_read_hi_b(uint32_t address, void *context) +{ + return xband_read_b(address | 0x200000, context); +} + +static void *xband_reg_write_b(uint32_t address, void *context, uint8_t value) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + if (!(address & 1)) { + printf("Ignoring write to even address %X: %X\n", address, value); + return context; + } + xband *x = get_xband(gen); + if (address < 0x3BFE00) { + uint32_t offset = (address - 0x3BC001) / 2; + if (offset < XBAND_REGS) { + x->regs[offset] = value; + printf("Write to register %X: %X\n", address, value); + } else { + printf("Unhandled register write %X: %X\n", address, value); + } + } else { + if (address == 0x3BFE01) { + x->kill = value; + printf("Write to kill register %X\n", value); + } else if (address == 0x3BFE03) { + update_control(gen, value); + printf("Write to control register %X\n", value); + } else { + printf("Unhandled register write %X: %X\n", address, value); + } + } + return context; +} + +static void *xband_reg_write_w(uint32_t address, void *context, uint16_t value) +{ + return xband_reg_write_b(address | 1, context, value); +} + +static uint8_t xband_reg_read_b(uint32_t address, void *context) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + if (!(address & 1)) { + printf("Read from even address %X\n", address); + return gen->header.get_open_bus_value(&gen->header) >> 8; + } + xband *x = get_xband(gen); + if (address < 0x3BFE00) { + uint32_t offset = (address - 0x3BC001) / 2; + if (offset < XBAND_REGS) { + return x->regs[offset]; + } else { + printf("Unhandled register read from address %X\n", address); + return 0x5D; + } + } else { + if (address == 0x3BFE01) { + return x->kill; + } else if (address == 0x3BFE03) { + return x->control; + } else { + printf("Unhandled register read from address %X\n", address); + return 0x5D; + } + } +} + +static uint16_t xband_reg_read_w(uint32_t address, void *context) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + uint16_t value = xband_reg_read_b(address | 1, context); + value |= gen->header.get_open_bus_value(&gen->header) & 0xFF00; + return value; +} + +rom_info xband_configure_rom(tern_node *rom_db, void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks) +{ + rom_info info; + if (lock_on && lock_on_size) { + rom_info lock_on_info = configure_rom(rom_db, lock_on, lock_on_size, NULL, 0, base_map, base_chunks); + info.name = alloc_concat("XBAND - ", lock_on_info.name); + info.regions = lock_on_info.regions; + //TODO: Move this to a shared function in romdbc.h + free(lock_on_info.name); + if (lock_on_info.save_type != SAVE_NONE) { + free(lock_on_info.save_buffer); + if (lock_on_info.save_type == SAVE_I2C) { + free(lock_on_info.eeprom_map); + } + } + free(lock_on_info.map); + free(lock_on_info.port1_override); + free(lock_on_info.port2_override); + free(lock_on_info.ext_override); + free(lock_on_info.mouse_mode); + } else { + info.name = strdup("XBAND"); + info.regions = REGION_J|REGION_U|REGION_E; + } + info.save_size = 64*1024; + info.save_buffer = malloc(info.save_size); + info.save_mask = info.save_size-1; + info.save_type = RAM_FLAG_BOTH; + info.port1_override = info.port2_override = info.ext_override = info.mouse_mode = NULL; + info.eeprom_map = NULL; + info.num_eeprom = 0; + xband *x = calloc(sizeof(xband), 1); + rom_size = nearest_pow2(rom_size); + for (int i = 0; (i + rom_size) <= sizeof(x->cart_space) / 2; i += rom_size) + { + memcpy(x->cart_space + i/2, rom, rom_size); + } + if (lock_on && lock_on_size >= 0x200) { + memcpy(x->cart_space + 0x80, ((uint16_t *)lock_on) + 0x80, 0x100); + } + byteswap_rom(0x400000, x->cart_space); + + info.map_chunks = base_chunks + 5; + info.map = calloc(sizeof(memmap_chunk), info.map_chunks); + info.map[0].mask = 0xFFFFFF; + info.map[0].aux_mask = 0xFFFFFF; + info.map[0].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_AUX_BUFF; + info.map[0].start = 0; + info.map[0].end = 0x10000; + info.map[0].ptr_index = 0; + info.map[0].buffer = x->cart_space; + info.map[0].write_16 = xband_write_w; + info.map[0].write_8 = xband_write_b; + info.map[0].read_16 = xband_read_w; + info.map[0].read_8 = xband_read_b; + info.map[1].mask = 0xFFFFFF; + info.map[1].aux_mask = 0xFFFFFF; + info.map[1].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_AUX_BUFF; + info.map[1].start = 0x10000; + info.map[1].end = 0x200000; + info.map[1].ptr_index = 1; + info.map[1].buffer = x->cart_space; + info.map[1].write_16 = xband_write_w; + info.map[1].write_8 = xband_write_b; + info.map[1].read_16 = xband_read_w; + info.map[1].read_8 = xband_read_b; + info.map[2].mask = 0xFFFF; + info.map[2].aux_mask = 0xFFFF; + info.map[2].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL; + info.map[2].start = 0x200000; + info.map[2].end = 0x210000; + info.map[2].ptr_index = 2; + info.map[2].buffer = NULL; + info.map[2].write_16 = xband_write_hi_w; + info.map[2].write_8 = xband_write_hi_b; + info.map[2].read_16 = xband_read_hi_w; + info.map[2].read_8 = xband_read_hi_b; + info.map[3].mask = 0xFFFFFF; + info.map[3].aux_mask = 0xFFFFFF; + info.map[3].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL; + info.map[3].start = 0x210000; + info.map[3].end = 0x3BC000; + info.map[3].ptr_index = 3; + info.map[3].buffer = NULL; + info.map[3].write_16 = xband_write_w; + info.map[3].write_8 = xband_write_b; + info.map[3].read_16 = xband_read_w; + info.map[3].read_8 = xband_read_b; + info.map[4].mask = 0xFFFFFF; + info.map[4].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL; + info.map[4].start = 0x3BC000; + info.map[4].end = 0x3C0000; + info.map[4].ptr_index = 4; + info.map[4].write_16 = xband_reg_write_w; + info.map[4].write_8 = xband_reg_write_b; + info.map[4].read_16 = xband_reg_read_w; + info.map[4].read_8 = xband_reg_read_b; + memcpy(info.map + 5, base_map, base_chunks * sizeof(memmap_chunk)); + + return info; +} @@ -0,0 +1,17 @@ +#ifndef XBAND_H_ +#define XBAND_H_ +#include <stdint.h> + +#define XBAND_REGS 0xB6 + +typedef struct { + uint16_t cart_space[0x200000]; + uint8_t regs[XBAND_REGS]; + uint8_t kill; + uint8_t control; +} xband; + +uint8_t xband_detect(uint8_t *rom, uint32_t rom_size); +rom_info xband_configure_rom(tern_node *rom_db, void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks); + +#endif //XBAND_H_ |