# HG changeset patch # User Michael Pavone # Date 1436131294 25200 # Node ID 1b2f8280ba8183cfb1b6e4e09dc4aefe1c71ab53 # Parent dc54387ee1cd4bd6508fa85c3e33183ff9f151d4 WIP changes to support reading cart memory map from ROM DB diff -r dc54387ee1cd -r 1b2f8280ba81 blastem.c --- a/blastem.c Thu Jul 02 20:43:01 2015 -0700 +++ b/blastem.c Sun Jul 05 14:21:34 2015 -0700 @@ -62,6 +62,7 @@ fseek(f, SMD_HEADER_SIZE, SEEK_SET); uint16_t * dst = cart; + int rom_size = filesize; while (filesize > 0) { fread(block, 1, SMD_BLOCK_SIZE, f); for (uint8_t *low = block, *high = (block+SMD_BLOCK_SIZE/2), *end = block+SMD_BLOCK_SIZE; high < end; high++, low++) { @@ -69,7 +70,7 @@ } filesize -= SMD_BLOCK_SIZE; } - return 1; + return filesize; } void byteswap_rom() @@ -112,7 +113,7 @@ } fread(cart, 2, filesize/2, f); fclose(f); - return 1; + return filesize; } uint16_t read_dma_value(uint32_t address) @@ -766,127 +767,6 @@ return context; } -uint16_t read_sram_w(uint32_t address, m68k_context * context) -{ - genesis_context * gen = context->system; - address &= gen->save_ram_mask; - switch(gen->save_flags) - { - case RAM_FLAG_BOTH: - return gen->save_ram[address] << 8 | gen->save_ram[address+1]; - case RAM_FLAG_EVEN: - return gen->save_ram[address >> 1] << 8 | 0xFF; - case RAM_FLAG_ODD: - return gen->save_ram[address >> 1] | 0xFF00; - } - return 0xFFFF;//We should never get here -} - -uint8_t read_sram_b(uint32_t address, m68k_context * context) -{ - genesis_context * gen = context->system; - address &= gen->save_ram_mask; - switch(gen->save_flags) - { - case RAM_FLAG_BOTH: - return gen->save_ram[address]; - case RAM_FLAG_EVEN: - if (address & 1) { - return 0xFF; - } else { - return gen->save_ram[address >> 1]; - } - case RAM_FLAG_ODD: - if (address & 1) { - return gen->save_ram[address >> 1]; - } else { - return 0xFF; - } - } - return 0xFF;//We should never get here -} - -m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value) -{ - genesis_context * gen = context->system; - if ((gen->bank_regs[0] & 0x3) == 1) { - address &= gen->save_ram_mask; - switch(gen->save_flags) - { - case RAM_FLAG_BOTH: - gen->save_ram[address] = value >> 8; - gen->save_ram[address+1] = value; - break; - case RAM_FLAG_EVEN: - gen->save_ram[address >> 1] = value >> 8; - break; - case RAM_FLAG_ODD: - gen->save_ram[address >> 1] = value; - break; - } - } - return context; -} - -m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8_t value) -{ - genesis_context * gen = context->system; - if ((gen->bank_regs[0] & 0x3) == 1) { - address &= gen->save_ram_mask; - switch(gen->save_flags) - { - case RAM_FLAG_BOTH: - gen->save_ram[address] = value; - break; - case RAM_FLAG_EVEN: - if (!(address & 1)) { - gen->save_ram[address >> 1] = value; - } - break; - case RAM_FLAG_ODD: - if (address & 1) { - gen->save_ram[address >> 1] = value; - } - break; - } - } - return context; -} - -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) { - context->mem_pointers[2] = NULL; - } else { - context->mem_pointers[2] = cart + 0x200000/2; - } - } - 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; - address &= 0xE; - address >>= 1; - gen->bank_regs[address] = value; - if (!address) { - if (value & 1) { - context->mem_pointers[2] = NULL; - } else { - context->mem_pointers[2] = cart + 0x200000/2; - } - } - } - return context; -} - void set_speed_percent(genesis_context * context, uint32_t percent) { uint32_t old_clock = context->master_clock; @@ -898,13 +778,7 @@ psg_adjust_master_clock(context->psg, context->master_clock); } -#define ROM_END 0x1A4 -#define RAM_ID 0x1B0 -#define RAM_FLAGS 0x1B2 -#define RAM_START 0x1B4 -#define RAM_END 0x1B8 #define MAX_MAP_CHUNKS (4+7+1) -#define RAM_FLAG_MASK 0x1800 const memmap_chunk static_map[] = { {0, 0x400000, 0xFFFFFF, 0, MMAP_READ, cart, @@ -947,6 +821,7 @@ //TODO: Handle carts larger than 4MB //TODO: Handle non-standard mappers uint32_t size; + /* if ((cart[RAM_ID/2] & 0xFF) == 'A' && (cart[RAM_ID/2] >> 8) == 'R') { //Cart has save RAM uint32_t rom_end = ((cart[ROM_END/2] << 16) | cart[ROM_END/2+1]) + 1; @@ -1020,6 +895,7 @@ memcpy(memmap, static_map, sizeof(static_map)); num_chunks = sizeof(static_map)/sizeof(memmap_chunk); } + */ if (gen->save_ram) { memset(gen->save_ram, 0, size); FILE * f = fopen(sram_filename, "rb"); @@ -1126,6 +1002,7 @@ char * romfname = NULL; FILE *address_log = NULL; char * statefile = NULL; + int rom_size; uint8_t * debuggerfun = NULL; uint8_t fullscreen = 0, use_gl = 1; for (int i = 1; i < argc; i++) { @@ -1207,7 +1084,7 @@ return 1; } } else if (!loaded) { - if(!load_rom(argv[i])) { + if(rom_size = load_rom(argv[i])) { fprintf(stderr, "Failed to open %s for reading\n", argv[i]); return 1; } @@ -1224,12 +1101,12 @@ return 1; } tern_node *rom_db = load_rom_db(); - rom_info info = configure_rom(rom_db, cart); + rom_info info = configure_rom(rom_db, cart, rom_size, static_map+1, sizeof(static_map)/sizeof(static_map[0]) - 1); byteswap_rom(); set_region(&info, force_version); update_title(info.name); int def_width = 0; - char *config_width = tern_find_ptr(config, "videowidth"); + char *config_width = tern_find_path(config, "video\0width\0").ptrval; if (config_width) { def_width = atoi(config_width); } @@ -1252,7 +1129,7 @@ init_vdp_context(&v_context, version_reg & 0x40); gen.frame_end = vdp_cycles_to_frame_end(&v_context); - char * config_cycles = tern_find_ptr(config, "clocksmax_cycles"); + char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0").ptrval; gen.max_cycles = config_cycles ? atoi(config_cycles) : 10000000; ym2612_context y_context; diff -r dc54387ee1cd -r 1b2f8280ba81 blastem.h --- a/blastem.h Thu Jul 02 20:43:01 2015 -0700 +++ b/blastem.h Sun Jul 05 14:21:34 2015 -0700 @@ -15,10 +15,6 @@ #include "io.h" #include "config.h" -#define RAM_FLAG_ODD 0x1800 -#define RAM_FLAG_EVEN 0x1000 -#define RAM_FLAG_BOTH 0x0000 - typedef struct { m68k_context *m68k; z80_context *z80; diff -r dc54387ee1cd -r 1b2f8280ba81 config.c --- a/config.c Thu Jul 02 20:43:01 2015 -0700 +++ b/config.c Sun Jul 05 14:21:34 2015 -0700 @@ -9,8 +9,6 @@ #include #include -#define MAX_NEST 30 //way more than I'll ever need - #ifdef _WIN32 char * strtok_r(char * input, char * sep, char ** state) { @@ -32,69 +30,59 @@ } #endif -tern_node * parse_config(char * config_data) +tern_node * parse_config_int(char **state, int started, int *line) { - char *state, *curline; - char *prefix = NULL; - int nest_level = 0; - char * prefix_parts[MAX_NEST]; - int line = 1; + char *config_data, *curline; tern_node * head = NULL; - while ((curline = strtok_r(config_data, "\n", &state))) + config_data = started ? NULL : *state; + while ((curline = strtok_r(config_data, "\n", state))) { + config_data = NULL; curline = strip_ws(curline); int len = strlen(curline); if (!len) { + *line++; continue; } if (curline[0] == '#') { + *line++; continue; } if (curline[0] == '}') { - if (!nest_level) { - fprintf(stderr, "unexpected } on line %d\n", line); - exit(1); + if (started) { + return head; } - if (prefix) { - free(prefix); - prefix = NULL; - } - nest_level--; - curline = strip_ws(curline+1); + fprintf(stderr, "unexpected } on line %d\n", *line); + exit(1); } + char * end = curline + len - 1; if (*end == '{') { *end = 0; curline = strip_ws(curline); - prefix_parts[nest_level++] = curline; - if (prefix) { - free(prefix); - prefix = NULL; - } + *line++; + head = tern_insert_node(head, curline, parse_config_int(state, 1, line)); } else { - if (nest_level && !prefix) { - prefix = alloc_concat_m(nest_level, prefix_parts); - } char * val = strip_ws(split_keyval(curline)); char * key = curline; - if (*key) { - if (prefix) { - key = alloc_concat(prefix, key); - } + if (*val) { head = tern_insert_ptr(head, key, strdup(val)); - if (prefix) { - free(key); - } + } else { + fprintf(stderr, "Key %s is missing a value on line %d\n", key, *line); } + *line++; } } - if (prefix) { - free(prefix); - } return head; } +tern_node * parse_config(char * config_data) +{ + int line = 1; + return parse_config_int(&config_data, 0, &line); +} + tern_node * parse_config_file(char * config_path) { tern_node * ret = NULL; diff -r dc54387ee1cd -r 1b2f8280ba81 io.c --- a/io.c Thu Jul 02 20:43:01 2015 -0700 +++ b/io.c Sun Jul 05 14:21:34 2015 -0700 @@ -536,7 +536,7 @@ void setup_io_devices(tern_node * config, io_port * ports) { - tern_node *io_nodes = tern_find_prefix(config, "iodevices"); + tern_node *io_nodes = tern_get_node(tern_find_path(config, "io\0devices\0")); char * io_1 = tern_find_ptr(io_nodes, "1"); char * io_2 = tern_find_ptr(io_nodes, "2"); char * io_ext = tern_find_ptr(io_nodes, "ext"); @@ -550,7 +550,7 @@ #ifndef _WIN32 if (ports[i].device_type == IO_SEGA_PARALLEL) { - char *pipe_name = tern_find_ptr(config, "ioparallel_pipe"); + char *pipe_name = tern_find_path(config, "io\0parallel_pipe\0").ptrval; if (!pipe_name) { fprintf(stderr, "IO port %s is configured to use the sega parallel board, but no paralell_pipe is set!\n", io_name(i)); @@ -576,7 +576,7 @@ } } } else if (ports[i].device_type == IO_GENERIC) { - char *sock_name = tern_find_ptr(config, "iosocket"); + char *sock_name = tern_find_path(config, "io\0socket\0").ptrval; if (!sock_name) { fprintf(stderr, "IO port %s is configured to use generic IO, but no socket is set!\n", io_name(i)); @@ -665,64 +665,73 @@ padbuttons = tern_insert_int(padbuttons, ".start", BUTTON_START); padbuttons = tern_insert_int(padbuttons, ".mode", BUTTON_MODE); - tern_node * keys = tern_find_prefix(config, "bindingskeys"); + tern_node * keys = tern_get_node(tern_find_path(config, "bindings\0keys\0")); process_keys(keys, special, padbuttons, NULL); - char prefix[] = "bindingspads00"; - for (int i = 0; i < 100 && i < render_num_joysticks(); i++) - { - if (i < 10) { - prefix[strlen("bindingspads")] = i + '0'; - prefix[strlen("bindingspads")+1] = 0; - } else { - prefix[strlen("bindingspads")] = i/10 + '0'; - prefix[strlen("bindingspads")+1] = i%10 + '0'; - } - tern_node * pad = tern_find_prefix(config, prefix); - if (pad) { - char dprefix[] = "dpads0"; - for (int dpad = 0; dpad < 10 && dpad < render_joystick_num_hats(i); dpad++) - { - dprefix[strlen("dpads")] = dpad + '0'; - tern_node * pad_dpad = tern_find_prefix(pad, dprefix); - char * dirs[] = {"up", "down", "left", "right"}; - int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; - for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) { - char * target = tern_find_ptr(pad_dpad, dirs[dir]); - if (target) { - int ui_func, padnum, button; - int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); - if (bindtype == 1) { - bind_dpad_gamepad(i, dpad, dirnums[dir], padnum, button); - } else if (bindtype == 2) { - bind_dpad_ui(i, dpad, dirnums[dir], ui_func, button); + char numstr[] = "00"; + tern_node * pads = tern_get_node(tern_find_path(config, "bindings\0pads\0")); + if (pads) { + for (int i = 0; i < 100 && i < render_num_joysticks(); i++) + { + + if (i < 10) { + numstr[0] = i + '0'; + numstr[1] = 0; + } else { + numstr[0] = i/10 + '0'; + numstr[1] = i%10 + '0'; + } + tern_node * pad = tern_find_ptr(pads, numstr); + if (pad) { + tern_node * dpad_node = tern_find_ptr(pad, "dpads"); + if (dpad_node) { + for (int dpad = 0; dpad < 10 && dpad < render_joystick_num_hats(i); dpad++) + { + numstr[0] = dpad + '0'; + numstr[1] = 0; + tern_node * pad_dpad = tern_find_ptr(dpad_node, numstr); + char * dirs[] = {"up", "down", "left", "right"}; + int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; + for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) { + char * target = tern_find_ptr(pad_dpad, dirs[dir]); + if (target) { + int ui_func, padnum, button; + int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); + if (bindtype == 1) { + bind_dpad_gamepad(i, dpad, dirnums[dir], padnum, button); + } else if (bindtype == 2) { + bind_dpad_ui(i, dpad, dirnums[dir], ui_func, button); + } + } } } } - } - char bprefix[] = "buttons00"; - for (int but = 0; but < 100 && but < render_joystick_num_buttons(i); but++) - { - if (but < 10) { - bprefix[strlen("buttons")] = but + '0'; - bprefix[strlen("buttons")+1] = 0; - } else { - bprefix[strlen("buttons")] = but/10 + '0'; - bprefix[strlen("buttons")+1] = but%10 + '0'; - } - char * target = tern_find_ptr(pad, bprefix); - if (target) { - int ui_func, padnum, button; - int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); - if (bindtype == 1) { - bind_button_gamepad(i, but, padnum, button); - } else if (bindtype == 2) { - bind_button_ui(i, but, ui_func, button); + tern_node *button_node = tern_find_ptr(pad, "buttons"); + if (button_node) { + for (int but = 0; but < 100 && but < render_joystick_num_buttons(i); but++) + { + if (but < 10) { + numstr[0] = but + '0'; + numstr[1] = 0; + } else { + numstr[0] = but/10 + '0'; + numstr[1] = but%10 + '0'; + } + char * target = tern_find_ptr(button_node, numstr); + if (target) { + int ui_func, padnum, button; + int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); + if (bindtype == 1) { + bind_button_gamepad(i, but, padnum, button); + } else if (bindtype == 2) { + bind_button_ui(i, but, ui_func, button); + } + } } } } } } - tern_node * speed_nodes = tern_find_prefix(config, "clocksspeeds"); + tern_node * speed_nodes = tern_get_node(tern_find_path(config, "clocks\0speeds\0")); speeds = malloc(sizeof(uint32_t)); speeds[0] = 100; process_speeds(speed_nodes, NULL); diff -r dc54387ee1cd -r 1b2f8280ba81 render_sdl.c --- a/render_sdl.c Thu Jul 02 20:43:01 2015 -0700 +++ b/render_sdl.c Sun Jul 05 14:21:34 2015 -0700 @@ -173,8 +173,10 @@ glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW); - vshader = load_shader(tern_find_ptr_default(config, "videovertex_shader", "default.v.glsl"), GL_VERTEX_SHADER); - fshader = load_shader(tern_find_ptr_default(config, "videofragment_shader", "default.f.glsl"), GL_FRAGMENT_SHADER); + tern_val def = {.ptrval = "default.v.glsl"}; + vshader = load_shader(tern_find_path_default(config, "video\0vertex_shader\0", def).ptrval, GL_VERTEX_SHADER); + def.ptrval = "default.f.glsl"; + fshader = load_shader(tern_find_path_default(config, "video\0fragment_shader\0", def).ptrval, GL_FRAGMENT_SHADER); program = glCreateProgram(); glAttachShader(program, vshader); glAttachShader(program, fshader); @@ -239,7 +241,8 @@ exit(1); } float aspect = (float)width / height; - if (fabs(aspect - 4.0/3.0) > 0.01 && strcmp(tern_find_ptr_default(config, "videoaspect", "normal"), "stretch")) { + tern_val def = {.ptrval = "normal"}; + if (fabs(aspect - 4.0/3.0) > 0.01 && strcmp(tern_find_path_default(config, "video\0aspect\0", def).ptrval, "stretch")) { for (int i = 0; i < 4; i++) { if (aspect > 4.0/3.0) { @@ -272,7 +275,7 @@ audio_ready = SDL_CreateCond(); SDL_AudioSpec desired, actual; - char * rate_str = tern_find_ptr(config, "audiorate"); + char * rate_str = tern_find_path(config, "audio\0rate\0").ptrval; int rate = rate_str ? atoi(rate_str) : 0; if (!rate) { rate = 48000; @@ -280,7 +283,7 @@ desired.freq = rate; desired.format = AUDIO_S16SYS; desired.channels = 2; - char * samples_str = tern_find_ptr(config, "audiobuffer"); + char * samples_str = tern_find_path(config, "audio\0buffer\0").ptrval; int samples = samples_str ? atoi(samples_str) : 0; if (!samples) { samples = 512; diff -r dc54387ee1cd -r 1b2f8280ba81 romdb.c --- a/romdb.c Thu Jul 02 20:43:01 2015 -0700 +++ b/romdb.c Sun Jul 05 14:21:34 2015 -0700 @@ -3,13 +3,140 @@ #include "config.h" #include "romdb.h" #include "util.h" +#include "blastem.h" #define TITLE_START 0x150 #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 +#define RAM_START 0x1B4 +#define RAM_END 0x1B8 #define REGION_START 0x1F0 +uint16_t read_sram_w(uint32_t address, m68k_context * context) +{ + genesis_context * gen = context->system; + address &= gen->save_ram_mask; + switch(gen->save_flags) + { + case RAM_FLAG_BOTH: + return gen->save_ram[address] << 8 | gen->save_ram[address+1]; + case RAM_FLAG_EVEN: + return gen->save_ram[address >> 1] << 8 | 0xFF; + case RAM_FLAG_ODD: + return gen->save_ram[address >> 1] | 0xFF00; + } + return 0xFFFF;//We should never get here +} + +uint8_t read_sram_b(uint32_t address, m68k_context * context) +{ + genesis_context * gen = context->system; + address &= gen->save_ram_mask; + switch(gen->save_flags) + { + case RAM_FLAG_BOTH: + return gen->save_ram[address]; + case RAM_FLAG_EVEN: + if (address & 1) { + return 0xFF; + } else { + return gen->save_ram[address >> 1]; + } + case RAM_FLAG_ODD: + if (address & 1) { + return gen->save_ram[address >> 1]; + } else { + return 0xFF; + } + } + return 0xFF;//We should never get here +} + +m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value) +{ + genesis_context * gen = context->system; + if ((gen->bank_regs[0] & 0x3) == 1) { + address &= gen->save_ram_mask; + switch(gen->save_flags) + { + case RAM_FLAG_BOTH: + gen->save_ram[address] = value >> 8; + gen->save_ram[address+1] = value; + break; + case RAM_FLAG_EVEN: + gen->save_ram[address >> 1] = value >> 8; + break; + case RAM_FLAG_ODD: + gen->save_ram[address >> 1] = value; + break; + } + } + return context; +} + +m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8_t value) +{ + genesis_context * gen = context->system; + if ((gen->bank_regs[0] & 0x3) == 1) { + address &= gen->save_ram_mask; + switch(gen->save_flags) + { + case RAM_FLAG_BOTH: + gen->save_ram[address] = value; + break; + case RAM_FLAG_EVEN: + if (!(address & 1)) { + gen->save_ram[address >> 1] = value; + } + break; + case RAM_FLAG_ODD: + if (address & 1) { + gen->save_ram[address >> 1] = value; + } + break; + } + } + return context; +} + +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) { + context->mem_pointers[2] = NULL; + } else { + context->mem_pointers[2] = cart + 0x200000/2; + } + } + 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; + address &= 0xE; + address >>= 1; + gen->bank_regs[address] = value; + if (!address) { + if (value & 1) { + context->mem_pointers[2] = NULL; + } else { + context->mem_pointers[2] = cart + 0x200000/2; + } + } + } + return context; +} + tern_node *load_rom_db() { char *exe_dir = get_exe_dir(); @@ -77,16 +204,96 @@ return regions; } +uint32_t get_u32be(uint8_t *data) +{ + return *data << 24 | data[1] << 16 | data[2] << 8 | data[3]; +} -rom_info configure_rom_heuristics(uint8_t *rom) +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') { + uint32_t rom_end = get_u32be(rom + ROM_END) + 1; + uint32_t ram_start = get_u32be(rom + RAM_START); + uint32_t ram_end = get_u32be(rom + RAM_END); + uint32_t ram_flags = info->save_type = rom[RAM_FLAGS] & RAM_FLAG_MASK; + ram_start &= 0xFFFFFE; + ram_end |= 1; + + info->map_chunks = base_chunks + (ram_start >= rom_end ? 2 : 3); + info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); + memset(info->map, 0, sizeof(memmap_chunk)*2); + memcpy(info->map+2, base_map, sizeof(memmap_chunk) * base_chunks); + + if (ram_start >= rom_end) { + info->map[0].end = rom_end; + //TODO: ROM mirroring + info->map[0].mask = 0xFFFFFF; + info->map[0].flags = MMAP_READ; + info->map[0].buffer = rom; + + info->map[1].start = ram_start; + info->map[1].mask = ram_end - ram_start; + info->map[1].end = ram_end + 1; + info->map[1].flags = MMAP_READ | MMAP_WRITE; + uint32_t size = info->map[1].mask + 1; + if (ram_flags == RAM_FLAG_ODD) { + info->map[1].flags |= MMAP_ONLY_ODD; + size /= 2; + } else if (ram_flags == RAM_FLAG_EVEN) { + info->map[1].flags |= MMAP_ONLY_EVEN; + size /= 2; + } + info->map[1].buffer = malloc(size); + } else { + //Assume the standard Sega mapper + info->map[0].end = 0x200000; + info->map[0].mask = 0xFFFFFF; + info->map[0].flags = MMAP_READ; + info->map[0].buffer = rom; + + info->map[1].start = 0x200000; + info->map[1].end = 0x400000; + info->map[1].mask = 0x1FFFFF; + info->map[1].flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL; + info->map[1].ptr_index = 2; + info->map[1].read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL + info->map[1].read_8 = (read_8_fun)read_sram_b; + info->map[1].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area + info->map[1].write_8 = (write_8_fun)write_sram_area_b; + info->map[1].buffer = cart + 0x200000; + + memmap_chunk *last = info->map + info->map_chunks - 1; + memset(last, 0, sizeof(memmap_chunk)); + last->start = 0xA13000; + last->end = 0xA13100; + last->mask = 0xFF; + last->write_16 = (write_16_fun)write_bank_reg_w; + last->write_8 = (write_8_fun)write_bank_reg_b; + } + } else { + info->map_chunks = base_chunks + 1; + info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); + memset(info->map, 0, sizeof(memmap_chunk)); + memcpy(info->map+1, base_map, sizeof(memmap_chunk) * base_chunks); + + info->map[0].end = 0x400000; + info->map[0].mask = 0xFFFFFF; + info->map[0].flags = MMAP_READ; + info->map[0].buffer = rom; + info->save_type = SAVE_NONE; + } +} + +rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) { rom_info info; info.name = get_header_name(rom); info.regions = get_header_regions(rom); + add_memmap_header(&info, rom, rom_size, base_map, base_chunks); return info; } -rom_info configure_rom(tern_node *rom_db, void *vrom) +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]; uint8_t *rom = vrom; @@ -102,7 +309,7 @@ } tern_node * entry = tern_find_prefix(rom_db, product_id); if (!entry) { - return configure_rom_heuristics(rom); + return configure_rom_heuristics(rom, rom_size, base_map, base_chunks); } rom_info info; info.name = tern_find_ptr(entry, "name"); @@ -123,5 +330,18 @@ if (!info.regions) { info.regions = get_header_regions(rom); } + + tern_node *map = tern_find_prefix(entry, "map"); + if (map) { + uint32_t map_count = tern_count(map); + if (map_count) { + + } else { + add_memmap_header(&info, rom, rom_size, base_map, base_chunks); + } + } else { + add_memmap_header(&info, rom, rom_size, base_map, base_chunks); + } + return info; } diff -r dc54387ee1cd -r 1b2f8280ba81 romdb.h --- a/romdb.h Thu Jul 02 20:43:01 2015 -0700 +++ b/romdb.h Sun Jul 05 14:21:34 2015 -0700 @@ -5,17 +5,29 @@ #define REGION_U 2 #define REGION_E 4 +#define RAM_FLAG_ODD 0x18 +#define RAM_FLAG_EVEN 0x10 +#define RAM_FLAG_BOTH 0x00 +#define RAM_FLAG_MASK RAM_FLAG_ODD +#define SAVE_I2C 0x01 +#define SAVE_NONE 0xFF + #include "tern.h" #include "backend.h" typedef struct { - char *name; - memmap_chunk *map; - uint8_t regions; + char *name; + memmap_chunk *map; + uint8_t *save_buffer; + uint32_t map_chunks; + uint32_t save_size; + uint8_t save_type; + uint8_t regions; } rom_info; tern_node *load_rom_db(); -rom_info configure_rom(tern_node *rom_db, void *vrom); +rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_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); uint8_t translate_region_char(uint8_t c); #endif //ROMDB_H_ diff -r dc54387ee1cd -r 1b2f8280ba81 tern.c --- a/tern.c Thu Jul 02 20:43:01 2015 -0700 +++ b/tern.c Sun Jul 05 14:21:34 2015 -0700 @@ -6,6 +6,8 @@ #include "tern.h" #include #include +#include +#include tern_node * tern_insert(tern_node * head, char * key, tern_val value) { @@ -115,6 +117,32 @@ return tern_find_ptr_default(head, key, NULL); } +tern_val tern_find_path_default(tern_node *head, char *key, tern_val def) +{ + tern_val ret; + while (*key) + { + if (!tern_find(head, key, &ret)) { + return def; + } + key = key + strlen(key) + 1; + if (*key) { + head = tern_get_node(ret); + if (!head) { + return def; + } + } + } + return ret; +} + +tern_val tern_find_path(tern_node *head, char *key) +{ + tern_val def; + def.ptrval = NULL; + return tern_find_path_default(head, key, def); +} + tern_node * tern_insert_ptr(tern_node * head, char * key, void * value) { tern_val val; @@ -122,6 +150,60 @@ return tern_insert(head, key, val); } +tern_node * tern_insert_node(tern_node *head, char *key, tern_node *value) +{ + tern_val val; + val.intval = ((intptr_t)value) | 1; + return tern_insert(head, key, val); +} + +uint32_t tern_count(tern_node *head) +{ + uint32_t count = 0; + if (head->left) { + count += tern_count(head->left); + } + if (head->right) { + count += tern_count(head->right); + } + if (!head->el) { + count++; + } else if (head->straight.next) { + count += tern_count(head->straight.next); + } + return count; +} + +#define MAX_ITER_KEY 127 +void tern_foreach_int(tern_node *head, iter_fun fun, void *data, char *keybuf, int pos) +{ + if (!head->el) { + keybuf[pos] = 0; + fun(keybuf, head->straight.value, data); + } + if (head->left) { + tern_foreach_int(head->left, fun, data, keybuf, pos); + } + if (head->el) { + if (pos == MAX_ITER_KEY) { + fputs("exceeded maximum key size", stderr); + exit(1); + } + keybuf[pos] = head->el; + tern_foreach_int(head->straight.next, fun, data, keybuf, pos+1); + } + if (head->right) { + tern_foreach_int(head->left, fun, data, keybuf, pos); + } +} + +void tern_foreach(tern_node *head, iter_fun fun, void *data) +{ + //lame, but good enough for my purposes + char key[MAX_ITER_KEY+1]; + tern_foreach_int(head, fun, data, key, 0); +} + char * tern_int_key(uint32_t key, char * buf) { char * cur = buf; @@ -133,3 +215,8 @@ *cur = 0; return buf; } + +tern_node * tern_get_node(tern_val value) +{ + return value.intval & 1 ? (tern_node *)(value.intval & ~1) : NULL; +} diff -r dc54387ee1cd -r 1b2f8280ba81 tern.h --- a/tern.h Thu Jul 02 20:43:01 2015 -0700 +++ b/tern.h Sun Jul 05 14:21:34 2015 -0700 @@ -25,6 +25,8 @@ char el; } tern_node; +typedef void (*iter_fun)(char *key, tern_val val, void *data); + tern_node * tern_insert(tern_node * head, char * key, tern_val value); int tern_find(tern_node * head, char * key, tern_val *ret); tern_node * tern_find_prefix(tern_node * head, char * key); @@ -32,7 +34,12 @@ tern_node * tern_insert_int(tern_node * head, char * key, intptr_t value); void * tern_find_ptr_default(tern_node * head, char * key, void * def); void * tern_find_ptr(tern_node * head, char * key); +tern_val tern_find_path_default(tern_node *head, char *key, tern_val def); +tern_val tern_find_path(tern_node *head, char *key); 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); char * tern_int_key(uint32_t key, char * buf); +tern_node * tern_get_node(tern_val value); #endif //TERN_H_