# HG changeset patch # User Michael Pavone # Date 1686846971 25200 # Node ID 2eda5f81f91e157d276d7017a77d3a8a015eb9a7 # Parent 8016dbb0fcde9386d5e9b2f3205ecbf75a2b1ac2 More fully baked ROM db support for SMS diff -r 8016dbb0fcde -r 2eda5f81f91e romdb.c --- a/romdb.c Tue May 09 09:03:37 2023 -0700 +++ b/romdb.c Thu Jun 15 09:36:11 2023 -0700 @@ -703,9 +703,8 @@ state->info->num_eeprom++; } -void map_iter_fun(char *key, tern_val val, uint8_t valtype, void *data) +char *map_node_common(char *key, tern_val val, uint8_t valtype, map_iter_state *state) { - map_iter_state *state = data; if (valtype != TVAL_NODE) { fatal_error("ROM DB map entry %d with address %s is not a node\n", state->index, key); } @@ -720,6 +719,7 @@ memmap_chunk *map = state->info->map + state->index; map->start = start; map->end = end + 1; + if (!strcmp(dtype, "ROM")) { uint32_t expanded_size = nearest_pow2(state->rom_size); if (offset >= expanded_size) { @@ -732,13 +732,100 @@ } else { map->flags = MMAP_READ | MMAP_WRITE | MMAP_CODE; } - } else if (!strcmp(dtype, "LOCK-ON")) { + return NULL; + } + if (!strcmp(dtype, "EEPROM")) { + process_eeprom_def(key, state); + add_eeprom_map(node, start, end, state); + + map->write_16 = write_eeprom_i2c_w; + map->write_8 = write_eeprom_i2c_b; + map->read_16 = read_eeprom_i2c_w; + map->read_8 = read_eeprom_i2c_b; + map->mask = 0xFFFFFF; + return NULL; + } + if (!strcmp(dtype, "SRAM")) { + process_sram_def(key, state); + map->buffer = state->info->save_buffer + offset; + map->flags = MMAP_READ | MMAP_WRITE; + uint32_t save_size_mask = state->info->save_size; + if (state->info->save_type == RAM_FLAG_ODD) { + map->flags |= MMAP_ONLY_ODD; + save_size_mask *= 2; + } else if(state->info->save_type == RAM_FLAG_EVEN) { + map->flags |= MMAP_ONLY_EVEN; + save_size_mask *= 2; + } else { + map->flags |= MMAP_CODE; + } + map->mask = calc_mask(save_size_mask, start, end); + return NULL; + } + if (!strcmp(dtype, "RAM")) { + uint32_t size = strtol(tern_find_ptr_default(node, "size", "0"), NULL, 16); + if (!size || size > map->end - map->start) { + size = map->end - map->start; + } + map->buffer = calloc(size, 1); + map->flags = MMAP_READ | MMAP_WRITE; + char *bus = tern_find_ptr_default(node, "bus", "both"); + if (!strcmp(bus, "odd")) { + map->flags |= MMAP_ONLY_ODD; + size *= 2; + } else if (!strcmp(bus, "even")) { + map->flags |= MMAP_ONLY_EVEN; + size *= 2; + } else { + map->flags |= MMAP_CODE; + } + map->mask = calc_mask(size, start, end); + return NULL; + } + if (!strcmp(dtype, "NOR")) { + process_nor_def(key, state); + + map->write_16 = nor_flash_write_w; + map->write_8 = nor_flash_write_b; + map->read_16 = nor_flash_read_w; + map->read_8 = nor_flash_read_b; + if (state->info->save_bus == RAM_FLAG_BOTH) { + map->flags |= MMAP_READ_CODE | MMAP_CODE; + map->buffer = state->info->save_buffer; + } + map->mask = 0xFFFFFF; + return NULL; + } + if (!strcmp(dtype, "fixed")) { + uint16_t *value = malloc(2); + map->buffer = value; + map->mask = 0; + map->flags = MMAP_READ; + *value = strtol(tern_find_ptr_default(node, "value", "0"), NULL, 16); + return NULL; + } + return dtype; +} + +void map_iter_fun(char *key, tern_val val, uint8_t valtype, void *data) +{ + map_iter_state *state = data; + char *dtype = map_node_common(key, val, valtype, state); + if (!dtype) { + //entry was handled by common function + state->index++; + return; + } + tern_node *node = val.ptrval; + memmap_chunk *map = state->info->map + state->index; + uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 16); + if (!strcmp(dtype, "LOCK-ON")) { rom_info lock_info; if (state->lock_on) { lock_info = configure_rom(state->rom_db, state->lock_on, state->lock_on_size, NULL, 0, NULL, 0); - } else if (state->rom_size > start) { + } else if (state->rom_size > map->start) { //This is a bit of a hack to deal with pre-combined S3&K/S2&K ROMs and S&K ROM hacks - lock_info = configure_rom(state->rom_db, state->rom + start, state->rom_size - start, NULL, 0, NULL, 0); + lock_info = configure_rom(state->rom_db, state->rom + map->start, state->rom_size - map->start, NULL, 0, NULL, 0); } else { //skip this entry if there is no lock on cartridge attached return; @@ -793,60 +880,6 @@ } free_rom_info(&lock_info); return; - } else if (!strcmp(dtype, "EEPROM")) { - process_eeprom_def(key, state); - add_eeprom_map(node, start, end, state); - - map->write_16 = write_eeprom_i2c_w; - map->write_8 = write_eeprom_i2c_b; - map->read_16 = read_eeprom_i2c_w; - map->read_8 = read_eeprom_i2c_b; - map->mask = 0xFFFFFF; - } else if (!strcmp(dtype, "SRAM")) { - process_sram_def(key, state); - map->buffer = state->info->save_buffer + offset; - map->flags = MMAP_READ | MMAP_WRITE; - uint32_t save_size_mask = state->info->save_size; - if (state->info->save_type == RAM_FLAG_ODD) { - map->flags |= MMAP_ONLY_ODD; - save_size_mask *= 2; - } else if(state->info->save_type == RAM_FLAG_EVEN) { - map->flags |= MMAP_ONLY_EVEN; - save_size_mask *= 2; - } else { - map->flags |= MMAP_CODE; - } - map->mask = calc_mask(save_size_mask, start, end); - } else if (!strcmp(dtype, "RAM")) { - uint32_t size = strtol(tern_find_ptr_default(node, "size", "0"), NULL, 16); - if (!size || size > map->end - map->start) { - size = map->end - map->start; - } - map->buffer = calloc(size, 1); - map->flags = MMAP_READ | MMAP_WRITE; - char *bus = tern_find_ptr_default(node, "bus", "both"); - if (!strcmp(bus, "odd")) { - map->flags |= MMAP_ONLY_ODD; - size *= 2; - } else if (!strcmp(bus, "even")) { - map->flags |= MMAP_ONLY_EVEN; - size *= 2; - } else { - map->flags |= MMAP_CODE; - } - map->mask = calc_mask(size, start, end); - } else if (!strcmp(dtype, "NOR")) { - process_nor_def(key, state); - - map->write_16 = nor_flash_write_w; - map->write_8 = nor_flash_write_b; - map->read_16 = nor_flash_read_w; - map->read_8 = nor_flash_read_b; - if (state->info->save_bus == RAM_FLAG_BOTH) { - map->flags |= MMAP_READ_CODE | MMAP_CODE; - map->buffer = state->info->save_buffer; - } - map->mask = 0xFFFFFF; } else if (!strcmp(dtype, "Sega mapper")) { state->info->mapper_type = MAPPER_SEGA; state->info->mapper_start_index = state->ptr_index++; @@ -854,7 +887,7 @@ char *save_device = tern_find_path(node, "save\0device\0", TVAL_PTR).ptrval; if (save_device && !strcmp(save_device, "EEPROM")) { process_eeprom_def(key, state); - add_eeprom_map(node, start & map->mask, end & map->mask, state); + add_eeprom_map(node, map->start & map->mask, (map->end - 1) & map->mask, state); } else if (save_device && !strcmp(save_device, "SRAM")) { process_sram_def(key, state); } else if(has_ram_header(state->rom, state->rom_size)) { @@ -868,11 +901,9 @@ state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks); memset(state->info->map + state->info->map_chunks - 1, 0, sizeof(memmap_chunk) * 1); map = state->info->map + state->index; - map->start = start; - map->end = end; offset &= nearest_pow2(state->rom_size) - 1; map->buffer = state->rom + offset; - map->mask = calc_mask(state->rom_size - offset, start, end); + map->mask = calc_mask(state->rom_size - offset, map->start, map->end - 1); map->ptr_index = state->info->mapper_start_index; map->flags = MMAP_READ | MMAP_PTR_IDX | MMAP_CODE | MMAP_FUNC_NULL; if (save_device && !strcmp(save_device, "EEPROM")) { @@ -893,6 +924,7 @@ state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks); memset(state->info->map + state->info->map_chunks - 7, 0, sizeof(memmap_chunk) * 7); map = state->info->map + state->index; + uint32_t start = map->start; for (int i = 0; i < 7; i++, state->index++, map++) { map->start = start + i * 0x80000; @@ -931,12 +963,6 @@ map->write_16 = menu_write_w; map->read_16 = menu_read_w; #endif - } else if (!strcmp(dtype, "fixed")) { - uint16_t *value = malloc(2); - map->buffer = value; - map->mask = 0; - map->flags = MMAP_READ; - *value = strtol(tern_find_ptr_default(node, "value", "0"), NULL, 16); } else if (!strcmp(dtype, "multi-game")) { state->info->mapper_type = MAPPER_MULTI_GAME; state->info->mapper_start_index = state->ptr_index++; @@ -950,7 +976,7 @@ memset(state->info->map + state->info->map_chunks - 1, 0, sizeof(memmap_chunk) * 1); map = state->info->map + state->index; map->buffer = state->rom; - map->mask = calc_mask(state->rom_size, start, end); + map->mask = calc_mask(state->rom_size, map->start, map->end - 1); map->flags = MMAP_READ | MMAP_PTR_IDX | MMAP_CODE; map->ptr_index = state->info->mapper_start_index; map++; @@ -988,7 +1014,7 @@ fatal_error("offset of %X is invalid for ROM size of %X in map entry %d with addess %s\n", offset, state->rom_size, state->index, key); } map->buffer = state->rom + offset; - map->mask = calc_mask(nearest_pow2(state->rom_size) - offset, start, end); + map->mask = calc_mask(nearest_pow2(state->rom_size) - offset, map->start, map->end - 1); map->write_8 = sft_wukong_write_b; map->write_16 = sft_wukong_write_w; if (!strcmp(dtype, "sft-wukong-remap")) { @@ -1003,6 +1029,31 @@ state->index++; } +void handle_io_overrides(tern_node *entry, rom_info *info) +{ + tern_node *device_overrides = tern_find_node(entry, "device_overrides"); + if (device_overrides) { + info->port1_override = tern_find_ptr(device_overrides, "1"); + info->port2_override = tern_find_ptr(device_overrides, "2"); + info->ext_override = tern_find_ptr(device_overrides, "ext"); + if ( + info->save_type == SAVE_NONE + && ( + (info->port1_override && startswith(info->port1_override, "heartbeat_trainer.")) + || (info->port2_override && startswith(info->port2_override, "heartbeat_trainer.")) + || (info->ext_override && startswith(info->ext_override, "heartbeat_trainer.")) + ) + ) { + info->save_type = SAVE_HBPT; + info->save_size = atoi(tern_find_path_default(entry, "HeartbeatTrainer\0size\0", (tern_val){.ptrval="512"}, TVAL_PTR).ptrval); + info->save_buffer = calloc(info->save_size + 5 + 8, 1); + memset(info->save_buffer, 0xFF, info->save_size); + } + } else { + info->port1_override = info->port2_override = info->ext_override = NULL; + } +} + 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) { uint8_t product_id[GAME_ID_LEN+1]; @@ -1110,27 +1161,7 @@ add_memmap_header(&info, rom, rom_size, base_map, base_chunks); } - tern_node *device_overrides = tern_find_node(entry, "device_overrides"); - if (device_overrides) { - info.port1_override = tern_find_ptr(device_overrides, "1"); - info.port2_override = tern_find_ptr(device_overrides, "2"); - info.ext_override = tern_find_ptr(device_overrides, "ext"); - if ( - info.save_type == SAVE_NONE - && ( - (info.port1_override && startswith(info.port1_override, "heartbeat_trainer.")) - || (info.port2_override && startswith(info.port2_override, "heartbeat_trainer.")) - || (info.ext_override && startswith(info.ext_override, "heartbeat_trainer.")) - ) - ) { - info.save_type = SAVE_HBPT; - info.save_size = atoi(tern_find_path_default(entry, "HeartbeatTrainer\0size\0", (tern_val){.ptrval="512"}, TVAL_PTR).ptrval); - info.save_buffer = calloc(info.save_size + 5 + 8, 1); - memset(info.save_buffer, 0xFF, info.save_size); - } - } else { - info.port1_override = info.port2_override = info.ext_override = NULL; - } + handle_io_overrides(entry, &info); info.mouse_mode = tern_find_ptr(entry, "mouse_mode"); info.wants_cd = !strcmp(tern_find_ptr_default(entry, "wants_cd", "no"), "yes"); @@ -1138,6 +1169,65 @@ } void *sms_sega_mapper_write(uint32_t location, void *vcontext, uint8_t value); +void *sms_cart_ram_write(uint32_t location, void *vcontext, uint8_t value); +void map_iter_fun_sms(char *key, tern_val val, uint8_t valtype, void *data) +{ + map_iter_state *state = data; + char *dtype = map_node_common(key, val, valtype, state); + if (!dtype) { + //entry was handled by common function + state->index++; + return; + } + tern_node *node = val.ptrval; + memmap_chunk *map = state->info->map + state->index; + uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 16); + if (!strcmp(dtype, "Sega mapper")) { + state->info->mapper_type = MAPPER_SMS_SEGA; + state->info->mapper_start_index = state->ptr_index++; + char *save_device = tern_find_path(node, "save\0device\0", TVAL_PTR).ptrval; + if (save_device && !strcmp(save_device, "EEPROM")) { + process_eeprom_def(key, state); + add_eeprom_map(node, map->start & map->mask, (map->end - 1) & map->mask, state); + } else if (save_device && !strcmp(save_device, "SRAM")) { + process_sram_def(key, state); + } + state->info->map_chunks += 4; + state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks); + map = state->info->map + state->index; + map[0].start = 0; + map[0].end = 0x400; + map[0].mask = 0xFFFF; + map[0].flags = MMAP_READ; + map[0].buffer = state->info->rom; + map[1].start = 0x400; + map[1].end = 0x4000; + map[1].mask = 0x3FFF; + map[1].ptr_index = 0; + map[1].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE; + map[2].start = 0x4000; + map[2].end = 0x8000; + map[2].mask = 0x3FFF; + map[2].ptr_index = 1; + map[2].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE; + map[3].start = 0x8000; + map[3].end = 0xC000; + map[3].mask = 0x3FFF; + map[3].ptr_index = 2; + if (state->info->save_type == RAM_FLAG_ODD || state->info->save_type == RAM_FLAG_EVEN) { + map[3].write_8 = sms_cart_ram_write; + } + map[3].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE; + map[4].start = 0xFFFC; + map[4].end = 0x10000; + map[4].mask = 3; + map[4].flags = MMAP_READ; + map[4].write_8 = sms_sega_mapper_write; + } else { + fatal_error("Invalid device type %s for ROM DB map entry %d with address %s\n", dtype, state->index, key); + } +} + void sms_memmap_heuristics(rom_info *info, memmap_chunk const *base_map, uint32_t num_base_chunks) { uint32_t num_chunks = num_base_chunks + (info->rom_size > 0xC000 ? 5 : 1); @@ -1155,7 +1245,7 @@ chunks[0].buffer = info->rom; chunks[1].start = 0x400; chunks[1].end = 0x4000; - chunks[1].mask = 0xFFFF; + chunks[1].mask = 0x3FFF; chunks[1].ptr_index = 0; chunks[1].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE; chunks[2].start = 0x4000; @@ -1168,14 +1258,18 @@ chunks[3].mask = 0x3FFF; chunks[3].ptr_index = 2; chunks[3].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE; - chunks[5].start = 0xFFFC; - chunks[5].end = 0x10000; - chunks[5].mask = 3; - chunks[5].flags = MMAP_READ; - chunks[5].write_8 = sms_sega_mapper_write; - if (chunks[4].end > 0xFFFC) { - //mapper regs overlap RAM from base map - chunks[4].end = 0xFFFC; + chunks[3].write_8 = sms_cart_ram_write; + chunks[num_chunks - 1].start = 0xFFFC; + chunks[num_chunks - 1].end = 0x10000; + chunks[num_chunks - 1].mask = 3; + chunks[num_chunks - 1].flags = MMAP_READ; + chunks[num_chunks - 1].write_8 = sms_sega_mapper_write; + for (uint32_t i = 4; i < num_chunks - 1; i++) + { + if (chunks[i].end > 0xFFFC) { + //mapper regs overlap RAM from base map + chunks[i].end = 0xFFFC; + } } } else { info->mapper_type = MAPPER_NONE; @@ -1269,7 +1363,38 @@ info.regions |= translate_region_char(*(dbreg++)); } } - //TODO: check for and handle map from db - sms_memmap_heuristics(&info, base_chunks, num_base_chunks); + tern_node *map = tern_find_node(entry, "map"); + if (map) { + info.save_type = SAVE_NONE; + info.map_chunks = tern_count(map); + if (info.map_chunks) { + info.map_chunks += num_base_chunks; + info.save_buffer = NULL; + info.save_size = 0; + info.map = malloc(sizeof(memmap_chunk) * info.map_chunks); + info.eeprom_map = NULL; + info.num_eeprom = 0; + memset(info.map, 0, sizeof(memmap_chunk) * info.map_chunks); + map_iter_state state = { + .info = &info, + .rom = rom, + .root = entry, + .rom_db = rom_db, + .rom_size = rom_size, + .index = 0, + .num_els = info.map_chunks - num_base_chunks, + .ptr_index = 0 + }; + tern_foreach(map, map_iter_fun_sms, &state); + memcpy(info.map + state.index, base_chunks, sizeof(memmap_chunk) * num_base_chunks); + info.rom = state.rom; + info.rom_size = state.rom_size; + } else { + sms_memmap_heuristics(&info, base_chunks, num_base_chunks); + } + } else { + sms_memmap_heuristics(&info, base_chunks, num_base_chunks); + } + handle_io_overrides(entry, &info); return info; } diff -r 8016dbb0fcde -r 2eda5f81f91e sms.c --- a/sms.c Tue May 09 09:03:37 2023 -0700 +++ b/sms.c Thu Jun 15 09:36:11 2023 -0700 @@ -165,7 +165,7 @@ return vcontext; } -static void *cart_ram_write(uint32_t location, void *vcontext, uint8_t value) +void *sms_cart_ram_write(uint32_t location, void *vcontext, uint8_t value) { z80_context *z80 = vcontext; sms_context *sms = z80->system; @@ -712,6 +712,13 @@ warning("Unrecognized VDP type %s\n", vdp_str); } } + for (uint32_t i = 0; i < sms->header.info.map_chunks; i++) + { + memmap_chunk *chunk = sms->header.info.map + i; + if ((chunk->flags == MMAP_READ) && !chunk->buffer && chunk->start > 0xC000) { + chunk->buffer = sms->ram + ((chunk->start - 0xC000) & 0x1FFF); + } + } if (is_gamegear) { init_z80_opts(zopts, sms->header.info.map, sms->header.info.map_chunks, io_gg, 6, 15, 0xFF); sms->start_button_region = 0xC0;