# HG changeset patch # User Michael Pavone # Date 1436322813 25200 # Node ID 2f48a3c187c6aa662538946685efd31682d60e16 # Parent ea525f600b1d324657e5eebd9dae4cc21e295647 Add support for reading cartridge memory map from ROM database, though without EEPROM support for now diff -r ea525f600b1d -r 2f48a3c187c6 rom.db --- a/rom.db Mon Jul 06 19:46:46 2015 -0700 +++ b/rom.db Tue Jul 07 19:33:33 2015 -0700 @@ -1,6 +1,6 @@ T-081326 { name NBA Jam - eeprom { + EEPROM { type i2c size 256 } @@ -10,7 +10,7 @@ last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 1 sda @@ -24,7 +24,7 @@ } T-81033 { name NBA Jam - eeprom { + EEPROM { type i2c size 256 } @@ -34,7 +34,7 @@ last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 1 sda @@ -48,7 +48,7 @@ } T-081276 { name NFL Quarterback Club - eeprom { + EEPROM { type i2c size 256 } @@ -58,7 +58,7 @@ last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 0 sda @@ -72,7 +72,7 @@ } T-81406 { name NBA Jam TE - eeprom { + EEPROM { type i2c size 512 } @@ -82,7 +82,7 @@ last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 0 sda @@ -96,7 +96,7 @@ } T-081586 { name NFL Quarterback Club '96 - eeprom { + EEPROM { type i2c size 2048 } @@ -106,7 +106,7 @@ last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 0 sda @@ -120,7 +120,7 @@ } T-81576 { name College Slam - eeprom { + EEPROM { type i2c size 8192 } @@ -130,7 +130,7 @@ last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 0 sda @@ -144,7 +144,7 @@ } T-81476 { name Frank Thomas Big Hurt Baseball - eeprom { + EEPROM { type i2c size 8192 } @@ -154,7 +154,7 @@ last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 0 sda diff -r ea525f600b1d -r 2f48a3c187c6 romdb.c --- a/romdb.c Mon Jul 06 19:46:46 2015 -0700 +++ b/romdb.c Tue Jul 07 19:33:33 2015 -0700 @@ -209,6 +209,18 @@ return *data << 24 | data[1] << 16 | data[2] << 8 | data[3]; } +uint32_t calc_mask(uint32_t src_size, uint32_t start, uint32_t end) +{ + uint32_t map_size = end-start+1; + if (src_size < map_size) { + return nearest_pow2(src_size)-1; + } else if (!start) { + return 0xFFFFFF; + } else { + return nearest_pow2(map_size)-1; + } +} + void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk const *base_map, int base_chunks) { if (rom[RAM_ID] == 'R' && rom[RAM_ID+1] == 'A') { @@ -298,6 +310,77 @@ return info; } +typedef struct { + rom_info *info; + uint8_t *rom; + tern_node *root; + uint32_t rom_size; + int index; +} map_iter_state; + +void map_iter_fun(char *key, tern_val val, void *data) +{ + map_iter_state *state = data; + tern_node *node = tern_get_node(val); + if (!node) { + fprintf(stderr, "ROM DB map entry %d with address %s is not a node\n", state->index, key); + exit(1); + } + uint32_t start = strtol(key, NULL, 16); + uint32_t end = strtol(tern_find_ptr_default(node, "last", "0"), NULL, 16); + if (!end || end < start) { + fprintf(stderr, "'last' value is missing or invalid for ROM DB map entry %d with address %s\n", state->index, key); + exit(1); + } + char * dtype = tern_find_ptr_default(node, "device", "ROM"); + uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 0); + memmap_chunk *map = state->info->map + state->index; + map->start = start; + map->end = end; + if (!strcmp(dtype, "ROM")) { + map->buffer = state->rom + offset; + map->flags = MMAP_READ; + map->mask = calc_mask(state->rom_size, start, end); + } else if (!strcmp(dtype, "EEPROM")) { + + + } else if (!strcmp(dtype, "SRAM")) { + if (!state->info->save_size) { + char * size = tern_find_path(state->root, "SRAM\0size\0").ptrval; + if (!size) { + fprintf(stderr, "ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key); + exit(1); + } + state->info->save_size = atoi(size); + if (!state->info->save_size) { + fprintf(stderr, "SRAM size %s is invalid\n", size); + exit(1); + } + state->info->save_buffer = malloc(state->info->save_size); + char *bus = tern_find_path(state->root, "SRAM\0bus\0").ptrval; + if (!strcmp(bus, "odd")) { + state->info->save_type = RAM_FLAG_ODD; + } else if(!strcmp(bus, "even")) { + state->info->save_type = RAM_FLAG_EVEN; + } else { + state->info->save_type = RAM_FLAG_BOTH; + } + } + map->buffer = state->info->save_buffer + offset; + map->flags = MMAP_READ | MMAP_WRITE; + if (state->info->save_type == RAM_FLAG_ODD) { + map->flags |= MMAP_ONLY_ODD; + } else if(state->info->save_type == RAM_FLAG_EVEN) { + map->flags |= MMAP_ONLY_EVEN; + } + map->mask = calc_mask(state->info->save_size, start, end); + } else { + fprintf(stderr, "Invalid device type for ROM DB map entry %d with address %s\n", state->index, key); + exit(1); + } + state->index++; +} + rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) { uint8_t product_id[GAME_ID_LEN+1]; @@ -312,13 +395,16 @@ product_id[i] = rom[GAME_ID_OFF + i]; } - tern_node * entry = tern_find_prefix(rom_db, product_id); + printf("Product ID: %s\n", product_id); + tern_node * entry = tern_find_ptr(rom_db, product_id); if (!entry) { + puts("Not found in ROM DB, examining header\n"); return configure_rom_heuristics(rom, rom_size, base_map, base_chunks); } rom_info info; info.name = tern_find_ptr(entry, "name"); if (info.name) { + printf("Found name: %s\n", info.name); info.name = strdup(info.name); } else { info.name = get_header_name(rom); @@ -336,11 +422,18 @@ info.regions = get_header_regions(rom); } - tern_node *map = tern_find_prefix(entry, "map"); + tern_node *map = tern_find_ptr(entry, "map"); if (map) { - uint32_t map_count = tern_count(map); - if (map_count) { - + info.map_chunks = tern_count(map); + if (info.map_chunks) { + info.map_chunks += base_chunks; + info.save_buffer = NULL; + info.save_size = 0; + info.map = malloc(sizeof(memmap_chunk) * info.map_chunks); + memset(info.map, 0, sizeof(memmap_chunk) * (info.map_chunks - base_chunks)); + map_iter_state state = {&info, rom, entry, rom_size, 0}; + tern_foreach(map, map_iter_fun, &state); + memcpy(info.map + state.index, base_map, sizeof(memmap_chunk) * base_chunks); } else { add_memmap_header(&info, rom, rom_size, base_map, base_chunks); } diff -r ea525f600b1d -r 2f48a3c187c6 tern.c --- a/tern.c Mon Jul 06 19:46:46 2015 -0700 +++ b/tern.c Tue Jul 07 19:33:33 2015 -0700 @@ -107,7 +107,11 @@ { tern_val ret; if (tern_find(head, key, &ret)) { - return ret.ptrval; + if (ret.intval & 1) { + return (void *)(ret.intval & ~1); + } else { + return ret.ptrval; + } } return def; } @@ -193,7 +197,7 @@ tern_foreach_int(head->straight.next, fun, data, keybuf, pos+1); } if (head->right) { - tern_foreach_int(head->left, fun, data, keybuf, pos); + tern_foreach_int(head->right, fun, data, keybuf, pos); } } diff -r ea525f600b1d -r 2f48a3c187c6 tern.h --- a/tern.h Mon Jul 06 19:46:46 2015 -0700 +++ b/tern.h Tue Jul 07 19:33:33 2015 -0700 @@ -39,6 +39,7 @@ tern_node * tern_insert_ptr(tern_node * head, char * key, void * value); tern_node * tern_insert_node(tern_node *head, char *key, tern_node *value); uint32_t tern_count(tern_node *head); +void tern_foreach(tern_node *head, iter_fun fun, void *data); char * tern_int_key(uint32_t key, char * buf); tern_node * tern_get_node(tern_val value); diff -r ea525f600b1d -r 2f48a3c187c6 util.c --- a/util.c Mon Jul 06 19:46:46 2015 -0700 +++ b/util.c Tue Jul 07 19:33:33 2015 -0700 @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,16 @@ return text+1; } +uint32_t nearest_pow2(uint32_t val) +{ + uint32_t ret = 1; + while (ret < val) + { + ret = ret << 1; + } + return ret; +} + static char * exe_str; void set_exe_str(char * str) diff -r ea525f600b1d -r 2f48a3c187c6 util.h --- a/util.h Mon Jul 06 19:46:46 2015 -0700 +++ b/util.h Tue Jul 07 19:33:33 2015 -0700 @@ -15,6 +15,8 @@ char * strip_ws(char * text); //Inserts a null after the first word, returns a pointer to the second word char * split_keyval(char * text); +//Gets the smallest power of two that is >= a certain value, won't work for values > 0x80000000 +uint32_t nearest_pow2(uint32_t val); //Should be called by main with the value of argv[0] for use by get_exe_dir void set_exe_str(char * str); //Returns the directory the executable is in